From 35149a848e169a7717d30537b54770e513a34679 Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Thu, 17 Jul 2014 14:16:54 +0400 Subject: ipoe: fixed passing packets in 'redirect on reject' mode --- accel-pppd/ctrl/ipoe/ipoe.c | 39 +++-------- accel-pppd/ctrl/ipoe/ipoe.h | 2 + accel-pppd/ctrl/ipoe/ipoe_netlink.c | 72 +++++++++++++++++++ drivers/ipoe/ipoe.c | 135 ++++++++++++++++++++++++++++++++++-- drivers/ipoe/ipoe.h | 2 + 5 files changed, 215 insertions(+), 35 deletions(-) diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index ec241ea8..134aec8c 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -68,7 +68,6 @@ struct unit_cache { struct l4_redirect { struct list_head entry; - int ifindex; in_addr_t addr; time_t timeout; }; @@ -339,7 +338,7 @@ static char *ipoe_session_get_username(struct ipoe_session *ses) return _strdup(ses->ses.ifname); } -static void l4_redirect_list_add(in_addr_t addr, int ifindex) +static void l4_redirect_list_add(in_addr_t addr) { struct l4_redirect *n = _malloc(sizeof(*n)); struct timespec ts; @@ -351,10 +350,9 @@ static void l4_redirect_list_add(in_addr_t addr, int ifindex) memset(n, 0, sizeof(*n)); n->addr = addr; - n->ifindex = ifindex; n->timeout = ts.tv_sec + conf_l4_redirect_on_reject; - ipoe_nl_modify(ifindex, addr, 1, NULL, NULL); + ipoe_nl_add_exclude(addr, 32); if (conf_l4_redirect_table) iprule_add(addr, conf_l4_redirect_table); @@ -391,7 +389,6 @@ static void l4_redirect_list_timer(struct triton_timer_t *t) { struct l4_redirect *n; struct timespec ts; - struct unit_cache *uc; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -407,16 +404,8 @@ static void l4_redirect_list_timer(struct triton_timer_t *t) if (conf_l4_redirect_ipset) ipset_del(conf_l4_redirect_ipset, n->addr); - - if (uc_size < conf_unit_cache && ipoe_nl_modify(n->ifindex, 0, 0, "", NULL)) { - uc = mempool_alloc(uc_pool); - uc->ifindex = n->ifindex; - pthread_mutex_lock(&uc_lock); - list_add_tail(&uc->entry, &uc_list); - ++uc_size; - pthread_mutex_unlock(&uc_lock); - } else - ipoe_nl_delete(n->ifindex); + + ipoe_nl_del_exclude(n->addr); _free(n); pthread_rwlock_wrlock(&l4_list_lock); @@ -555,10 +544,8 @@ static void ipoe_session_start(struct ipoe_session *ses) pthread_rwlock_unlock(&ses_lock); if (conf_ppp_verbose) log_ppp_warn("authentication failed\n"); - if (conf_l4_redirect_on_reject && !ses->dhcpv4_request && ses->ifindex != -1) { - l4_redirect_list_add(ses->yiaddr, ses->ifindex); - ses->ifindex = -1; - } + if (conf_l4_redirect_on_reject && !ses->dhcpv4_request) + l4_redirect_list_add(ses->yiaddr); ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0); return; } @@ -1836,7 +1823,7 @@ static void l4_redirect_ctx_close(struct triton_context_t *ctx) if (conf_l4_redirect_ipset) ipset_del(conf_l4_redirect_ipset, n->addr); - ipoe_nl_delete(n->ifindex); + ipoe_nl_del_exclude(n->addr); _free(n); } @@ -2437,17 +2424,7 @@ static void parse_local_net(const char *opt) mask = 24; } - if (mask == 32) - mask = 0xffffffff; - else - mask = (1 << (32-mask)) - 1; - - addr = ntohl(addr); - mask = ~mask; - - //printf("%x/%x %x\n", htonl(addr), ~mask, htonl(addr)&(~mask)); - - ipoe_nl_add_net(addr & mask, mask); + ipoe_nl_add_net(addr, mask); return; diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index b3a346f3..e50d7221 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -122,6 +122,8 @@ void ipoe_nl_get_sessions(struct list_head *list); int ipoe_nl_add_vlan_mon(int ifindex, long *mask, int len); int ipoe_nl_add_vlan_mon_vid(int ifindex, int vid); int ipoe_nl_del_vlan_mon(int ifindex); +int ipoe_nl_add_exclude(uint32_t addr, int mask); +void ipoe_nl_del_exclude(uint32_t addr); struct arp_serv *arpd_start(struct ipoe_serv *ipoe); void arpd_stop(struct arp_serv *arp); diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index e4d1d024..7643961a 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -74,6 +74,8 @@ void ipoe_nl_add_net(uint32_t addr, int mask) ghdr = NLMSG_DATA(&req.n); ghdr->cmd = IPOE_CMD_ADD_NET; + + mask = ((1 << mask) - 1) << (32 - mask); addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); addattr32(nlh, 1024, IPOE_ATTR_MASK, mask); @@ -82,6 +84,74 @@ void ipoe_nl_add_net(uint32_t addr, int mask) log_error("ipoe: nl_add_net: error talking to kernel\n"); } +int ipoe_nl_add_exclude(uint32_t addr, int mask) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + int ret = 0; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_ppp_error("ipoe: cannot open generic netlink socket\n"); + return -1; + } + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = ipoe_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = IPOE_CMD_ADD_EXCLUDE; + + + addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { + log_ppp_error("ipoe: nl_add_net: error talking to kernel\n"); + ret = -1; + } + + rtnl_close(&rth); + + return ret; +} + +void ipoe_nl_del_exclude(uint32_t addr) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_ppp_error("ipoe: cannot open generic netlink socket\n"); + return; + } + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = ipoe_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = IPOE_CMD_DEL_EXCLUDE; + + addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) + log_ppp_error("ipoe: nl_add_net: error talking to kernel\n"); + + rtnl_close(&rth); +} + void ipoe_nl_delete_interfaces(void) { struct nlmsghdr *nlh; @@ -673,6 +743,8 @@ static void init(void) triton_md_register_handler(&mc_ctx, &mc_hnd); triton_md_enable_handler(&mc_hnd, MD_MODE_READ); triton_context_wakeup(&mc_ctx); + + ipoe_nl_del_exclude(0); } DEFINE_INIT(19, init); diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 1aafde62..04fc7113 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -65,7 +65,6 @@ struct ipoe_session { __be32 addr; __be32 peer_addr; - __be32 l4_redirect; __u8 hwaddr[ETH_ALEN]; struct net_device *dev; @@ -121,6 +120,7 @@ struct vlan_notify { static struct list_head ipoe_list[HASH_BITS + 1]; static struct list_head ipoe_list1_u[HASH_BITS + 1]; +static struct list_head ipoe_excl_list[HASH_BITS + 1]; static LIST_HEAD(ipoe_list2); static LIST_HEAD(ipoe_list2_u); static DEFINE_SEMAPHORE(ipoe_wlock); @@ -196,6 +196,28 @@ static int ipoe_check_network(__be32 addr) return r; } +static int ipoe_check_exclude(__be32 addr) +{ + struct ipoe_network *n; + struct list_head *ht; + int r = 0; + + ht = &ipoe_excl_list[hash_addr(addr)]; + + rcu_read_lock(); + + list_for_each_entry_rcu(n, ht, entry) { + if (addr == n->addr) { + r = 1; + break; + } + } + + rcu_read_unlock(); + + return r; +} + static int ipoe_check_interface(int ifindex) { struct ipoe_iface *i; @@ -754,6 +776,9 @@ static unsigned int ipt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *s ses = ipoe_lookup(iph->saddr); if (!ses) { + if (ipoe_check_exclude(iph->saddr)) + return NF_ACCEPT; + if (!ipoe_check_network(iph->saddr)) return NF_ACCEPT; @@ -847,6 +872,9 @@ static unsigned int ipt_out_hook(const struct nf_hook_ops *ops, struct sk_buff * iph = ip_hdr(skb); + if (ipoe_check_exclude(iph->daddr)) + return NF_ACCEPT; + if (!ipoe_check_network(iph->daddr)) return NF_ACCEPT; @@ -1558,6 +1586,7 @@ static int ipoe_nl_cmd_add_net(struct sk_buff *skb, struct genl_info *info) n->addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]); n->mask = nla_get_u32(info->attrs[IPOE_ATTR_MASK]); + n->addr = ntohl(n->addr) & n->mask; //pr_info("add net %08x/%08x\n", n->addr, n->mask); down(&ipoe_wlock); @@ -1596,6 +1625,89 @@ static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info) return 0; } +static int ipoe_nl_cmd_add_exclude(struct sk_buff *skb, struct genl_info *info) +{ + struct ipoe_network *n; + struct list_head *ht; + + if (!info->attrs[IPOE_ATTR_ADDR]) + return -EINVAL; + + n = kmalloc(sizeof(*n), GFP_KERNEL); + if (!n) + return -ENOMEM; + + n->addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]); + + ht = &ipoe_excl_list[hash_addr(n->addr)]; + + down(&ipoe_wlock); + list_add_tail_rcu(&n->entry, ht); + up(&ipoe_wlock); + + return 0; +} + +static void clean_excl_list(void) +{ + struct ipoe_network *n; + struct list_head *ht; + int i; + + down(&ipoe_wlock); + rcu_read_lock(); + for (i = 0; i <= HASH_BITS; i++) { + ht = &ipoe_excl_list[i]; + list_for_each_entry_rcu(n, ht, entry) { + list_del_rcu(&n->entry); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + kfree_rcu(n, rcu_head); +#else + call_rcu(&n->rcu_head, ipoe_kfree_rcu); +#endif + } + } + rcu_read_unlock(); + up(&ipoe_wlock); +} + +static int ipoe_nl_cmd_del_exclude(struct sk_buff *skb, struct genl_info *info) +{ + struct list_head *ht; + struct ipoe_network *n; + u32 addr; + + if (!info->attrs[IPOE_ATTR_ADDR]) + return -EINVAL; + + addr = ntohl(nla_get_u32(info->attrs[IPOE_ATTR_ADDR])); + if (!addr) { + clean_excl_list(); + return 0; + } + + ht = &ipoe_excl_list[hash_addr(addr)]; + + down(&ipoe_wlock); + rcu_read_lock(); + list_for_each_entry_rcu(n, ht, entry) { + if (n->addr == addr) { + list_del_rcu(&n->entry); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + kfree_rcu(n, rcu_head); +#else + call_rcu(&n->rcu_head, ipoe_kfree_rcu); +#endif + } + } + rcu_read_unlock(); + up(&ipoe_wlock); + + synchronize_rcu(); + + return 0; +} + static int ipoe_nl_cmd_add_interface(struct sk_buff *skb, struct genl_info *info) { struct ipoe_iface *i; @@ -1907,6 +2019,18 @@ static struct genl_ops ipoe_nl_ops[] = { .policy = ipoe_nl_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = IPOE_CMD_ADD_EXCLUDE, + .doit = ipoe_nl_cmd_add_exclude, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = IPOE_CMD_DEL_EXCLUDE, + .doit = ipoe_nl_cmd_del_exclude, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family ipoe_nl_family = { @@ -1976,14 +2100,15 @@ static int __init ipoe_init(void) { int err, i; - printk("IPoE session driver v1.8.0.2\n"); + printk("IPoE session driver v1.8.0.3\n"); /*err = register_pernet_device(&ipoe_net_ops); if (err < 0) return err;*/ - for (i = 0; i < HASH_BITS + 1; i++) { + for (i = 0; i <= HASH_BITS; i++) { INIT_LIST_HEAD(&ipoe_list[i]); INIT_LIST_HEAD(&ipoe_list1_u[i]); + INIT_LIST_HEAD(&ipoe_excl_list[i]); } skb_queue_head_init(&ipoe_queue); @@ -2070,7 +2195,7 @@ static void __exit ipoe_fini(void) down(&ipoe_wlock); up(&ipoe_wlock); - for (i = 0; i < HASH_BITS; i++) + for (i = 0; i <= HASH_BITS; i++) rcu_assign_pointer(ipoe_list[i].next, &ipoe_list[i]); rcu_barrier(); @@ -2122,6 +2247,8 @@ static void __exit ipoe_fini(void) kfree(vn); } + clean_excl_list(); + synchronize_rcu(); } diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h index 7296505c..192fa2f2 100644 --- a/drivers/ipoe/ipoe.h +++ b/drivers/ipoe/ipoe.h @@ -18,6 +18,8 @@ enum { IPOE_CMD_DEL_VLAN_MON, IPOE_REP_PKT, IPOE_VLAN_NOTIFY, + IPOE_CMD_ADD_EXCLUDE, + IPOE_CMD_DEL_EXCLUDE, __IPOE_CMD_MAX, }; -- cgit v1.2.3