@@ -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