From 7ddb3fd59b5b5c309f7b1c8d904f504f50137031 Mon Sep 17 00:00:00 2001 From: Lionel Gauthier Date: Tue, 16 Dec 2014 17:16:50 +0000 Subject: [PATCH] git-svn-id: http://svn.eurecom.fr/openair4G/trunk@6273 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- openair-cn/GTPV1-U/GTPURH/libxt_GTPURH.c | 123 ++++- openair-cn/GTPV1-U/GTPURH/xt_GTPURH.c | 586 +++++++---------------- 2 files changed, 266 insertions(+), 443 deletions(-) diff --git a/openair-cn/GTPV1-U/GTPURH/libxt_GTPURH.c b/openair-cn/GTPV1-U/GTPURH/libxt_GTPURH.c index 01dfc33427..cb0b13ab27 100755 --- a/openair-cn/GTPV1-U/GTPURH/libxt_GTPURH.c +++ b/openair-cn/GTPV1-U/GTPURH/libxt_GTPURH.c @@ -50,14 +50,22 @@ #endif enum { - PARAM_ACTION = 1 << 0, + PARAM_LADDR = 1 << 0, + PARAM_LTUN = 1 << 1, + PARAM_RADDR = 1 << 2, + PARAM_RTUN = 1 << 3, + PARAM_ACTION = 1 << 4, }; static void GTPURH_help(void) { printf( -"GTPURH target options\n" -" --action value Set action \n"); + "GTPUAH target options\n" + " --action value Set action \n" + " --own-ip value Set own IP address\n" + " --own-tun value Set own tunnel id \n" + " --peer-ip value Set peer IP address\n" + " --peer-tun value Set peer tunnel id \n"); } #if (IPTVERSION <= 135) @@ -97,17 +105,63 @@ void gtpurh_param_act(unsigned int status, const char *p1, ...) #endif +static void parse_gtpurh_addr(const char *s, struct xt_gtpurh_target_info *info, int flag) +{ + in_addr_t addr; + + if ((addr = inet_addr(s)) == -1) { + switch (flag) { + case PARAM_LADDR: + gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--own-ip", s); + break; + case PARAM_RADDR: + gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--peer-ip", s); + break; + } + } + + switch (flag) { + case PARAM_LADDR: + info->laddr = addr; + break; + case PARAM_RADDR: + info->raddr = addr; + break; + } +} + +static void parse_gtpurh_tunid(char *s, struct xt_gtpurh_target_info *info, int flag) +{ + unsigned int value; + + if (!gtpurh_strtoui(s, &value, 0, UINT32_MAX)) { + switch (flag) { + case PARAM_LTUN: + gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--own-tun", s); + break; + case PARAM_RTUN: + gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--peer-tun", s); + break; + } + } + + switch (flag) { + case PARAM_LTUN: + info->ltun = value; + break; + case PARAM_RTUN: + info->rtun = value; + break; + } +} static void parse_gtpurh_action(char *s, struct xt_gtpurh_target_info *info, unsigned int *flags) { - if (!strcmp(s, "remove")) - { + if (!strcmp(s, "remove")) { info->action = PARAM_GTPURH_ACTION_REM; *flags |= PARAM_GTPURH_ACTION_REM; - } - else - { + } else { gtpurh_param_act(GTPURH_PARAM_BAD_VALUE, "GTPURH", "--action", s); } } @@ -128,10 +182,30 @@ GTPURH_parse(int c, char **argv, int invert, unsigned int *flags, switch (c) { case '1': - gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--action", *flags & PARAM_ACTION); - parse_gtpurh_action(optarg, info, flags); - *flags |= PARAM_ACTION; - return 1; + gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--own-ip", *flags & PARAM_LADDR); + parse_gtpurh_addr(optarg, info, PARAM_LADDR); + *flags |= PARAM_LADDR; + return 1; + case '2': + gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--own-tun", *flags & PARAM_LTUN); + parse_gtpurh_tunid(optarg, info, PARAM_LTUN); + *flags |= PARAM_LTUN; + return 1; + case '3': + gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--peer-ip", *flags & PARAM_RADDR); + parse_gtpurh_addr(optarg, info, PARAM_RADDR); + *flags |= PARAM_RADDR; + return 1; + case '4': + gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--peer-tun", *flags & PARAM_RTUN); + parse_gtpurh_tunid(optarg, info, PARAM_RTUN); + *flags |= PARAM_RTUN; + return 1; + case '5': + gtpurh_param_act(GTPURH_PARAM_ONLY_ONCE, "GTPURH", "--action", *flags & PARAM_ACTION); + parse_gtpurh_action(optarg, info, flags); + *flags |= PARAM_ACTION; + return 1; } return 1; @@ -143,10 +217,21 @@ static void GTPURH_check(unsigned int flags) { gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify action"); } - - if (flags & PARAM_GTPURH_ACTION_REM) + if (!(flags & PARAM_LADDR)) { - return; + gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify local addr"); + } + if (!(flags & PARAM_LTUN)) + { + gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify local tunnel id"); + } + if (!(flags & PARAM_RADDR)) + { + gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify remote addr"); + } + if (!(flags & PARAM_RTUN)) + { + gtpurh_exit_error(PARAMETER_PROBLEM, "GTPURH: You must specify remote tunnel id"); } } @@ -191,8 +276,12 @@ GTPURH_print(const void *ip, } static struct option GTPURH_opts[] = { - { "action", 1, NULL, '1' }, - { .name = NULL } + { "own-ip", 1, NULL, '1' }, + { "own-tun", 1, NULL, '2' }, + { "peer-ip", 1, NULL, '3' }, + { "peer-tun", 1, NULL, '4' }, + { "action", 1, NULL, '5' }, + { .name = NULL } }; #if (IPTVERSION <= 135) diff --git a/openair-cn/GTPV1-U/GTPURH/xt_GTPURH.c b/openair-cn/GTPV1-U/GTPURH/xt_GTPURH.c index 78f920185f..f31512570d 100755 --- a/openair-cn/GTPV1-U/GTPURH/xt_GTPURH.c +++ b/openair-cn/GTPV1-U/GTPURH/xt_GTPURH.c @@ -1,4 +1,3 @@ - /* * GTPu klm for Linux/iptables * @@ -28,6 +27,9 @@ #if 0 #include #endif +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +# define WITH_IPV6 1 +#endif //#define ROUTE_PACKET 1 @@ -39,220 +41,50 @@ #error "Kernel version is not defined!!!! Exiting." #endif +#define NIPADDR(addr) \ + (uint8_t)(addr & 0x000000FF), \ + (uint8_t)((addr & 0x0000FF00) >> 8), \ + (uint8_t)((addr & 0x00FF0000) >> 16), \ + (uint8_t)((addr & 0xFF000000) >> 24) + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pradip Biswas "); MODULE_DESCRIPTION("GTPu Data Path extension on netfilter"); - -/* - * Statically sized hash table implementation - * (C) 2012 Sasha Levin - */ - -#ifndef _LINUX_HASHTABLE_H -#define _LINUX_HASHTABLE_H - -#include -#include -#include -#include -#include - -#define DEFINE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] = \ - { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } - -#define DECLARE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] - -#define HASH_SIZE(name) (ARRAY_SIZE(name)) -#define HASH_BITS(name) ilog2(HASH_SIZE(name)) - -/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ -#define hash_min(val, bits) \ - (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) - -static inline void __hash_init(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - INIT_HLIST_HEAD(&ht[i]); -} - -/** - * hash_init - initialize a hash table - * @hashtable: hashtable to be initialized - * - * Calculates the size of the hashtable from the given parameter, otherwise - * same as hash_init_size. - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_add - add an object to a hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add(hashtable, node, key) \ - hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_add_rcu - add an object to a rcu enabled hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add_rcu(hashtable, node, key) \ - hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_hashed - check whether an object is in any hashtable - * @node: the &struct hlist_node of the object to be checked - */ -static inline bool hash_hashed(struct hlist_node *node) -{ - return !hlist_unhashed(node); -} - -static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - if (!hlist_empty(&ht[i])) - return false; - - return true; -} - -/** - * hash_empty - check whether a hashtable is empty - * @hashtable: hashtable to check - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_del - remove an object from a hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del(struct hlist_node *node) -{ - hlist_del_init(node); -} - -/** - * hash_del_rcu - remove an object from a rcu enabled hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del_rcu(struct hlist_node *node) -{ - hlist_del_init_rcu(node); -} - -/** - * hash_for_each - iterate over a hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each(name, bkt, obj, pos, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry(obj, pos, &name[bkt], member) - - -/** - * hash_for_each_rcu - iterate over a rcu enabled hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_rcu(name, bkt, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_rcu(obj, &name[bkt], member) - -/** - * hash_for_each_safe - iterate over a hashtable safe against removal of - * hash entry - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @tmp: a &struct used for temporary storage - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_safe(name, bkt, tmp, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_safe(obj, tmp, &name[bkt], member) - -/** - * hash_for_each_possible - iterate over all possible objects hashing to the - * same bucket - * @name: hashtable to iterate - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible(name, tpos, pos, member, key) \ - hlist_for_each_entry(tpos, pos, &name[hash_min(key, HASH_BITS(name))], member) - - -/** - * hash_for_each_possible_rcu - iterate over all possible objects hashing to the - * same bucket in an rcu enabled hashtable - * in a rcu enabled hashtable - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_rcu(name, obj, member, key) \ - hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\ - member) - -/** - * hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing - * to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - * - * This is the same as hash_for_each_possible_rcu() except that it does - * not do any RCU debugging or tracing. - */ -#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \ - hlist_for_each_entry_rcu_notrace(obj, \ - &name[hash_min(key, HASH_BITS(name))], member) - -/** - * hash_for_each_possible_safe - iterate over all possible objects hashing to the - * same bucket safe against removals - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @tmp: a &struct used for temporary storage - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ - hlist_for_each_entry_safe(obj, tmp,\ - &name[hash_min(key, HASH_BITS(name))], member) - - +static char* _gtpurh_nf_inet_hook_2_string(int nf_inet_hookP); +static inline bool _gtpurh_ip_is_fragment(const struct iphdr *iph_p); +static void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP); +static unsigned int _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP); +#if defined(WITH_IPV6) +static unsigned int gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP); #endif +static unsigned int gtpurh_tg4(struct sk_buff *skb_pP, const struct xt_action_param *par_pP); + +static struct xt_target gtpurh_tg_reg[] __read_mostly = { + { + .name = "GTPURH", + .revision = 0, + .family = NFPROTO_IPV4, + .hooks = (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_OUT), + .proto = IPPROTO_UDP, + .table = "raw", + .target = gtpurh_tg4, + .targetsize = sizeof(struct xt_gtpurh_target_info), + .me = THIS_MODULE, + }, +#if defined(WITH_IPV6) + { + .name = "GTPURH", + .revision = 0, + .family = NFPROTO_IPV6, + .proto = IPPROTO_UDP, + .table = "raw", + .target = gtpurh_tg6, + .me = THIS_MODULE, + }, +#endif +}; struct gtpuhdr { @@ -276,28 +108,26 @@ struct gtpuhdr static char _gtpurh_print_buffer[GTPURH_2_PRINT_BUFFER_LEN]; -/*typedef struct ip_fragment_entry_s { - struct sk_buff *skb_p; - //struct timeval first_ts; // TO DO WITH IP_FRAG_TIME - int flags; //ip header field - int offset; //ip header field - int end; - struct hlist_node node; -}ip_fragment_entry_t; +//----------------------------------------------------------------------------- +static char* +_gtpurh_nf_inet_hook_2_string(int nf_inet_hookP) { + //----------------------------------------------------------------------------- + switch (nf_inet_hookP) { + case NF_INET_PRE_ROUTING: return "NF_INET_PRE_ROUTING";break; + case NF_INET_LOCAL_IN: return "NF_INET_LOCAL_IN";break; + case NF_INET_FORWARD: return "NF_INET_FORWARD";break; + case NF_INET_LOCAL_OUT: return "NF_INET_LOCAL_OUT";break; + case NF_INET_POST_ROUTING: return "NF_INET_POST_ROUTING";break; + default: return "NF_INET_UNKNOWN"; + } +} -typedef struct ip_reassembly_entry_s { -}ip_reassembly_entry_t; -*/ - -static inline bool _gtpurh_ip_is_fragment(const struct iphdr *iph_p) -{ +//----------------------------------------------------------------------------- +static inline bool +_gtpurh_ip_is_fragment(const struct iphdr *iph_p) { + //----------------------------------------------------------------------------- return (iph_p->frag_off & htons(IP_MF | IP_OFFSET)) != 0; } -#define MAX_IP_FRAGMENTS 16 - -#define GTPURH_HASHTABLE_BITS 7 - -DEFINE_HASHTABLE(ip_fragments, GTPURH_HASHTABLE_BITS); //----------------------------------------------------------------------------- void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP) @@ -356,7 +186,9 @@ void _gtpurh_print_hex_octets(unsigned char* data_pP, unsigned short sizeP) #if defined(ROUTE_PACKET) +//----------------------------------------------------------------------------- static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_target_info *info_pP) +//----------------------------------------------------------------------------- { int err = 0; struct rtable *rt = NULL; @@ -408,7 +240,7 @@ static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_ skb_dst_set(skb_pP, &rt->dst); skb_pP->dev = skb_dst(skb_pP)->dev; - /* Send the GTPu message out */ + // Send the GTPu message out ip_local_out(skb_pP); if (err == 0) { @@ -418,140 +250,12 @@ static bool _gtpurh_route_packet(struct sk_buff *skb_pP, const struct xt_gtpurh_ } } #endif -/* -static void -_gtpurh_delete_collection_ip_fragments(void) -{ - int bucket_loop_cursor = 0; - struct ip_fragment_entry_s *ip_fragment_p = NULL; - struct hlist_node *pos_p = NULL; - - hash_for_each(ip_fragments, bucket_loop_cursor, ip_fragment_p, pos_p, node) { - pr_info("GTPURH: %s struct ip_fragment_entry_s* %p, struct hlist_node* %p\n", - __FUNCTION__, - ip_fragment_p, - pos_p); - } -} - - -static int -_gtpurh_target_reassembly(struct sk_buff *orig_skb_pP, const struct xt_gtpurh_target_info *tgi_pP) -{ - struct iphdr *iph_p = ip_hdr(orig_skb_pP); - struct sk_buff *skb_p = NULL; - struct sk_buff *new_skb_p = NULL; - uint16_t key = 0; - int flags, offset, last_frag_offset; - int ihl, end; - struct ip_fragment_entry_s *ip_fragment_p = NULL; - struct hlist_node *pos_p = NULL; - int all_segments_availables = 1; - - if ((orig_skb_pP) && (tgi_pP)) { - offset = ntohs(iph_p->frag_off); - flags = offset & ~IP_OFFSET; - offset &= IP_OFFSET; // offset is in 8-byte chunks - offset <<= 3; - ihl = ip_hdrlen(orig_skb_pP); - end = offset + orig_skb_pP->len - ihl; - - key = iph_p->id; - - pr_info("---------------GTPURH: Dump fragment:------------------------------------------------\n"); - _gtpurh_print_hex_octets((unsigned char*)iph_p, orig_skb_pP->len); - // Is this the final fragment? - if ((flags & IP_MF) == 0) { - pr_info("GTPURH: try reassembly last segment id %u len %u offset %u end %u\n", - key,orig_skb_pP->len, offset, end); - // may be the last segment received - // normally iterator gives elements from head to tail, but elements - // have been inserted at the head, so iterator should retrieve fragments - // in reverse order. - last_frag_offset = offset; - hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) { - pr_info("GTPURH: try reassembly segment id %u len %u offset %u end %u\n", - key,ip_fragment_p->skb_p->len, ip_fragment_p->offset, ip_fragment_p->end); - if (ip_fragment_p->end == offset) { - offset = ip_fragment_p->offset; - } else { - pr_info("GTPURH: try reassembly segment id %u failed\n", - key); - all_segments_availables = 0; - break; - } - } - if (all_segments_availables) { - // not optimal, but optimize later - new_skb_p = skb_copy_expand(orig_skb_pP, - last_frag_offset + skb_headroom(orig_skb_pP), - skb_tailroom(orig_skb_pP), - GFP_ATOMIC); - if (new_skb_p != NULL) - { - hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) { - skb_p = ip_fragment_p->skb_p; - skb_pull(new_skb_p, ihl); - - pr_info("GTPURH: reassembly segment id %u len %u offset %u end %u\n", - key, skb_p->len, ip_fragment_p->offset, ip_fragment_p->end); - - iph_p = (struct iphdr*)skb_push(new_skb_p, skb_p->len); - ihl = ip_hdrlen(skb_p); - memcpy(iph_p, skb_network_header(skb_p), skb_p->len); - } - skb_set_network_header(new_skb_p, 0); - if (_gtpurh_route_packet(new_skb_p, tgi_pP) != GTPURH_SUCCESS) - { - kfree_skb(new_skb_p); - } - - } else { - pr_info("GTPURH: Failed in skb_p allocation (%u bytes)\n", - last_frag_offset + skb_headroom(orig_skb_pP)); - } - } - if (1) { - hash_for_each_possible(ip_fragments, ip_fragment_p, pos_p, node, key) { - kfree_skb(ip_fragment_p->skb_p); - hash_del(pos_p); - kfree(ip_fragment_p); - } - } - } else { - pr_info("GTPURH: but in buffer not last segment id %u len %u offset %u end %u\n", - key,orig_skb_pP->len, offset, end); - // not the last fragment received - // assuming no out of order - ip_fragment_p = kmalloc(sizeof(struct ip_fragment_entry_s), GFP_KERNEL); - - if (NULL != ip_fragment_p) { - ip_fragment_p->skb_p = skb_copy(orig_skb_pP, GFP_ATOMIC); // may use skb_clone(), TODO - ip_fragment_p->flags = flags; - ip_fragment_p->offset = offset; - ip_fragment_p->end = end; - pr_info("GTPURH: adding in hashtable key %04x ip_fragment %p skbuff %p\n", - key, ip_fragment_p, ip_fragment_p->skb_p); - - INIT_HLIST_NODE(&ip_fragment_p->node); - hash_add(ip_fragments, &ip_fragment_p->node, key); - return 0; - } else { - pr_info("GTPURH: ERROR could not allocate memory for buffering IP fragment\n"); - } - } - } else { - pr_info("%s(skb_p=%p,tgi_pP=%p) parameter skb_p or tgi_pP is NULL\n", - __FUNCTION__, orig_skb_pP, tgi_pP); - } - return -1; -}*/ - - +//----------------------------------------------------------------------------- static unsigned int -_gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP) -{ +_gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_pP) { +//----------------------------------------------------------------------------- + struct iphdr *iph_p = ip_hdr(orig_skb_pP); struct iphdr *iph2_p = NULL; struct udphdr *udph_p = NULL; @@ -560,7 +264,6 @@ _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_p #if defined(NEW_SKB) struct sk_buff *new_skb_p = NULL; struct iphdr *new_ip_p = NULL; - unsigned int addr_type = 0; #endif uint16_t gtp_payload_size = 0; @@ -730,57 +433,78 @@ _gtpurh_tg4_rem(struct sk_buff *orig_skb_pP, const struct xt_action_param *par_p skb_p->priority = rt_tos2priority(iph2_p->tos); skb_p->pkt_type = PACKET_OTHERHOST; skb_dst_drop(skb_p); - skb_dst_set(skb_p, &rt->dst); + skb_dst_set(skb_p, dst_clone(&rt->dst)); skb_p->dev = skb_dst(skb_p)->dev; - } + #if defined(NEW_SKB) - new_skb_p = alloc_skb(LL_MAX_HEADER + ntohs(iph2_p->tot_len), GFP_ATOMIC); - if (new_skb_p == NULL) { - return NF_DROP; - } + new_skb_p = alloc_skb(LL_MAX_HEADER + ntohs(iph2_p->tot_len), GFP_ATOMIC); + if (new_skb_p == NULL) { + return NF_DROP; + } - skb_reserve(new_skb_p, LL_MAX_HEADER); - new_skb_p->protocol = skb_p->protocol; + skb_reserve(new_skb_p, LL_MAX_HEADER); + new_skb_p->protocol = skb_p->protocol; - skb_reset_network_header(new_skb_p); - new_ip_p = (void *)skb_put(new_skb_p, iph2_p->ihl << 2); - skb_reset_transport_header(new_skb_p); - skb_put(new_skb_p, ntohs(iph2_p->tot_len) - (iph2_p->ihl << 2)); - memcpy(new_ip_p, iph2_p, ntohs(iph2_p->tot_len)); + skb_reset_network_header(new_skb_p); + new_ip_p = (void *)skb_put(new_skb_p, iph2_p->ihl << 2); + skb_reset_transport_header(new_skb_p); + skb_put(new_skb_p, ntohs(iph2_p->tot_len) - (iph2_p->ihl << 2)); + memcpy(new_ip_p, iph2_p, ntohs(iph2_p->tot_len)); - new_skb_p->mark = ntohl(gtpuh_p->tunid); + new_skb_p->mark = ntohl(gtpuh_p->tunid); //new_skb_p->mark = skb_p->mark; - /* ip_route_me_harder expects skb->dst to be set */ - skb_dst_set(new_skb_p, dst_clone(skb_dst(skb_p))); + /* ip_route_me_harder expects skb->dst to be set */ + skb_dst_set(new_skb_p, dst_clone(skb_dst(skb_p))); - if (ip_route_me_harder(new_skb_p, RTN_UNSPEC) < 0) - goto free_new_skb; + /*if (ip_route_me_harder(new_skb_p, RTN_UNSPEC) < 0) { + pr_info("GTPURH: cannot route harder dest 0x%x\n", daddr); + goto free_skb; + }*/ - new_ip_p->ttl = ip4_dst_hoplimit(skb_dst(new_skb_p)); - new_skb_p->ip_summed = CHECKSUM_NONE; + new_ip_p->ttl = new_ip_p->ttl -1; // ip4_dst_hoplimit(skb_dst(new_skb_p)); + new_skb_p->ip_summed = CHECKSUM_NONE; - /* "Never happens" (?) */ - if (new_skb_p->len > dst_mtu(skb_dst(new_skb_p))) - goto free_new_skb; + if (new_skb_p->len > dst_mtu(skb_dst(new_skb_p))) { + pr_info("GTPURH: bad length\n"); + goto free_skb; + } - nf_ct_attach(new_skb_p, skb_p); - ip_local_out(new_skb_p); - return NF_DROP; + nf_ct_attach(new_skb_p, skb_p); + pr_info("GTPURH: ip_local_out %s/%s dev %s src %u.%u.%u.%u dst %u.%u.%u.%u \n", + _gtpurh_nf_inet_hook_2_string(par_pP->hooknum), + gtpurh_tg_reg[0].table, + (new_skb_p->dev == NULL) ? "NULL" : new_skb_p->dev->name, + NIPADDR(new_ip_p->saddr), + NIPADDR(new_ip_p->daddr)); + ip_local_out(new_skb_p); + return NF_DROP; +free_skb: + pr_info("GTPURH: Dropped skb ip_local_out %s/%s\n", + _gtpurh_nf_inet_hook_2_string(par_pP->hooknum), + gtpurh_tg_reg[0].table); + kfree_skb(new_skb_p); + return NF_DROP; -free_new_skb: - kfree_skb(new_skb_p); - return NF_DROP; #else - return NF_ACCEPT; + + return NF_ACCEPT; +free_skb: + pr_info("GTPURH: Dropped skb\n"); + kfree_skb(skb_p); + return NF_DROP; #endif + } #endif } +#if defined(WITH_IPV6) +//----------------------------------------------------------------------------- static unsigned int gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP) +//----------------------------------------------------------------------------- { const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo; int result = NF_DROP; @@ -794,60 +518,70 @@ gtpurh_tg6(struct sk_buff *skb_pP, const struct xt_action_param *par_pP) } return result; } +#endif +//----------------------------------------------------------------------------- static unsigned int gtpurh_tg4(struct sk_buff *skb_pP, const struct xt_action_param *par_pP) +//----------------------------------------------------------------------------- { + const struct iphdr *iph_p = ip_hdr(skb_pP); + const struct rtable *rt_p = skb_rtable(skb_pP); const struct xt_gtpurh_target_info *tgi_p = par_pP->targinfo; - int result = NF_ACCEPT; if (tgi_p == NULL) { - return result; + return NF_ACCEPT; + } + + if ((tgi_p->raddr != iph_p->saddr) || (tgi_p->laddr != iph_p->daddr)) { + pr_info("GTPURH: Not processed because of not matching saddr %d.%d.%d.%d raddr %d.%d.%d.%d laddr %d.%d.%d.%d daddr %d.%d.%d.%d\n", + NIPADDR(tgi_p->raddr), + NIPADDR(iph_p->saddr), + NIPADDR(tgi_p->laddr), + NIPADDR(iph_p->daddr)); + return NF_ACCEPT; + } + + if (ip_hdrlen(skb_pP) != sizeof(struct iphdr)) { + pr_info("GTPURH: Dropped because IP options\n"); + return NF_DROP; + } + + // Drop fragments + if (iph_p->frag_off & htons(IP_OFFSET)) { + pr_info("GTPURH: Dropped because is fragment\n"); + return NF_DROP; } if (tgi_p->action == PARAM_GTPURH_ACTION_REM) { - result = _gtpurh_tg4_rem(skb_pP, par_pP); + return _gtpurh_tg4_rem(skb_pP, par_pP); } - return result; + return NF_DROP; } -static struct xt_target gtpurh_tg_reg[] __read_mostly = { - { - .name = "GTPURH", - .revision = 0, - .family = NFPROTO_IPV6, - .proto = IPPROTO_UDP, - .table = "raw", - .target = gtpurh_tg6, - .me = THIS_MODULE, - }, - { - .name = "GTPURH", - .revision = 0, - .family = NFPROTO_IPV4, - .hooks = (1 << NF_INET_PRE_ROUTING) | - (1 << NF_INET_LOCAL_OUT), - .proto = IPPROTO_UDP, - .table = "raw", - .target = gtpurh_tg4, - .targetsize = sizeof(struct xt_gtpurh_target_info), - .me = THIS_MODULE, - }, -}; -static int __init gtpurh_tg_init(void) -{ +//----------------------------------------------------------------------------- +static int +__init gtpurh_tg_init(void) { +//----------------------------------------------------------------------------- + pr_info("GTPURH: Initializing module (KVersion: %d)\n", KVERSION); pr_info("GTPURH: Copyright Polaris Networks 2010-2011\n"); pr_info("GTPURH: Modified by EURECOM Lionel GAUTHIER 2014\n"); - //hash_init(ip_fragments); +#if defined(WITH_IPV6) + pr_info("GTPURH: IPv4/IPv6 enabled\n"); +#else + pr_info("GTPURH: IPv4 only enabled\n"); +#endif return xt_register_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg)); } -static void __exit gtpurh_tg_exit(void) -{ +//----------------------------------------------------------------------------- +static void +__exit gtpurh_tg_exit(void) { +//----------------------------------------------------------------------------- + xt_unregister_targets(gtpurh_tg_reg, ARRAY_SIZE(gtpurh_tg_reg)); - //_gtpurh_delete_collection_ip_fragments(); pr_info("GTPURH: Unloading module\n"); }