Skip to content

Commit 2421b7d

Browse files
committed
bypass-lan: Compare interface for unchanged policies
In case a subnet is moved from one interface to another the policies can remain as is but the route has to change. This currently doesn't happen automatically and there is no option to update the policy or route so removing and reinstalling the policies is the only option. Fixes #2820.
1 parent ecba84a commit 2421b7d

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

src/libcharon/plugins/bypass_lan/bypass_lan_listener.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef struct {
6464
private_bypass_lan_listener_t *listener;
6565
host_t *net;
6666
uint8_t mask;
67+
char *iface;
6768
child_cfg_t *cfg;
6869
} bypass_policy_t;
6970

@@ -85,6 +86,7 @@ static void bypass_policy_destroy(bypass_policy_t *this)
8586
ts->destroy(ts);
8687
}
8788
this->net->destroy(this->net);
89+
free(this->iface);
8890
free(this);
8991
}
9092

@@ -126,6 +128,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
126128
enumerator_t *enumerator;
127129
hashtable_t *seen;
128130
bypass_policy_t *found, *lookup;
131+
traffic_selector_t *ts;
129132
host_t *net;
130133
uint8_t mask;
131134
char *iface;
@@ -146,6 +149,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
146149
INIT(lookup,
147150
.net = net->clone(net),
148151
.mask = mask,
152+
.iface = strdupnull(iface),
149153
);
150154
found = seen->put(seen, lookup, lookup);
151155
if (found)
@@ -160,7 +164,6 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
160164
.mode = MODE_PASS,
161165
};
162166
child_cfg_t *cfg;
163-
traffic_selector_t *ts;
164167
char name[128];
165168

166169
ts = traffic_selector_create_from_subnet(net->clone(net), mask,
@@ -176,6 +179,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
176179
INIT(found,
177180
.net = net->clone(net),
178181
.mask = mask,
182+
.iface = strdupnull(iface),
179183
.cfg = cfg,
180184
);
181185
this->policies->put(this->policies, found, found);
@@ -186,11 +190,29 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
186190
enumerator = this->policies->create_enumerator(this->policies);
187191
while (enumerator->enumerate(enumerator, NULL, &lookup))
188192
{
189-
if (!seen->get(seen, lookup))
193+
found = seen->get(seen, lookup);
194+
if (!found)
190195
{
191196
this->policies->remove_at(this->policies, enumerator);
192197
bypass_policy_destroy(lookup);
193198
}
199+
else if (!streq(lookup->iface, found->iface))
200+
{ /* if the subnet is on multiple interfaces, we only get the last
201+
* one (hopefully, they are enumerated in a consistent order) */
202+
ts = traffic_selector_create_from_subnet(
203+
lookup->net->clone(lookup->net),
204+
lookup->mask, 0, 0, 65535);
205+
DBG1(DBG_IKE, "interface change for bypass policy for %R (from %s "
206+
"to %s)", ts, lookup->iface, found->iface);
207+
ts->destroy(ts);
208+
free(lookup->iface);
209+
lookup->iface = strdupnull(found->iface);
210+
/* there is currently no API to update shunts, so we remove and
211+
* reinstall it to update the route */
212+
charon->shunts->uninstall(charon->shunts, "bypass-lan",
213+
lookup->cfg->get_name(lookup->cfg));
214+
charon->shunts->install(charon->shunts, "bypass-lan", lookup->cfg);
215+
}
194216
}
195217
enumerator->destroy(enumerator);
196218
this->mutex->unlock(this->mutex);

0 commit comments

Comments
 (0)