summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2014-07-17 14:16:54 +0400
committerDmitry Kozlov <xeb@mail.ru>2014-07-17 14:17:38 +0400
commit35149a848e169a7717d30537b54770e513a34679 (patch)
tree841b68098b52bb1ef8aefd6fb41dd2e3d7446740
parent953a944839db2dd4cf4eef5ef9cd94e4ba08e4d8 (diff)
downloadaccel-ppp-35149a848e169a7717d30537b54770e513a34679.tar.gz
accel-ppp-35149a848e169a7717d30537b54770e513a34679.zip
ipoe: fixed passing packets in 'redirect on reject' mode
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c39
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h2
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c72
-rw-r--r--drivers/ipoe/ipoe.c135
-rw-r--r--drivers/ipoe/ipoe.h2
5 files changed, 215 insertions, 35 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index ec241ea..134aec8 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 b3a346f..e50d722 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 e4d1d02..7643961 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 1aafde6..04fc711 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 7296505..192fa2f 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,
};