--- zzzz-none-000/linux-4.4.271/net/netfilter/nf_conntrack_proto_gre.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/net/netfilter/nf_conntrack_proto_gre.c 2023-04-19 10:22:30.000000000 +0000 @@ -1,4 +1,6 @@ /* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * * ip_conntrack_proto_gre.c - Version 3.0 * * Connection tracking protocol helper module for GRE. @@ -41,6 +43,8 @@ #include #include #include +#include +#include enum grep_conntrack { GRE_CT_UNREPLIED, @@ -90,16 +94,18 @@ } /* look up the source key for a given tuple */ -static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t) +static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t, bool *found) { struct netns_proto_gre *net_gre = gre_pernet(net); struct nf_ct_gre_keymap *km; __be16 key = 0; + *found = false; read_lock_bh(&net_gre->keymap_lock); list_for_each_entry(km, &net_gre->keymap_list, list) { if (gre_key_cmpfn(km, t)) { key = km->tuple.src.u.gre.key; + *found = true; break; } } @@ -197,6 +203,12 @@ __be16 srckey; const struct gre_hdr *grehdr; struct gre_hdr _grehdr; +#if IS_ENABLED(CONFIG_PPTP) + struct pptp_opt opt; + struct iphdr *v4_hdr; + int ret; +#endif + bool found; /* first only delinearize old RFC1701 GRE header */ grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); @@ -218,10 +230,53 @@ } tuple->dst.u.gre.key = pgrehdr->call_id; - srckey = gre_keymap_lookup(net, tuple); + srckey = gre_keymap_lookup(net, tuple, &found); tuple->src.u.gre.key = srckey; +#if !IS_ENABLED(CONFIG_PPTP) return true; +#else + + /* Return if src key is found */ + if (found) { + pr_debug("key map entry found (srckey=0x%x dstkey=0x%x)\n", ntohs(srckey), + ntohs(tuple->dst.u.gre.key)); + return true; + } + + /* Key map was not found. Return for IPv6 packet */ + v4_hdr = ip_hdr(skb); + if (v4_hdr->version != IPVERSION) { + pr_debug("PPTP IP version is %d\n", v4_hdr->version); + return true; + } + + /* Lookup the call-id based on dest callID. This is needed for packet originated from the system */ + ret = pptp_session_find(&opt, pgrehdr->call_id, v4_hdr->daddr); + if (!ret) { + tuple->src.u.gre.key = htons(opt.src_addr.call_id); + pr_debug("PPTP session found by dest callid sip=0x%x srckey=0x%x dip=0x%x destkey=0x%x\n", + ntohl(opt.src_addr.sin_addr.s_addr), opt.src_addr.call_id, + ntohl(opt.dst_addr.sin_addr.s_addr), opt.dst_addr.call_id); + return true; + } + + /* Lookup the call-id based on source callID. This is needed for packets received */ + ret = pptp_session_find_by_src_callid(&opt, pgrehdr->call_id, v4_hdr->saddr, v4_hdr->daddr); + if (!ret) { + tuple->src.u.gre.key = htons(opt.dst_addr.call_id); + pr_debug("PPTP session found by src callid sip=0x%x srckey=0x%x dip=0x%x destkey=0x%x\n", + ntohl(opt.dst_addr.sin_addr.s_addr), opt.dst_addr.call_id, + ntohl(opt.src_addr.sin_addr.s_addr), opt.src_addr.call_id); + return true; + } + + /* Do not create conntrack entry */ + pr_debug("Could not find PPTP session (sip=0x%x srckey=0x%x dip=0x%x dstkey=0x%x)\n", + ntohl(v4_hdr->saddr), ntohs(srckey), + ntohl(v4_hdr->daddr), ntohs(tuple->dst.u.gre.key)); + return false; +#endif } /* print gre part of tuple */ @@ -393,17 +448,62 @@ .init_net = gre_init_net, }; +static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre6 __read_mostly = { + .l3proto = AF_INET6, + .l4proto = IPPROTO_GRE, + .name = "gre", + .pkt_to_tuple = gre_pkt_to_tuple, + .invert_tuple = gre_invert_tuple, + .print_tuple = gre_print_tuple, + .print_conntrack = gre_print_conntrack, + .get_timeouts = gre_get_timeouts, + .packet = gre_packet, + .new = gre_new, + .destroy = gre_destroy, + .me = THIS_MODULE, +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, +#endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = gre_timeout_nlattr_to_obj, + .obj_to_nlattr = gre_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_GRE_MAX, + .obj_size = sizeof(unsigned int) * GRE_CT_MAX, + .nla_policy = gre_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + .net_id = &proto_gre_net_id, + .init_net = gre_init_net, +}; + static int proto_gre_net_init(struct net *net) { int ret = 0; ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_gre4); - if (ret < 0) + if (ret < 0) { pr_err("nf_conntrack_gre4: pernet registration failed.\n"); + goto out; + } + + ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_gre6); + if (ret < 0) { + pr_err("nf_conntrack_gre6: pernet registration failed.\n"); + goto cleanup_gre4; + } + return 0; +cleanup_gre4: + nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_gre4); +out: return ret; } static void proto_gre_net_exit(struct net *net) { + nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_gre6); nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_gre4); nf_ct_gre_keymap_flush(net); } @@ -427,7 +527,13 @@ if (ret < 0) goto out_gre4; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre6); + if (ret < 0) + goto out_gre6; + return 0; +out_gre6: + nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); out_gre4: unregister_pernet_subsys(&proto_gre_net_ops); out_pernet: @@ -436,6 +542,7 @@ static void __exit nf_ct_proto_gre_fini(void) { + nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre6); nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); unregister_pernet_subsys(&proto_gre_net_ops); }