From 33ca7f48ec3369301c1f0ce4aa1abe306151af76 Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Mon, 26 May 2014 09:51:06 +0400 Subject: ipoe: send NAK after number of unreplied REQUESTs After introduction offer-delay accel-ppp stopped to answer NAK for REQUESTs if requested session is not existing to give chance other servers to reply. But this causes that some broken clients enter to infinite REQUEST loop. This patch corrects this issue, so if offer-delay is not configured (means that this is only server in the net) or after receiving few REQUESTs accel-ppp send NAK for non-existing sessions. --- accel-pppd/ctrl/ipoe/ipoe.c | 62 ++++++++++++++++++++++++++++++++++++++++++--- accel-pppd/ctrl/ipoe/ipoe.h | 1 + 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 6855fbaf..e13ec45a 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -90,6 +90,13 @@ struct delay { int delay; }; +struct request_item { + struct list_head entry; + uint32_t xid; + time_t expire; + int cnt; +}; + static int conf_dhcpv4 = 1; static int conf_up = 0; static int conf_mode = 0; @@ -114,6 +121,7 @@ static int conf_l4_redirect_table; static int conf_l4_redirect_on_reject; static const char *conf_l4_redirect_ipset; static int conf_vlan_timeout = 30; +static int conf_max_request = 3; static const char *conf_relay; @@ -140,6 +148,7 @@ static unsigned int stat_delayed_offer; static mempool_t ses_pool; static mempool_t disc_item_pool; +static mempool_t req_item_pool; static int connlimit_loaded; @@ -1114,7 +1123,7 @@ static void ipoe_ses_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packe if (conf_verbose) { log_ppp_info2("recv "); - dhcpv4_print_packet(pack, 0, log_info2); + dhcpv4_print_packet(pack, 0, log_ppp_info2); } if (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id)) { @@ -1268,6 +1277,42 @@ static void ipoe_serv_check_disc(struct ipoe_serv *serv, struct dhcpv4_packet *p } } +static int ipoe_serv_request_check(struct ipoe_serv *serv, uint32_t xid) +{ + struct request_item *r; + struct list_head *pos, *n; + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + list_for_each_safe(pos, n, &serv->req_list) { + r = list_entry(pos, typeof(*r), entry); + if (r->xid == xid) { + if (++r->cnt == conf_max_request) { + list_del(&r->entry); + mempool_free(r); + return 1; + } + + r->expire = ts.tv_sec + 30; + return 0; + } + + if (ts.tv_sec > r->expire) { + list_del(&r->entry); + mempool_free(r); + } + } + + r = mempool_alloc(req_item_pool); + r->xid = xid; + r->expire = ts.tv_sec + 30; + r->cnt = 0; + list_add_tail(&r->entry, &serv->req_list); + + return 0; +} + static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack, int force) { struct ipoe_serv *serv = container_of(dhcpv4->ctx, typeof(*serv), ctx); @@ -1346,7 +1391,7 @@ static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet if (!ses) { if (conf_verbose) { - log_debug("recv "); + log_debug("%s: recv ", serv->ifname); dhcpv4_print_packet(pack, 0, log_debug); } @@ -1362,7 +1407,8 @@ static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet } triton_context_call(&opt82_ses->ctx, (triton_event_func)__ipoe_session_terminate, &opt82_ses->ses); - } + } else if (list_empty(&conf_offer_delay) || ipoe_serv_request_check(serv, pack->hdr->xid)) + dhcpv4_send_nak(dhcpv4, pack); } else { ses->xid = pack->hdr->xid; @@ -1373,7 +1419,7 @@ static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet if (conf_verbose) { log_switch(dhcpv4->ctx, &ses->ses); log_ppp_info2("recv "); - dhcpv4_print_packet(pack, 0, log_info2); + dhcpv4_print_packet(pack, 0, log_ppp_info2); if ((opt82_ses && ses != opt82_ses) || (!opt82_ses && pack->relay_agent)) log_ppp_warn("port change detected\n"); } @@ -1735,6 +1781,12 @@ static void ipoe_serv_release(struct ipoe_serv *serv) mempool_free(d); __sync_sub_and_fetch(&stat_delayed_offer, 1); } + + while (!list_empty(&serv->req_list)) { + struct request_item *r = list_first_entry(&serv->req_list, typeof(*r), entry); + list_del(&r->entry); + mempool_free(r); + } if (serv->disc_timer.tpd) triton_timer_del(&serv->disc_timer); @@ -2220,6 +2272,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int INIT_LIST_HEAD(&serv->sessions); INIT_LIST_HEAD(&serv->addr_list); INIT_LIST_HEAD(&serv->disc_list); + INIT_LIST_HEAD(&serv->req_list); memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); serv->disc_timer.expire = ipoe_serv_disc_timer; @@ -2967,6 +3020,7 @@ static void ipoe_init(void) { ses_pool = mempool_create(sizeof(struct ipoe_session)); disc_item_pool = mempool_create(sizeof(struct disc_item)); + req_item_pool = mempool_create(sizeof(struct request_item)); uc_pool = mempool_create(sizeof(struct unit_cache)); triton_context_register(&l4_redirect_ctx, NULL); diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 5ef46b7a..88e37e46 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -27,6 +27,7 @@ struct ipoe_serv { struct dhcpv4_relay *dhcpv4_relay; struct arp_serv *arp; struct list_head disc_list; + struct list_head req_list; struct triton_timer_t disc_timer; struct triton_timer_t timer; pthread_mutex_t lock; -- cgit v1.2.3 From 30397cca6a4472f3087d1071ecc43438e39f705f Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Mon, 26 May 2014 10:55:57 +0400 Subject: ipoe: introduced "ip-unnumbered" option Before this time accel-ppp always worked in "ip unnumbered" mode. This option may turn this mode off (default is on) --- accel-pppd/accel-ppp.conf | 1 + accel-pppd/ctrl/ipoe/ipoe.c | 80 ++++++++++++++++++++--------------------- accel-pppd/libnetlink/iputils.c | 4 +-- accel-pppd/libnetlink/iputils.h | 2 +- 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 2cec7d74..e3639d61 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -107,6 +107,7 @@ shared=0 ifcfg=1 mode=L2 start=dhcpv4 +#ip-unnumbered=1 #proxy-arp=0 #nat=0 #proto=100 diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index e13ec45a..9a21c8c3 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -50,6 +50,7 @@ struct ifaddr { struct list_head entry; in_addr_t addr; + int mask; int refs; }; @@ -141,6 +142,7 @@ static const char *conf_agent_remote_id; static int conf_proto; static LIST_HEAD(conf_offer_delay); static const char *conf_vlan_name; +static int conf_ip_unnumbered; static unsigned int stat_starting; static unsigned int stat_active; @@ -495,7 +497,7 @@ static int ipoe_create_interface(struct ipoe_session *ses) strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN); ses->ses.ifindex = ses->ifindex; ses->ses.unit_idx = ses->ifindex; - ses->ctrl.dont_ifcfg = 0; + ses->ctrl.dont_ifcfg = !conf_ip_unnumbered; log_ppp_info2("create interface %s parent %s\n", ifr.ifr_name, ses->serv->ifname); @@ -690,27 +692,30 @@ static void __ipoe_session_start(struct ipoe_session *ses) } } -static void ipoe_serv_add_addr(struct ipoe_serv *serv, in_addr_t addr) +static void ipoe_serv_add_addr(struct ipoe_serv *serv, in_addr_t addr, int mask) { struct ifaddr *a; pthread_mutex_lock(&serv->lock); - list_for_each_entry(a, &serv->addr_list, entry) { - if (a->addr == addr) { - a->refs++; - pthread_mutex_unlock(&serv->lock); + if (serv->opt_shared) { + list_for_each_entry(a, &serv->addr_list, entry) { + if (a->addr == addr) { + a->refs++; + pthread_mutex_unlock(&serv->lock); - return; + return; + } } } a = _malloc(sizeof(*a)); a->addr = addr; + a->mask = mask; a->refs = 1; list_add_tail(&a->entry, &serv->addr_list); - if (ipaddr_add(serv->ifindex, a->addr, 32)) + if (ipaddr_add(serv->ifindex, a->addr, mask)) log_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname); pthread_mutex_unlock(&serv->lock); @@ -725,7 +730,7 @@ static void ipoe_serv_del_addr(struct ipoe_serv *serv, in_addr_t addr) list_for_each_entry(a, &serv->addr_list, entry) { if (a->addr == addr) { if (--a->refs == 0) { - if (ipaddr_del(serv->ifindex, a->addr)) + if (ipaddr_del(serv->ifindex, a->addr, a->mask)) log_warn("ipoe: failed to delete addess from interface '%s'\n", serv->ifname); list_del(&a->entry); _free(a); @@ -741,19 +746,13 @@ static void ipoe_ifcfg_add(struct ipoe_session *ses) { struct ipoe_serv *serv = ses->serv; - if (ses->serv->opt_ifcfg) { - if (ses->serv->opt_shared) - ipoe_serv_add_addr(ses->serv, ses->siaddr); - else { - pthread_mutex_lock(&serv->lock); - if (ipaddr_add(serv->ifindex, ses->siaddr, 32)) - log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname); - pthread_mutex_unlock(&serv->lock); - } + if (ses->serv->opt_ifcfg) + ipoe_serv_add_addr(ses->serv, ses->siaddr, conf_ip_unnumbered ? 32 : ses->mask); + + if (conf_ip_unnumbered) { if (iproute_add(serv->ifindex, ses->serv->opt_src ? ses->serv->opt_src : ses->router, ses->yiaddr, conf_proto)) log_ppp_warn("ipoe: failed to add route to interface '%s'\n", serv->ifname); - } else if (iproute_add(serv->ifindex, ses->serv->opt_src ? ses->serv->opt_src : ses->router, ses->yiaddr, conf_proto)) - log_ppp_warn("ipoe: failed to add route to interface '%s'\n", serv->ifname); + } ses->ifcfg = 1; } @@ -762,23 +761,13 @@ static void ipoe_ifcfg_del(struct ipoe_session *ses, int lock) { struct ipoe_serv *serv = ses->serv; - if (iproute_del(serv->ifindex, ses->yiaddr, conf_proto)) - log_ppp_warn("ipoe: failed to delete route from interface '%s'\n", serv->ifname); - - if (ses->serv->opt_ifcfg) { - if (ses->serv->opt_shared) { - ipoe_serv_del_addr(ses->serv, ses->siaddr); - } else { - if (lock) - pthread_mutex_lock(&serv->lock); - if (ipaddr_del(serv->ifindex, ses->siaddr)) { - if (lock) - log_ppp_warn("ipoe: failed to remove addess from interface '%s'\n", serv->ifname); - } - if (lock) - pthread_mutex_unlock(&serv->lock); - } + if (conf_ip_unnumbered) { + if (iproute_del(serv->ifindex, ses->yiaddr, conf_proto)) + log_ppp_warn("ipoe: failed to delete route from interface '%s'\n", serv->ifname); } + + if (ses->serv->opt_ifcfg) + ipoe_serv_del_addr(ses->serv, ses->siaddr); } static void __ipoe_session_activate(struct ipoe_session *ses) @@ -797,6 +786,8 @@ static void __ipoe_session_activate(struct ipoe_session *ses) } } else if (ses->ses.ipv4->peer_addr != ses->yiaddr) addr = ses->ses.ipv4->peer_addr; + else if (!conf_ip_unnumbered) + ses->ctrl.dont_ifcfg = 1; if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, addr, NULL, NULL)) { ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0); @@ -811,8 +802,11 @@ static void __ipoe_session_activate(struct ipoe_session *ses) ses->ipv4.addr = ses->siaddr; } - if (ses->ifindex == -1 && (ses->serv->opt_ifcfg || (ses->serv->opt_mode == MODE_L2))) - ipoe_ifcfg_add(ses); + if (ses->ifindex == -1) { + if (ses->serv->opt_ifcfg || (ses->serv->opt_mode == MODE_L2)) + ipoe_ifcfg_add(ses); + } else if (ses->ctrl.dont_ifcfg) + ipaddr_add(ses->ifindex, ses->siaddr, ses->mask); if (ses->l4_redirect) ipoe_change_l4_redirect(ses, 0); @@ -2189,7 +2183,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (!serv->dhcpv4_relay && serv->opt_dhcpv4 && opt_relay) { if (opt_ifcfg) - ipoe_serv_add_addr(serv, opt_giaddr); + ipoe_serv_add_addr(serv, opt_giaddr, 32); serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay); } @@ -2285,7 +2279,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (opt_relay) { if (opt_ifcfg) - ipoe_serv_add_addr(serv, opt_giaddr); + ipoe_serv_add_addr(serv, opt_giaddr, 32); serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay); } } @@ -2995,6 +2989,12 @@ static void load_config(void) if (!conf_vlan_name) conf_vlan_name = "%I.%N"; + opt = conf_get_opt("ipoe", "ip-unnumbered"); + if (opt) + conf_ip_unnumbered = atoi(opt); + else + conf_ip_unnumbered = 1; + #ifdef RADIUS if (triton_module_loaded("radius")) load_radius_attrs(); diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c index fbb32c60..060fbab3 100644 --- a/accel-pppd/libnetlink/iputils.c +++ b/accel-pppd/libnetlink/iputils.c @@ -274,7 +274,7 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask) return 0; } -int __export ipaddr_del(int ifindex, in_addr_t addr) +int __export ipaddr_del(int ifindex, in_addr_t addr, int mask) { struct ipaddr_req { struct nlmsghdr n; @@ -295,7 +295,7 @@ int __export ipaddr_del(int ifindex, in_addr_t addr) req.n.nlmsg_type = RTM_DELADDR; req.i.ifa_family = AF_INET; req.i.ifa_index = ifindex; - req.i.ifa_prefixlen = 32; + req.i.ifa_prefixlen = mask; addattr32(&req.n, sizeof(req), IFA_LOCAL, addr); diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h index 896b4cc5..75dfd1a4 100644 --- a/accel-pppd/libnetlink/iputils.h +++ b/accel-pppd/libnetlink/iputils.h @@ -12,7 +12,7 @@ int iplink_vlan_add(const char *ifname, int ifindex, int vid); int iplink_vlan_del(int ifindex); int ipaddr_add(int ifindex, in_addr_t addr, int mask); -int ipaddr_del(int ifindex, in_addr_t addr); +int ipaddr_del(int ifindex, in_addr_t addr, int mask); int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, int proto); int iproute_del(int ifindex, in_addr_t dst, int proto); -- cgit v1.2.3 From 16d7884910de5f30a67351692492cc5a85dd6e3d Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Wed, 28 May 2014 18:46:42 +0400 Subject: ipoe: dhcp: fixed incorrect parsing empty options --- accel-pppd/ctrl/ipoe/dhcpv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c index 35fc4688..b4c962cb 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4.c @@ -183,7 +183,7 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna serv->hnd.read = dhcpv4_read; serv->ifindex = ifindex; - if (opt) { + if (opt && *opt) { str0 = _strdup(opt); str = str0; -- cgit v1.2.3