6
6
#include <linux/if_vlan.h>
7
7
#include <net/ip.h>
8
8
#include <net/ipv6.h>
9
+ #include <net/gre.h>
10
+ #include <net/pptp.h>
9
11
#include <linux/igmp.h>
10
12
#include <linux/icmp.h>
11
13
#include <linux/sctp.h>
@@ -338,32 +340,42 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
338
340
ip_proto_again :
339
341
switch (ip_proto ) {
340
342
case IPPROTO_GRE : {
341
- struct gre_hdr {
342
- __be16 flags ;
343
- __be16 proto ;
344
- } * hdr , _hdr ;
343
+ struct gre_base_hdr * hdr , _hdr ;
344
+ u16 gre_ver ;
345
+ int offset = 0 ;
345
346
346
347
hdr = __skb_header_pointer (skb , nhoff , sizeof (_hdr ), data , hlen , & _hdr );
347
348
if (!hdr )
348
349
goto out_bad ;
349
- /*
350
- * Only look inside GRE if version zero and no
351
- * routing
352
- */
353
- if (hdr -> flags & (GRE_VERSION | GRE_ROUTING ))
350
+
351
+ /* Only look inside GRE without routing */
352
+ if (hdr -> flags & GRE_ROUTING )
354
353
break ;
355
354
356
- proto = hdr -> proto ;
357
- nhoff += 4 ;
355
+ /* Only look inside GRE for version 0 and 1 */
356
+ gre_ver = ntohs (hdr -> flags & GRE_VERSION );
357
+ if (gre_ver > 1 )
358
+ break ;
359
+
360
+ proto = hdr -> protocol ;
361
+ if (gre_ver ) {
362
+ /* Version1 must be PPTP, and check the flags */
363
+ if (!(proto == GRE_PROTO_PPP && (hdr -> flags & GRE_KEY )))
364
+ break ;
365
+ }
366
+
367
+ offset += sizeof (struct gre_base_hdr );
368
+
358
369
if (hdr -> flags & GRE_CSUM )
359
- nhoff += 4 ;
370
+ offset += sizeof (((struct gre_full_hdr * )0 )-> csum ) +
371
+ sizeof (((struct gre_full_hdr * )0 )-> reserved1 );
372
+
360
373
if (hdr -> flags & GRE_KEY ) {
361
374
const __be32 * keyid ;
362
375
__be32 _keyid ;
363
376
364
- keyid = __skb_header_pointer (skb , nhoff , sizeof (_keyid ),
377
+ keyid = __skb_header_pointer (skb , nhoff + offset , sizeof (_keyid ),
365
378
data , hlen , & _keyid );
366
-
367
379
if (!keyid )
368
380
goto out_bad ;
369
381
@@ -372,32 +384,65 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
372
384
key_keyid = skb_flow_dissector_target (flow_dissector ,
373
385
FLOW_DISSECTOR_KEY_GRE_KEYID ,
374
386
target_container );
375
- key_keyid -> keyid = * keyid ;
387
+ if (gre_ver == 0 )
388
+ key_keyid -> keyid = * keyid ;
389
+ else
390
+ key_keyid -> keyid = * keyid & GRE_PPTP_KEY_MASK ;
376
391
}
377
- nhoff += 4 ;
392
+ offset += sizeof ((( struct gre_full_hdr * ) 0 ) -> key ) ;
378
393
}
394
+
379
395
if (hdr -> flags & GRE_SEQ )
380
- nhoff += 4 ;
381
- if (proto == htons (ETH_P_TEB )) {
382
- const struct ethhdr * eth ;
383
- struct ethhdr _eth ;
384
-
385
- eth = __skb_header_pointer (skb , nhoff ,
386
- sizeof (_eth ),
387
- data , hlen , & _eth );
388
- if (!eth )
396
+ offset += sizeof (((struct pptp_gre_header * )0 )-> seq );
397
+
398
+ if (gre_ver == 0 ) {
399
+ if (proto == htons (ETH_P_TEB )) {
400
+ const struct ethhdr * eth ;
401
+ struct ethhdr _eth ;
402
+
403
+ eth = __skb_header_pointer (skb , nhoff + offset ,
404
+ sizeof (_eth ),
405
+ data , hlen , & _eth );
406
+ if (!eth )
407
+ goto out_bad ;
408
+ proto = eth -> h_proto ;
409
+ offset += sizeof (* eth );
410
+
411
+ /* Cap headers that we access via pointers at the
412
+ * end of the Ethernet header as our maximum alignment
413
+ * at that point is only 2 bytes.
414
+ */
415
+ if (NET_IP_ALIGN )
416
+ hlen = (nhoff + offset );
417
+ }
418
+ } else { /* version 1, must be PPTP */
419
+ u8 _ppp_hdr [PPP_HDRLEN ];
420
+ u8 * ppp_hdr ;
421
+
422
+ if (hdr -> flags & GRE_ACK )
423
+ offset += sizeof (((struct pptp_gre_header * )0 )-> ack );
424
+
425
+ ppp_hdr = skb_header_pointer (skb , nhoff + offset ,
426
+ sizeof (_ppp_hdr ), _ppp_hdr );
427
+ if (!ppp_hdr )
389
428
goto out_bad ;
390
- proto = eth -> h_proto ;
391
- nhoff += sizeof (* eth );
392
-
393
- /* Cap headers that we access via pointers at the
394
- * end of the Ethernet header as our maximum alignment
395
- * at that point is only 2 bytes.
396
- */
397
- if (NET_IP_ALIGN )
398
- hlen = nhoff ;
429
+
430
+ switch (PPP_PROTOCOL (ppp_hdr )) {
431
+ case PPP_IP :
432
+ proto = htons (ETH_P_IP );
433
+ break ;
434
+ case PPP_IPV6 :
435
+ proto = htons (ETH_P_IPV6 );
436
+ break ;
437
+ default :
438
+ /* Could probably catch some more like MPLS */
439
+ break ;
440
+ }
441
+
442
+ offset += PPP_HDRLEN ;
399
443
}
400
444
445
+ nhoff += offset ;
401
446
key_control -> flags |= FLOW_DIS_ENCAPSULATION ;
402
447
if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP )
403
448
goto out_good ;
0 commit comments