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