@@ -149,6 +149,21 @@ struct xfrm_pol_inexact_candidates {
149149 struct hlist_head * res [XFRM_POL_CAND_MAX ];
150150};
151151
152+ struct xfrm_flow_keys {
153+ struct flow_dissector_key_basic basic ;
154+ struct flow_dissector_key_control control ;
155+ union {
156+ struct flow_dissector_key_ipv4_addrs ipv4 ;
157+ struct flow_dissector_key_ipv6_addrs ipv6 ;
158+ } addrs ;
159+ struct flow_dissector_key_ip ip ;
160+ struct flow_dissector_key_icmp icmp ;
161+ struct flow_dissector_key_ports ports ;
162+ struct flow_dissector_key_keyid gre ;
163+ };
164+
165+ static struct flow_dissector xfrm_session_dissector __ro_after_init ;
166+
152167static DEFINE_SPINLOCK (xfrm_if_cb_lock );
153168static struct xfrm_if_cb const __rcu * xfrm_if_cb __read_mostly ;
154169
@@ -3367,191 +3382,74 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
33673382}
33683383
33693384static void
3370- decode_session4 (struct sk_buff * skb , struct flowi * fl , bool reverse )
3385+ decode_session4 (const struct xfrm_flow_keys * flkeys , struct flowi * fl , bool reverse )
33713386{
3372- const struct iphdr * iph = ip_hdr (skb );
3373- int ihl = iph -> ihl ;
3374- u8 * xprth = skb_network_header (skb ) + ihl * 4 ;
33753387 struct flowi4 * fl4 = & fl -> u .ip4 ;
33763388
33773389 memset (fl4 , 0 , sizeof (struct flowi4 ));
33783390
3379- fl4 -> flowi4_proto = iph -> protocol ;
3380- fl4 -> daddr = reverse ? iph -> saddr : iph -> daddr ;
3381- fl4 -> saddr = reverse ? iph -> daddr : iph -> saddr ;
3382- fl4 -> flowi4_tos = iph -> tos & ~INET_ECN_MASK ;
3383-
3384- if (!ip_is_fragment (iph )) {
3385- switch (iph -> protocol ) {
3386- case IPPROTO_UDP :
3387- case IPPROTO_UDPLITE :
3388- case IPPROTO_TCP :
3389- case IPPROTO_SCTP :
3390- case IPPROTO_DCCP :
3391- if (xprth + 4 < skb -> data ||
3392- pskb_may_pull (skb , xprth + 4 - skb -> data )) {
3393- __be16 * ports ;
3394-
3395- xprth = skb_network_header (skb ) + ihl * 4 ;
3396- ports = (__be16 * )xprth ;
3397-
3398- fl4 -> fl4_sport = ports [!!reverse ];
3399- fl4 -> fl4_dport = ports [!reverse ];
3400- }
3401- break ;
3402- case IPPROTO_ICMP :
3403- if (xprth + 2 < skb -> data ||
3404- pskb_may_pull (skb , xprth + 2 - skb -> data )) {
3405- u8 * icmp ;
3406-
3407- xprth = skb_network_header (skb ) + ihl * 4 ;
3408- icmp = xprth ;
3409-
3410- fl4 -> fl4_icmp_type = icmp [0 ];
3411- fl4 -> fl4_icmp_code = icmp [1 ];
3412- }
3413- break ;
3414- case IPPROTO_GRE :
3415- if (xprth + 12 < skb -> data ||
3416- pskb_may_pull (skb , xprth + 12 - skb -> data )) {
3417- __be16 * greflags ;
3418- __be32 * gre_hdr ;
3419-
3420- xprth = skb_network_header (skb ) + ihl * 4 ;
3421- greflags = (__be16 * )xprth ;
3422- gre_hdr = (__be32 * )xprth ;
3423-
3424- if (greflags [0 ] & GRE_KEY ) {
3425- if (greflags [0 ] & GRE_CSUM )
3426- gre_hdr ++ ;
3427- fl4 -> fl4_gre_key = gre_hdr [1 ];
3428- }
3429- }
3430- break ;
3431- default :
3432- break ;
3433- }
3391+ if (reverse ) {
3392+ fl4 -> saddr = flkeys -> addrs .ipv4 .dst ;
3393+ fl4 -> daddr = flkeys -> addrs .ipv4 .src ;
3394+ fl4 -> fl4_sport = flkeys -> ports .dst ;
3395+ fl4 -> fl4_dport = flkeys -> ports .src ;
3396+ } else {
3397+ fl4 -> saddr = flkeys -> addrs .ipv4 .src ;
3398+ fl4 -> daddr = flkeys -> addrs .ipv4 .dst ;
3399+ fl4 -> fl4_sport = flkeys -> ports .src ;
3400+ fl4 -> fl4_dport = flkeys -> ports .dst ;
34343401 }
3402+
3403+ fl4 -> flowi4_proto = flkeys -> basic .ip_proto ;
3404+ fl4 -> flowi4_tos = flkeys -> ip .tos ;
3405+ fl4 -> fl4_icmp_type = flkeys -> icmp .type ;
3406+ fl4 -> fl4_icmp_type = flkeys -> icmp .code ;
3407+ fl4 -> fl4_gre_key = flkeys -> gre .keyid ;
34353408}
34363409
34373410#if IS_ENABLED (CONFIG_IPV6 )
34383411static void
3439- decode_session6 (struct sk_buff * skb , struct flowi * fl , bool reverse )
3412+ decode_session6 (const struct xfrm_flow_keys * flkeys , struct flowi * fl , bool reverse )
34403413{
34413414 struct flowi6 * fl6 = & fl -> u .ip6 ;
3442- int onlyproto = 0 ;
3443- const struct ipv6hdr * hdr = ipv6_hdr (skb );
3444- u32 offset = sizeof (* hdr );
3445- struct ipv6_opt_hdr * exthdr ;
3446- const unsigned char * nh = skb_network_header (skb );
3447- u16 nhoff = IP6CB (skb )-> nhoff ;
3448- u8 nexthdr ;
3449-
3450- if (!nhoff )
3451- nhoff = offsetof(struct ipv6hdr , nexthdr );
3452-
3453- nexthdr = nh [nhoff ];
34543415
34553416 memset (fl6 , 0 , sizeof (struct flowi6 ));
34563417
3457- fl6 -> daddr = reverse ? hdr -> saddr : hdr -> daddr ;
3458- fl6 -> saddr = reverse ? hdr -> daddr : hdr -> saddr ;
3459-
3460- while (nh + offset + sizeof (* exthdr ) < skb -> data ||
3461- pskb_may_pull (skb , nh + offset + sizeof (* exthdr ) - skb -> data )) {
3462- nh = skb_network_header (skb );
3463- exthdr = (struct ipv6_opt_hdr * )(nh + offset );
3464-
3465- switch (nexthdr ) {
3466- case NEXTHDR_FRAGMENT :
3467- onlyproto = 1 ;
3468- fallthrough ;
3469- case NEXTHDR_ROUTING :
3470- case NEXTHDR_HOP :
3471- case NEXTHDR_DEST :
3472- offset += ipv6_optlen (exthdr );
3473- nexthdr = exthdr -> nexthdr ;
3474- break ;
3475- case IPPROTO_UDP :
3476- case IPPROTO_UDPLITE :
3477- case IPPROTO_TCP :
3478- case IPPROTO_SCTP :
3479- case IPPROTO_DCCP :
3480- if (!onlyproto && (nh + offset + 4 < skb -> data ||
3481- pskb_may_pull (skb , nh + offset + 4 - skb -> data ))) {
3482- __be16 * ports ;
3483-
3484- nh = skb_network_header (skb );
3485- ports = (__be16 * )(nh + offset );
3486- fl6 -> fl6_sport = ports [!!reverse ];
3487- fl6 -> fl6_dport = ports [!reverse ];
3488- }
3489- fl6 -> flowi6_proto = nexthdr ;
3490- return ;
3491- case IPPROTO_ICMPV6 :
3492- if (!onlyproto && (nh + offset + 2 < skb -> data ||
3493- pskb_may_pull (skb , nh + offset + 2 - skb -> data ))) {
3494- u8 * icmp ;
3495-
3496- nh = skb_network_header (skb );
3497- icmp = (u8 * )(nh + offset );
3498- fl6 -> fl6_icmp_type = icmp [0 ];
3499- fl6 -> fl6_icmp_code = icmp [1 ];
3500- }
3501- fl6 -> flowi6_proto = nexthdr ;
3502- return ;
3503- case IPPROTO_GRE :
3504- if (!onlyproto &&
3505- (nh + offset + 12 < skb -> data ||
3506- pskb_may_pull (skb , nh + offset + 12 - skb -> data ))) {
3507- struct gre_base_hdr * gre_hdr ;
3508- __be32 * gre_key ;
3509-
3510- nh = skb_network_header (skb );
3511- gre_hdr = (struct gre_base_hdr * )(nh + offset );
3512- gre_key = (__be32 * )(gre_hdr + 1 );
3513-
3514- if (gre_hdr -> flags & GRE_KEY ) {
3515- if (gre_hdr -> flags & GRE_CSUM )
3516- gre_key ++ ;
3517- fl6 -> fl6_gre_key = * gre_key ;
3518- }
3519- }
3520- fl6 -> flowi6_proto = nexthdr ;
3521- return ;
3522-
3523- #if IS_ENABLED (CONFIG_IPV6_MIP6 )
3524- case IPPROTO_MH :
3525- offset += ipv6_optlen (exthdr );
3526- if (!onlyproto && (nh + offset + 3 < skb -> data ||
3527- pskb_may_pull (skb , nh + offset + 3 - skb -> data ))) {
3528- struct ip6_mh * mh ;
3529-
3530- nh = skb_network_header (skb );
3531- mh = (struct ip6_mh * )(nh + offset );
3532- fl6 -> fl6_mh_type = mh -> ip6mh_type ;
3533- }
3534- fl6 -> flowi6_proto = nexthdr ;
3535- return ;
3536- #endif
3537- default :
3538- fl6 -> flowi6_proto = nexthdr ;
3539- return ;
3540- }
3418+ if (reverse ) {
3419+ fl6 -> saddr = flkeys -> addrs .ipv6 .dst ;
3420+ fl6 -> daddr = flkeys -> addrs .ipv6 .src ;
3421+ fl6 -> fl6_sport = flkeys -> ports .dst ;
3422+ fl6 -> fl6_dport = flkeys -> ports .src ;
3423+ } else {
3424+ fl6 -> saddr = flkeys -> addrs .ipv6 .src ;
3425+ fl6 -> daddr = flkeys -> addrs .ipv6 .dst ;
3426+ fl6 -> fl6_sport = flkeys -> ports .src ;
3427+ fl6 -> fl6_dport = flkeys -> ports .dst ;
35413428 }
3429+
3430+ fl6 -> flowi6_proto = flkeys -> basic .ip_proto ;
3431+ fl6 -> fl6_icmp_type = flkeys -> icmp .type ;
3432+ fl6 -> fl6_icmp_type = flkeys -> icmp .code ;
3433+ fl6 -> fl6_gre_key = flkeys -> gre .keyid ;
35423434}
35433435#endif
35443436
35453437int __xfrm_decode_session (struct net * net , struct sk_buff * skb , struct flowi * fl ,
35463438 unsigned int family , int reverse )
35473439{
3440+ struct xfrm_flow_keys flkeys ;
3441+
3442+ memset (& flkeys , 0 , sizeof (flkeys ));
3443+ __skb_flow_dissect (net , skb , & xfrm_session_dissector , & flkeys ,
3444+ NULL , 0 , 0 , 0 , FLOW_DISSECTOR_F_STOP_AT_ENCAP );
3445+
35483446 switch (family ) {
35493447 case AF_INET :
3550- decode_session4 (skb , fl , reverse );
3448+ decode_session4 (& flkeys , fl , reverse );
35513449 break ;
35523450#if IS_ENABLED (CONFIG_IPV6 )
35533451 case AF_INET6 :
3554- decode_session6 (skb , fl , reverse );
3452+ decode_session6 (& flkeys , fl , reverse );
35553453 break ;
35563454#endif
35573455 default :
@@ -4253,8 +4151,47 @@ static struct pernet_operations __net_initdata xfrm_net_ops = {
42534151 .exit = xfrm_net_exit ,
42544152};
42554153
4154+ static const struct flow_dissector_key xfrm_flow_dissector_keys [] = {
4155+ {
4156+ .key_id = FLOW_DISSECTOR_KEY_CONTROL ,
4157+ .offset = offsetof(struct xfrm_flow_keys , control ),
4158+ },
4159+ {
4160+ .key_id = FLOW_DISSECTOR_KEY_BASIC ,
4161+ .offset = offsetof(struct xfrm_flow_keys , basic ),
4162+ },
4163+ {
4164+ .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS ,
4165+ .offset = offsetof(struct xfrm_flow_keys , addrs .ipv4 ),
4166+ },
4167+ {
4168+ .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS ,
4169+ .offset = offsetof(struct xfrm_flow_keys , addrs .ipv6 ),
4170+ },
4171+ {
4172+ .key_id = FLOW_DISSECTOR_KEY_PORTS ,
4173+ .offset = offsetof(struct xfrm_flow_keys , ports ),
4174+ },
4175+ {
4176+ .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID ,
4177+ .offset = offsetof(struct xfrm_flow_keys , gre ),
4178+ },
4179+ {
4180+ .key_id = FLOW_DISSECTOR_KEY_IP ,
4181+ .offset = offsetof(struct xfrm_flow_keys , ip ),
4182+ },
4183+ {
4184+ .key_id = FLOW_DISSECTOR_KEY_ICMP ,
4185+ .offset = offsetof(struct xfrm_flow_keys , icmp ),
4186+ },
4187+ };
4188+
42564189void __init xfrm_init (void )
42574190{
4191+ skb_flow_dissector_init (& xfrm_session_dissector ,
4192+ xfrm_flow_dissector_keys ,
4193+ ARRAY_SIZE (xfrm_flow_dissector_keys ));
4194+
42584195 register_pernet_subsys (& xfrm_net_ops );
42594196 xfrm_dev_init ();
42604197 xfrm_input_init ();
0 commit comments