15
15
#include <linux/percpu.h>
16
16
#include <linux/route.h>
17
17
#include <linux/skbuff.h>
18
+ #include <linux/notifier.h>
18
19
#include <net/checksum.h>
19
20
#include <net/icmp.h>
20
21
#include <net/ip.h>
32
33
# define WITH_IPV6 1
33
34
#endif
34
35
36
+ struct xt_tee_priv {
37
+ struct notifier_block notifier ;
38
+ struct xt_tee_tginfo * tginfo ;
39
+ int oif ;
40
+ };
41
+
35
42
static const union nf_inet_addr tee_zero_address ;
36
43
static DEFINE_PER_CPU (bool , tee_active ) ;
37
44
@@ -49,20 +56,6 @@ static struct net *pick_net(struct sk_buff *skb)
49
56
return & init_net ;
50
57
}
51
58
52
- static bool tee_tg_route_oif (struct flowi * f , struct net * net ,
53
- const struct xt_tee_tginfo * info )
54
- {
55
- const struct net_device * dev ;
56
-
57
- if (* info -> oif != '\0' )
58
- return true;
59
- dev = dev_get_by_name (net , info -> oif );
60
- if (dev == NULL )
61
- return false;
62
- f -> oif = dev -> ifindex ;
63
- return true;
64
- }
65
-
66
59
static bool
67
60
tee_tg_route4 (struct sk_buff * skb , const struct xt_tee_tginfo * info )
68
61
{
@@ -72,8 +65,11 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
72
65
struct flowi fl ;
73
66
74
67
memset (& fl , 0 , sizeof (fl ));
75
- if (!tee_tg_route_oif (& fl , net , info ))
76
- return false;
68
+ if (info -> priv ) {
69
+ if (info -> priv -> oif == -1 )
70
+ return false;
71
+ fl .oif = info -> priv -> oif ;
72
+ }
77
73
fl .nl_u .ip4_u .daddr = info -> gw .ip ;
78
74
fl .nl_u .ip4_u .tos = RT_TOS (iph -> tos );
79
75
fl .nl_u .ip4_u .scope = RT_SCOPE_UNIVERSE ;
@@ -149,8 +145,11 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
149
145
struct flowi fl ;
150
146
151
147
memset (& fl , 0 , sizeof (fl ));
152
- if (!tee_tg_route_oif (& fl , net , info ))
153
- return false;
148
+ if (info -> priv ) {
149
+ if (info -> priv -> oif == -1 )
150
+ return false;
151
+ fl .oif = info -> priv -> oif ;
152
+ }
154
153
fl .nl_u .ip6_u .daddr = info -> gw .in6 ;
155
154
fl .nl_u .ip6_u .flowlabel = ((iph -> flow_lbl [0 ] & 0xF ) << 16 ) |
156
155
(iph -> flow_lbl [1 ] << 8 ) | iph -> flow_lbl [2 ];
@@ -198,15 +197,71 @@ tee_tg6(struct sk_buff *skb, const struct xt_target_param *par)
198
197
}
199
198
#endif /* WITH_IPV6 */
200
199
200
+ static int tee_netdev_event (struct notifier_block * this , unsigned long event ,
201
+ void * ptr )
202
+ {
203
+ struct net_device * dev = ptr ;
204
+ struct xt_tee_priv * priv ;
205
+
206
+ priv = container_of (this , struct xt_tee_priv , notifier );
207
+ switch (event ) {
208
+ case NETDEV_REGISTER :
209
+ if (!strcmp (dev -> name , priv -> tginfo -> oif ))
210
+ priv -> oif = dev -> ifindex ;
211
+ break ;
212
+ case NETDEV_UNREGISTER :
213
+ if (dev -> ifindex == priv -> oif )
214
+ priv -> oif = -1 ;
215
+ break ;
216
+ case NETDEV_CHANGENAME :
217
+ if (!strcmp (dev -> name , priv -> tginfo -> oif ))
218
+ priv -> oif = dev -> ifindex ;
219
+ else if (dev -> ifindex == priv -> oif )
220
+ priv -> oif = -1 ;
221
+ break ;
222
+ }
223
+
224
+ return NOTIFY_DONE ;
225
+ }
226
+
201
227
static int tee_tg_check (const struct xt_tgchk_param * par )
202
228
{
203
- const struct xt_tee_tginfo * info = par -> targinfo ;
229
+ struct xt_tee_tginfo * info = par -> targinfo ;
230
+ struct xt_tee_priv * priv ;
204
231
205
- if (info -> oif [sizeof (info -> oif )- 1 ] != '\0' )
206
- return - EINVAL ;
207
232
/* 0.0.0.0 and :: not allowed */
208
- return (memcmp (& info -> gw , & tee_zero_address ,
209
- sizeof (tee_zero_address )) == 0 ) ? - EINVAL : 0 ;
233
+ if (memcmp (& info -> gw , & tee_zero_address ,
234
+ sizeof (tee_zero_address )) == 0 )
235
+ return - EINVAL ;
236
+
237
+ if (info -> oif [0 ]) {
238
+ if (info -> oif [sizeof (info -> oif )- 1 ] != '\0' )
239
+ return - EINVAL ;
240
+
241
+ priv = kzalloc (sizeof (* priv ), GFP_KERNEL );
242
+ if (priv == NULL )
243
+ return - ENOMEM ;
244
+
245
+ priv -> tginfo = info ;
246
+ priv -> oif = -1 ;
247
+ priv -> notifier .notifier_call = tee_netdev_event ;
248
+ info -> priv = priv ;
249
+
250
+ register_netdevice_notifier (& priv -> notifier );
251
+ } else
252
+ info -> priv = NULL ;
253
+
254
+ return 0 ;
255
+ }
256
+
257
+ static void tee_tg_destroy (const struct xt_tgdtor_param * par )
258
+ {
259
+ struct xt_tee_tginfo * info = par -> targinfo ;
260
+
261
+ if (info -> priv ) {
262
+ unregister_netdevice_notifier (& info -> priv -> notifier );
263
+ kfree (info -> priv );
264
+ }
210
265
}
211
266
212
267
static struct xt_target tee_tg_reg [] __read_mostly = {
@@ -217,6 +272,7 @@ static struct xt_target tee_tg_reg[] __read_mostly = {
217
272
.target = tee_tg4 ,
218
273
.targetsize = sizeof (struct xt_tee_tginfo ),
219
274
.checkentry = tee_tg_check ,
275
+ .destroy = tee_tg_destroy ,
220
276
.me = THIS_MODULE ,
221
277
},
222
278
#ifdef WITH_IPV6
@@ -227,6 +283,7 @@ static struct xt_target tee_tg_reg[] __read_mostly = {
227
283
.target = tee_tg6 ,
228
284
.targetsize = sizeof (struct xt_tee_tginfo ),
229
285
.checkentry = tee_tg_check ,
286
+ .destroy = tee_tg_destroy ,
230
287
.me = THIS_MODULE ,
231
288
},
232
289
#endif
0 commit comments