libipsec: Match IPsec policies against ports of processed packets
[strongswan.git] / src / libipsec / ipsec_policy.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_policy.h"
19
20 #include <utils/debug.h>
21
22 typedef struct private_ipsec_policy_t private_ipsec_policy_t;
23
24 /**
25 * Private additions to ipsec_policy_t.
26 */
27 struct private_ipsec_policy_t {
28
29 /**
30 * Public members
31 */
32 ipsec_policy_t public;
33
34 /**
35 * SA source address
36 */
37 host_t *src;
38
39 /**
40 * SA destination address
41 */
42 host_t *dst;
43
44 /**
45 * Source traffic selector
46 */
47 traffic_selector_t *src_ts;
48
49 /**
50 * Destination traffic selector
51 */
52 traffic_selector_t *dst_ts;
53
54 /**
55 * If any of the two TS has a protocol selector we cache it here
56 */
57 uint8_t protocol;
58
59 /**
60 * Traffic direction
61 */
62 policy_dir_t direction;
63
64 /**
65 * Policy type
66 */
67 policy_type_t type;
68
69 /**
70 * SA configuration
71 */
72 ipsec_sa_cfg_t sa;
73
74 /**
75 * Mark
76 */
77 mark_t mark;
78
79 /**
80 * Policy priority
81 */
82 policy_priority_t priority;
83
84 /**
85 * Reference counter
86 */
87 refcount_t refcount;
88
89 };
90
91 METHOD(ipsec_policy_t, match, bool,
92 private_ipsec_policy_t *this, traffic_selector_t *src_ts,
93 traffic_selector_t *dst_ts, policy_dir_t direction, uint32_t reqid,
94 mark_t mark, policy_priority_t priority)
95 {
96 return (this->direction == direction &&
97 this->priority == priority &&
98 this->sa.reqid == reqid &&
99 memeq(&this->mark, &mark, sizeof(mark_t)) &&
100 this->src_ts->equals(this->src_ts, src_ts) &&
101 this->dst_ts->equals(this->dst_ts, dst_ts));
102 }
103
104 /**
105 * Match the port of the given host against the given traffic selector.
106 */
107 static inline bool match_port(traffic_selector_t *ts, host_t *host)
108 {
109 uint16_t from, to, port;
110
111 from = ts->get_from_port(ts);
112 to = ts->get_to_port(ts);
113 if ((from == 0 && to == 0xffff) ||
114 (from == 0xffff && to == 0))
115 {
116 return TRUE;
117 }
118 port = host->get_port(host);
119 return from <= port && port <= to;
120 }
121
122 METHOD(ipsec_policy_t, match_packet, bool,
123 private_ipsec_policy_t *this, ip_packet_t *packet)
124 {
125 uint8_t proto = packet->get_next_header(packet);
126 host_t *src = packet->get_source(packet),
127 *dst = packet->get_destination(packet);
128
129 return (!this->protocol || this->protocol == proto) &&
130 this->src_ts->includes(this->src_ts, src) &&
131 match_port(this->src_ts, src) &&
132 this->dst_ts->includes(this->dst_ts, dst) &&
133 match_port(this->dst_ts, dst);
134 }
135
136 METHOD(ipsec_policy_t, get_source_ts, traffic_selector_t*,
137 private_ipsec_policy_t *this)
138 {
139 return this->src_ts;
140 }
141
142 METHOD(ipsec_policy_t, get_destination_ts, traffic_selector_t*,
143 private_ipsec_policy_t *this)
144 {
145 return this->dst_ts;
146 }
147
148 METHOD(ipsec_policy_t, get_reqid, uint32_t,
149 private_ipsec_policy_t *this)
150 {
151 return this->sa.reqid;
152 }
153
154 METHOD(ipsec_policy_t, get_direction, policy_dir_t,
155 private_ipsec_policy_t *this)
156 {
157 return this->direction;
158 }
159
160 METHOD(ipsec_policy_t, get_priority, policy_priority_t,
161 private_ipsec_policy_t *this)
162 {
163 return this->priority;
164 }
165
166 METHOD(ipsec_policy_t, get_type, policy_type_t,
167 private_ipsec_policy_t *this)
168 {
169 return this->type;
170 }
171
172 METHOD(ipsec_policy_t, get_ref, ipsec_policy_t*,
173 private_ipsec_policy_t *this)
174 {
175 ref_get(&this->refcount);
176 return &this->public;
177 }
178
179 METHOD(ipsec_policy_t, destroy, void,
180 private_ipsec_policy_t *this)
181 {
182 if (ref_put(&this->refcount))
183 {
184 this->src->destroy(this->src);
185 this->dst->destroy(this->dst);
186 this->src_ts->destroy(this->src_ts);
187 this->dst_ts->destroy(this->dst_ts);
188 free(this);
189 }
190 }
191
192 /**
193 * Described in header.
194 */
195 ipsec_policy_t *ipsec_policy_create(host_t *src, host_t *dst,
196 traffic_selector_t *src_ts,
197 traffic_selector_t *dst_ts,
198 policy_dir_t direction, policy_type_t type,
199 ipsec_sa_cfg_t *sa, mark_t mark,
200 policy_priority_t priority)
201 {
202 private_ipsec_policy_t *this;
203
204 INIT(this,
205 .public = {
206 .match = _match,
207 .match_packet = _match_packet,
208 .get_source_ts = _get_source_ts,
209 .get_destination_ts = _get_destination_ts,
210 .get_direction = _get_direction,
211 .get_priority = _get_priority,
212 .get_reqid = _get_reqid,
213 .get_type = _get_type,
214 .get_ref = _get_ref,
215 .destroy = _destroy,
216 },
217 .src = src->clone(src),
218 .dst = dst->clone(dst),
219 .src_ts = src_ts->clone(src_ts),
220 .dst_ts = dst_ts->clone(dst_ts),
221 .protocol = max(src_ts->get_protocol(src_ts),
222 dst_ts->get_protocol(dst_ts)),
223 .direction = direction,
224 .type = type,
225 .sa = *sa,
226 .mark = mark,
227 .priority = priority,
228 .refcount = 1,
229 );
230
231 return &this->public;
232 }