farp: Only cache IPv4 traffic selectors
[strongswan.git] / src / libcharon / plugins / farp / farp_listener.c
1 /*
2 * Copyright (C) 2019 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "farp_listener.h"
20
21 #include <collections/linked_list.h>
22 #include <threading/rwlock.h>
23
24 typedef struct private_farp_listener_t private_farp_listener_t;
25
26 /**
27 * Private data of an farp_listener_t object.
28 */
29 struct private_farp_listener_t {
30
31 /**
32 * Public farp_listener_t interface.
33 */
34 farp_listener_t public;
35
36 /**
37 * List with entry_t
38 */
39 linked_list_t *entries;
40
41 /**
42 * RWlock for IP list
43 */
44 rwlock_t *lock;
45 };
46
47 /**
48 * Traffic selector cache entry
49 */
50 typedef struct {
51 /** list of local selectors */
52 linked_list_t *local;
53 /** list of remote selectors */
54 linked_list_t *remote;
55 /** reqid of CHILD_SA */
56 uint32_t reqid;
57 } entry_t;
58
59 /**
60 * Destroy a cache entry
61 */
62 static void destroy_entry(entry_t *this)
63 {
64 this->local->destroy_offset(this->local,
65 offsetof(traffic_selector_t, destroy));
66 this->remote->destroy_offset(this->remote,
67 offsetof(traffic_selector_t, destroy));
68 free(this);
69 }
70
71 METHOD(listener_t, child_updown, bool,
72 private_farp_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
73 bool up)
74 {
75 enumerator_t *enumerator;
76 traffic_selector_t *ts;
77 entry_t *entry;
78
79 if (up)
80 {
81 INIT(entry,
82 .local = linked_list_create(),
83 .remote = linked_list_create(),
84 .reqid = child_sa->get_reqid(child_sa),
85 );
86
87 enumerator = child_sa->create_ts_enumerator(child_sa, FALSE);
88 while (enumerator->enumerate(enumerator, &ts))
89 {
90 if (ts->get_type(ts) != TS_IPV4_ADDR_RANGE)
91 {
92 continue;
93 }
94 entry->remote->insert_last(entry->remote, ts->clone(ts));
95 }
96 enumerator->destroy(enumerator);
97
98 enumerator = child_sa->create_ts_enumerator(child_sa, TRUE);
99 while (enumerator->enumerate(enumerator, &ts))
100 {
101 if (ts->get_type(ts) != TS_IPV4_ADDR_RANGE)
102 {
103 continue;
104 }
105 entry->local->insert_last(entry->local, ts->clone(ts));
106 }
107 enumerator->destroy(enumerator);
108
109 if (!entry->remote->get_count(entry->remote) ||
110 !entry->local->get_count(entry->local))
111 {
112 destroy_entry(entry);
113 return TRUE;
114 }
115
116 this->lock->write_lock(this->lock);
117 this->entries->insert_last(this->entries, entry);
118 this->lock->unlock(this->lock);
119 }
120 else
121 {
122 this->lock->write_lock(this->lock);
123 enumerator = this->entries->create_enumerator(this->entries);
124 while (enumerator->enumerate(enumerator, &entry))
125 {
126 if (entry->reqid == child_sa->get_reqid(child_sa))
127 {
128 this->entries->remove_at(this->entries, enumerator);
129 destroy_entry(entry);
130 break;
131 }
132 }
133 enumerator->destroy(enumerator);
134 this->lock->unlock(this->lock);
135 }
136 return TRUE;
137 }
138
139 METHOD(farp_listener_t, has_tunnel, bool,
140 private_farp_listener_t *this, host_t *local, host_t *remote)
141 {
142 enumerator_t *entries, *locals, *remotes;
143 traffic_selector_t *ts;
144 bool found = FALSE;
145 entry_t *entry;
146
147 this->lock->read_lock(this->lock);
148 entries = this->entries->create_enumerator(this->entries);
149 while (!found && entries->enumerate(entries, &entry))
150 {
151 remotes = entry->remote->create_enumerator(entry->remote);
152 while (!found && remotes->enumerate(remotes, &ts))
153 {
154 if (ts->includes(ts, remote))
155 {
156 locals = entry->local->create_enumerator(entry->local);
157 while (!found && locals->enumerate(locals, &ts))
158 {
159 found = ts->includes(ts, local);
160 }
161 locals->destroy(locals);
162 }
163 }
164 remotes->destroy(remotes);
165 }
166 entries->destroy(entries);
167 this->lock->unlock(this->lock);
168
169 return found;
170 }
171
172 METHOD(farp_listener_t, destroy, void,
173 private_farp_listener_t *this)
174 {
175 this->entries->destroy(this->entries);
176 this->lock->destroy(this->lock);
177 free(this);
178 }
179
180 /**
181 * See header
182 */
183 farp_listener_t *farp_listener_create()
184 {
185 private_farp_listener_t *this;
186
187 INIT(this,
188 .public = {
189 .listener = {
190 .child_updown = _child_updown,
191 },
192 .has_tunnel = _has_tunnel,
193 .destroy = _destroy,
194 },
195 .entries = linked_list_create(),
196 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
197 );
198
199 return &this->public;
200 }