Fix parsing of IPv6 headers in ip_packet_t
[strongswan.git] / src / libipsec / ipsec_sa.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "ipsec_sa.h"
19
20 #include <library.h>
21 #include <debug.h>
22
23 typedef struct private_ipsec_sa_t private_ipsec_sa_t;
24
25 /**
26 * Private additions to ipsec_sa_t.
27 */
28 struct private_ipsec_sa_t {
29
30 /**
31 * Public members
32 */
33 ipsec_sa_t public;
34
35 /**
36 * SPI of this SA
37 */
38 u_int32_t spi;
39
40 /**
41 * Source address
42 */
43 host_t *src;
44
45 /**
46 * Destination address
47 */
48 host_t *dst;
49
50 /**
51 * Protocol
52 */
53 u_int8_t protocol;
54
55 /**
56 * Reqid of this SA
57 */
58 u_int32_t reqid;
59
60 /**
61 * Lifetime configuration
62 */
63 lifetime_cfg_t lifetime;
64
65 /**
66 * IPsec mode
67 */
68 ipsec_mode_t mode;
69
70 /**
71 * TRUE if extended sequence numbers are used
72 */
73 bool esn;
74
75 /**
76 * TRUE if this is an inbound SA
77 */
78 bool inbound;
79
80 /**
81 * ESP context
82 */
83 esp_context_t *esp_context;
84 };
85
86 METHOD(ipsec_sa_t, get_source, host_t*,
87 private_ipsec_sa_t *this)
88 {
89 return this->src;
90 }
91
92 METHOD(ipsec_sa_t, get_destination, host_t*,
93 private_ipsec_sa_t *this)
94 {
95 return this->dst;
96 }
97
98 METHOD(ipsec_sa_t, get_spi, u_int32_t,
99 private_ipsec_sa_t *this)
100 {
101 return this->spi;
102 }
103
104 METHOD(ipsec_sa_t, get_reqid, u_int32_t,
105 private_ipsec_sa_t *this)
106 {
107 return this->reqid;
108 }
109
110 METHOD(ipsec_sa_t, get_protocol, u_int8_t,
111 private_ipsec_sa_t *this)
112 {
113 return this->protocol;
114 }
115
116 METHOD(ipsec_sa_t, get_lifetime, lifetime_cfg_t*,
117 private_ipsec_sa_t *this)
118 {
119 return &this->lifetime;
120 }
121
122 METHOD(ipsec_sa_t, is_inbound, bool,
123 private_ipsec_sa_t *this)
124 {
125 return this->inbound;
126 }
127
128 METHOD(ipsec_sa_t, get_esp_context, esp_context_t*,
129 private_ipsec_sa_t *this)
130 {
131 return this->esp_context;
132 }
133
134 METHOD(ipsec_sa_t, match_by_spi_dst, bool,
135 private_ipsec_sa_t *this, u_int32_t spi, host_t *dst)
136 {
137 return this->spi == spi && this->dst->ip_equals(this->dst, dst);
138 }
139
140 METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
141 private_ipsec_sa_t *this, u_int32_t spi, host_t *src, host_t *dst)
142 {
143 return this->spi == spi && this->src->ip_equals(this->src, src) &&
144 this->dst->ip_equals(this->dst, dst);
145 }
146
147 METHOD(ipsec_sa_t, match_by_reqid, bool,
148 private_ipsec_sa_t *this, u_int32_t reqid, bool inbound)
149 {
150 return this->reqid == reqid && this->inbound == inbound;
151 }
152
153 METHOD(ipsec_sa_t, destroy, void,
154 private_ipsec_sa_t *this)
155 {
156 this->src->destroy(this->src);
157 this->dst->destroy(this->dst);
158 DESTROY_IF(this->esp_context);
159 free(this);
160 }
161
162 /**
163 * Described in header.
164 */
165 ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
166 u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
167 lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
168 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
169 u_int16_t ipcomp, u_int16_t cpi, bool encap, bool esn, bool inbound,
170 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
171 {
172 private_ipsec_sa_t *this;
173
174 if (protocol != IPPROTO_ESP)
175 {
176 DBG1(DBG_ESP, " IPsec SA: protocol not supported");
177 return NULL;
178 }
179 if (!encap)
180 {
181 DBG1(DBG_ESP, " IPsec SA: only UDP encapsulation is supported");
182 return NULL;
183 }
184 if (esn)
185 {
186 DBG1(DBG_ESP, " IPsec SA: ESN not supported");
187 return NULL;
188 }
189 if (ipcomp != IPCOMP_NONE)
190 {
191 DBG1(DBG_ESP, " IPsec SA: compression not supported");
192 return NULL;
193 }
194 if (mode != MODE_TUNNEL)
195 {
196 DBG1(DBG_ESP, " IPsec SA: unsupported mode");
197 return NULL;
198 }
199
200 INIT(this,
201 .public = {
202 .destroy = _destroy,
203 .get_source = _get_source,
204 .get_destination = _get_destination,
205 .get_spi = _get_spi,
206 .get_reqid = _get_reqid,
207 .get_protocol = _get_protocol,
208 .get_lifetime = _get_lifetime,
209 .is_inbound = _is_inbound,
210 .match_by_spi_dst = _match_by_spi_dst,
211 .match_by_spi_src_dst = _match_by_spi_src_dst,
212 .match_by_reqid = _match_by_reqid,
213 .get_esp_context = _get_esp_context,
214 },
215 .spi = spi,
216 .src = src->clone(src),
217 .dst = dst->clone(dst),
218 .lifetime = *lifetime,
219 .protocol = protocol,
220 .reqid = reqid,
221 .mode = mode,
222 .esn = esn,
223 .inbound = inbound,
224 );
225
226 this->esp_context = esp_context_create(enc_alg, enc_key, int_alg, int_key,
227 inbound);
228 if (!this->esp_context)
229 {
230 destroy(this);
231 return NULL;
232 }
233 return &this->public;
234 }