diff options
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 28 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 1 | ||||
-rw-r--r-- | accel-pppd/ipv6/dhcpv6.c | 189 | ||||
-rw-r--r-- | accel-pppd/ipv6/dhcpv6.h | 44 | ||||
-rw-r--r-- | accel-pppd/ipv6/nd.c | 32 | ||||
-rw-r--r-- | accel-pppd/radius/acct.c | 8 | ||||
-rw-r--r-- | accel-pppd/radius/serv.c | 2 |
7 files changed, 132 insertions, 172 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 134aec8c..b4a0e1a3 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -99,12 +99,13 @@ struct request_item { }; static int conf_dhcpv4 = 1; -static int conf_up = 0; -static int conf_mode = 0; +static int conf_up; +static int conf_mode; static int conf_shared = 1; static int conf_ifcfg = 1; -static int conf_nat = 0; -static int conf_arp = 0; +static int conf_nat; +static int conf_arp; +static int conf_ipv6; static uint32_t conf_src; static const char *conf_ip_pool; //static int conf_dhcpv6; @@ -806,6 +807,14 @@ static void __ipoe_session_activate(struct ipoe_session *ses) if (ses->l4_redirect) ipoe_change_l4_redirect(ses, 0); + + if (ses->serv->opt_mode == MODE_L2 && ses->serv->opt_ipv6 && sock6_fd != -1) { + ses->ses.ipv6 = ipdb_get_ipv6(&ses->ses); + if (!ses->ses.ipv6) + log_ppp_warn("ipoe: no free IPv6 address\n"); + if (!ses->ses.ipv6->peer_intf_id) + ses->ses.ipv6->peer_intf_id = htobe64(1); + } __sync_sub_and_fetch(&stat_starting, 1); __sync_add_and_fetch(&stat_active, 1); @@ -2035,6 +2044,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int int opt_ifcfg = conf_ifcfg; int opt_nat = conf_nat; int opt_username = conf_username; + int opt_ipv6 = conf_ipv6; #ifdef USE_LUA char *opt_lua_username_func = NULL; #endif @@ -2097,6 +2107,8 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int opt_src = inet_addr(ptr1); } else if (strcmp(str, "proxy-arp") == 0) { opt_arp = atoi(ptr1); + } else if (strcmp(str, "ipv6") == 0) { + opt_ipv6 = atoi(ptr1); } else if (strcmp(str, "username") == 0) { if (strcmp(ptr1, "ifname") == 0) opt_username = USERNAME_IFNAME; @@ -2197,6 +2209,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int serv->opt_src = opt_src; serv->opt_arp = opt_arp; serv->opt_username = opt_username; + serv->opt_ipv6 = opt_ipv6; #ifdef USE_LUA if (serv->opt_lua_username_func && (!opt_lua_username_func || strcmp(serv->opt_lua_username_func, opt_lua_username_func))) { _free(serv->opt_lua_username_func); @@ -2254,6 +2267,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int serv->opt_src = opt_src; serv->opt_arp = opt_arp; serv->opt_username = opt_username; + serv->opt_ipv6 = opt_ipv6; #ifdef USE_LUA serv->opt_lua_username_func = opt_lua_username_func; #endif @@ -2931,6 +2945,12 @@ static void load_config(void) else conf_agent_remote_id = "accel-pppd"; + opt = conf_get_opt("ipoe", "ipv6"); + if (opt) + conf_ipv6 = atoi(opt); + else + conf_ipv6 = 0; + opt = conf_get_opt("ipoe", "noauth"); if (opt) conf_noauth = atoi(opt); diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index e50d7221..44c8b99f 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -45,6 +45,7 @@ struct ipoe_serv { int opt_up:1; int opt_ifcfg:1; int opt_nat:1; + int opt_ipv6:1; int need_close:1; int active:1; }; diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index 809496e8..67b1b751 100644 --- a/accel-pppd/ipv6/dhcpv6.c +++ b/accel-pppd/ipv6/dhcpv6.c @@ -40,9 +40,10 @@ static int conf_dns_count; static void *conf_dnssl; static int conf_dnssl_size; -struct dhcpv6_pd -{ +struct dhcpv6_pd { struct ap_private pd; + struct ap_session *ses; + struct triton_md_handler_t hnd; struct dhcpv6_opt_clientid *clientid; uint32_t addr_iaid; uint32_t dp_iaid; @@ -50,35 +51,71 @@ struct dhcpv6_pd int dp_active:1; }; -static struct triton_md_handler_t dhcpv6_hnd; -static struct triton_context_t dhcpv6_ctx; - -static uint8_t *buf; static void *pd_key; -static void ev_ppp_started(struct ap_session *ses) +static int dhcpv6_read(struct triton_md_handler_t *h); + +static void ev_ses_started(struct ap_session *ses) { struct ipv6_mreq mreq; struct dhcpv6_pd *pd; + struct sockaddr_in6 addr; + int sock; + int f = 1; if (!ses->ipv6) return; + + sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (!sock) { + log_ppp_error("dhcpv6: socket: %s\n", strerror(errno)); + return; + } + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); - pd = _malloc(sizeof(*pd)); - memset(pd, 0, sizeof(*pd)); + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) { + log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno)); + close(sock); + return; + } - pd->pd.key = &pd_key; - list_add_tail(&pd->pd.entry, &ses->pd_list); + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(DHCPV6_SERV_PORT); + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { + log_ppp_error("dhcpv6: bind: %s\n", strerror(errno)); + close(sock); + return; + } memset(&mreq, 0, sizeof(mreq)); mreq.ipv6mr_interface = ses->ifindex; mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000); mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x010002); - if (setsockopt(dhcpv6_hnd.fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) { + if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) { log_ppp_error("dhcpv6: failed to join to All_DHCP_Relay_Agents_and_Servers\n"); + close(sock); return; } + + fcntl(sock, F_SETFL, O_NONBLOCK); + fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); + + pd = _malloc(sizeof(*pd)); + memset(pd, 0, sizeof(*pd)); + + pd->pd.key = &pd_key; + list_add_tail(&pd->pd.entry, &ses->pd_list); + + pd->ses = ses; + + pd->hnd.fd = sock; + pd->hnd.read = dhcpv6_read; + triton_md_register_handler(ses->ctrl->ctx, &pd->hnd); + triton_md_enable_handler(&pd->hnd, MD_MODE_READ); } static struct dhcpv6_pd *find_pd(struct ap_session *ses) @@ -93,7 +130,7 @@ static struct dhcpv6_pd *find_pd(struct ap_session *ses) return NULL; } -static void ev_ppp_finished(struct ap_session *ses) +static void ev_ses_finished(struct ap_session *ses) { struct dhcpv6_pd *pd = find_pd(ses); @@ -107,24 +144,12 @@ static void ev_ppp_finished(struct ap_session *ses) if (pd->ipv6_dp) ipdb_put_ipv6_prefix(ses, pd->ipv6_dp); + + triton_md_unregister_handler(&pd->hnd, 1); _free(pd); } -static void dhcpv6_send(struct dhcpv6_packet *reply) -{ - struct sockaddr_in6 addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(DHCPV6_CLIENT_PORT); - addr.sin6_addr.s6_addr32[0] = htons(0xfe80); - *(uint64_t *)(addr.sin6_addr.s6_addr + 8) = reply->ses->ipv6->peer_intf_id; - addr.sin6_scope_id = reply->ses->ifindex; - - sendto(dhcpv6_hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&addr, sizeof(addr)); -} - static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr) { memcpy(addr, &a->addr, sizeof(*addr)); @@ -405,7 +430,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i dhcpv6_packet_print(reply, log_ppp_info2); } - dhcpv6_send(reply); + sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr)); dhcpv6_packet_free(reply); } @@ -551,7 +576,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, dhcpv6_packet_print(reply, log_ppp_info2); } - dhcpv6_send(reply); + sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr)); dhcpv6_packet_free(reply); } @@ -559,11 +584,8 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, static void dhcpv6_recv_solicit(struct dhcpv6_packet *req) { - struct dhcpv6_pd *pd = find_pd(req->ses); + struct dhcpv6_pd *pd = req->pd; - if (!pd) - return; - if (!req->clientid) { log_ppp_error("dhcpv6: no Client-ID option\n"); return; @@ -591,11 +613,8 @@ static void dhcpv6_recv_solicit(struct dhcpv6_packet *req) static void dhcpv6_recv_request(struct dhcpv6_packet *req) { - struct dhcpv6_pd *pd = find_pd(req->ses); + struct dhcpv6_pd *pd = req->pd; - if (!pd) - return; - if (!req->clientid) { log_ppp_error("dhcpv6: no Client-ID option\n"); return; @@ -619,11 +638,8 @@ static void dhcpv6_recv_request(struct dhcpv6_packet *req) static void dhcpv6_recv_renew(struct dhcpv6_packet *req) { - struct dhcpv6_pd *pd = find_pd(req->ses); + struct dhcpv6_pd *pd = req->pd; - if (!pd) - return; - if (!req->clientid) { log_ppp_error("dhcpv6: no Client-ID option\n"); return; @@ -656,7 +672,7 @@ static void dhcpv6_recv_renew(struct dhcpv6_packet *req) static void dhcpv6_recv_information_request(struct dhcpv6_packet *req) { - struct dhcpv6_pd *pd = find_pd(req->ses); + struct dhcpv6_pd *pd = req->pd; if (req->rapid_commit) { log_ppp_error("dhcpv6: unexpected Rapid-Commit option\n"); @@ -670,11 +686,8 @@ static void dhcpv6_recv_information_request(struct dhcpv6_packet *req) static void dhcpv6_recv_rebind(struct dhcpv6_packet *req) { - struct dhcpv6_pd *pd = find_pd(req->ses); + struct dhcpv6_pd *pd = req->pd; - if (!pd) - return; - if (!req->clientid) { log_ppp_error("dhcpv6: no Client-ID option\n"); return; @@ -744,18 +757,21 @@ static void dhcpv6_recv_packet(struct dhcpv6_packet *pkt) static int dhcpv6_read(struct triton_md_handler_t *h) { + struct dhcpv6_pd *pd = container_of(h, typeof(*pd), hnd); + struct ap_session *ses = pd->ses; int n; struct sockaddr_in6 addr; socklen_t len = sizeof(addr); struct dhcpv6_packet *pkt; - struct ap_session *ses; + uint8_t *buf = _malloc(BUF_SIZE); while (1) { n = recvfrom(h->fd, buf, BUF_SIZE, 0, &addr, &len); if (n == -1) { if (errno == EAGAIN) - return 0; + break; log_error("dhcpv6: read: %s\n", strerror(errno)); + continue; } if (!IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) @@ -769,45 +785,18 @@ static int dhcpv6_read(struct triton_md_handler_t *h) continue; } - pthread_rwlock_rdlock(&ses_lock); - list_for_each_entry(ses, &ses_list, entry) { - if (ses->state != AP_STATE_ACTIVE) - continue; + pkt->ses = ses; + pkt->pd = pd; + pkt->addr = addr; - if (!ses->ipv6) - continue; - - if (ses->ifindex != addr.sin6_scope_id) - continue; - - if (ses->ipv6->peer_intf_id != *(uint64_t *)(addr.sin6_addr.s6_addr + 8)) - continue; - - pkt->ses = ses; - - triton_context_call(ses->ctrl->ctx, (triton_event_func)dhcpv6_recv_packet, pkt); - break; - } - pthread_rwlock_unlock(&ses_lock); + dhcpv6_recv_packet(pkt); } - return 0; -} + _free(buf); -static void dhcpv6_close(struct triton_context_t *ctx) -{ - triton_md_unregister_handler(&dhcpv6_hnd, 1); - triton_context_unregister(ctx); + return 0; } -static struct triton_md_handler_t dhcpv6_hnd = { - .read = dhcpv6_read, -}; - -static struct triton_context_t dhcpv6_ctx = { - .close = dhcpv6_close, -}; - static void add_dnssl(const char *val) { int n = strlen(val); @@ -951,48 +940,14 @@ static void load_config(void) static void init(void) { - struct sockaddr_in6 addr; - int sock; - int f = 1; - if (!triton_module_loaded("ipv6_nd")) log_warn("dhcpv6: ipv6_nd module is not loaded, you probably get misconfigured network environment\n"); load_config(); - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (!sock) { - log_error("dhcpv6: socket: %s\n", strerror(errno)); - return; - } - - fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); - - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(DHCPV6_SERV_PORT); - - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { - log_error("dhcpv6: bind: %s\n", strerror(errno)); - close(sock); - return; - } - - fcntl(sock, F_SETFL, O_NONBLOCK); - - dhcpv6_hnd.fd = sock; - - buf = malloc(BUF_SIZE); - - triton_context_register(&dhcpv6_ctx, NULL); - triton_md_register_handler(&dhcpv6_ctx, &dhcpv6_hnd); - triton_md_enable_handler(&dhcpv6_hnd, MD_MODE_READ); - triton_context_wakeup(&dhcpv6_ctx); - triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); - triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ppp_started); - triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ev_ppp_finished); + triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ses_started); + triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ev_ses_finished); } DEFINE_INIT(10, init); diff --git a/accel-pppd/ipv6/dhcpv6.h b/accel-pppd/ipv6/dhcpv6.h index 4afb5fa6..82e366e7 100644 --- a/accel-pppd/ipv6/dhcpv6.h +++ b/accel-pppd/ipv6/dhcpv6.h @@ -61,22 +61,19 @@ #define DUID_EN 2 #define DUID_LL 3 -struct dhcpv6_opt_hdr -{ +struct dhcpv6_opt_hdr { uint16_t code; uint16_t len; uint8_t data[0]; } __packed; -struct dhcpv6_msg_hdr -{ +struct dhcpv6_msg_hdr { uint32_t type:8; uint32_t trans_id:24; uint8_t data[0]; } __packed; -struct dhcpv6_duid -{ +struct dhcpv6_duid { uint16_t type; union { struct { @@ -96,56 +93,48 @@ struct dhcpv6_duid } u; } __packed; -struct dhcpv6_opt_clientid -{ +struct dhcpv6_opt_clientid { struct dhcpv6_opt_hdr hdr; struct dhcpv6_duid duid; } __packed; -struct dhcpv6_opt_serverid -{ +struct dhcpv6_opt_serverid { struct dhcpv6_opt_hdr hdr; struct dhcpv6_duid duid; } __packed; -struct dhcpv6_opt_ia_na -{ +struct dhcpv6_opt_ia_na { struct dhcpv6_opt_hdr hdr; uint32_t iaid; uint32_t T1; uint32_t T2; } __packed; -struct dhcpv6_opt_ia_ta -{ +struct dhcpv6_opt_ia_ta { struct dhcpv6_opt_hdr hdr; uint32_t iaid; } __packed; -struct dhcpv6_opt_ia_addr -{ +struct dhcpv6_opt_ia_addr { struct dhcpv6_opt_hdr hdr; struct in6_addr addr; uint32_t pref_lifetime; uint32_t valid_lifetime; } __packed; -struct dhcpv6_opt_oro -{ +struct dhcpv6_opt_oro { struct dhcpv6_opt_hdr hdr; uint16_t opt[0]; } __packed; -struct dhcpv6_opt_status -{ +struct dhcpv6_opt_status { struct dhcpv6_opt_hdr hdr; uint16_t code; char msg[0]; } __packed; -struct dhcpv6_opt_ia_prefix -{ +struct dhcpv6_opt_ia_prefix { struct dhcpv6_opt_hdr hdr; uint32_t pref_lifetime; uint32_t valid_lifetime; @@ -154,8 +143,7 @@ struct dhcpv6_opt_ia_prefix } __packed; -struct dhcpv6_option -{ +struct dhcpv6_option { struct list_head entry; struct dhcpv6_opt_hdr *hdr; @@ -164,10 +152,12 @@ struct dhcpv6_option struct list_head opt_list; }; -struct ppp_t; -struct dhcpv6_packet -{ +struct dhcpv6_pd; + +struct dhcpv6_packet { struct ap_session *ses; + struct dhcpv6_pd *pd; + struct sockaddr_in6 addr; struct dhcpv6_msg_hdr *hdr; struct dhcpv6_opt_clientid *clientid; diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c index 67a4a0ff..669840a3 100644 --- a/accel-pppd/ipv6/nd.c +++ b/accel-pppd/ipv6/nd.c @@ -256,7 +256,6 @@ static int ipv6_nd_start(struct ap_session *ses) { int sock; struct icmp6_filter filter; - struct sockaddr_in6 addr; struct ipv6_mreq mreq; int val; struct ipv6_nd_handler_t *h; @@ -268,17 +267,9 @@ static int ipv6_nd_start(struct ap_session *ses) return -1; } - fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); - - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_addr.s6_addr32[0] = htons(0xfe80); - *(uint64_t *)(addr.sin6_addr.s6_addr + 8) = ses->ipv6->intf_id; - addr.sin6_scope_id = ses->ifindex; - - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { - close(sock); - return 1; + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) { + log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno)); + goto out_err; } val = 2; @@ -322,6 +313,7 @@ static int ipv6_nd_start(struct ap_session *ses) goto out_err; } + fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); fcntl(sock, F_SETFL, O_NONBLOCK); h = _malloc(sizeof(*h)); @@ -358,19 +350,19 @@ static struct ipv6_nd_handler_t *find_pd(struct ap_session *ses) return NULL; } -static void ipv6_nd_start_later(struct ap_session *ses) -{ - while (ipv6_nd_start(ses) == 1) - sched_yield(); -} - static void ev_ses_started(struct ap_session *ses) { + struct ipv6db_addr_t *a; + if (!ses->ipv6) return; - if (ipv6_nd_start(ses) == 1) - triton_context_call(triton_context_self(), (triton_event_func)ipv6_nd_start_later, ses); + list_for_each_entry(a, &ses->ipv6->addr_list, entry) { + if (a->prefix_len == 64) { + ipv6_nd_start(ses); + break; + } + } } static void ev_ses_finishing(struct ap_session *ses) diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c index 5816e509..fc4cae8a 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -382,11 +382,12 @@ void rad_acct_stop(struct radius_pd_t *rpd) if (!rpd->acct_req || !rpd->acct_req->serv) return; - if (rpd->acct_interim_timer.tpd) { + if (rpd->acct_interim_timer.tpd) triton_timer_del(&rpd->acct_interim_timer); - } - if (rpd->acct_req) { + if (rpd->acct_req->timeout.tpd) + rad_server_req_exit(rpd->acct_req); + if (rpd->acct_req->hnd.tpd) triton_md_unregister_handler(&rpd->acct_req->hnd, 0); @@ -496,6 +497,5 @@ out: rad_req_free(rpd->acct_req); rpd->acct_req = NULL; - } } diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c index 3d01057a..0910314a 100644 --- a/accel-pppd/radius/serv.c +++ b/accel-pppd/radius/serv.c @@ -138,6 +138,7 @@ int rad_server_req_enter(struct rad_req_t *req) } req->serv->req_cnt++; + log_ppp_debug("radius(%i): req_enter %i\n", req->serv->id, req->serv->req_cnt); pthread_mutex_unlock(&req->serv->lock); return 0; @@ -152,6 +153,7 @@ void rad_server_req_exit(struct rad_req_t *req) pthread_mutex_lock(&req->serv->lock); req->serv->req_cnt--; + log_ppp_debug("radius(%i): req_exit %i\n", req->serv->id, req->serv->req_cnt); assert(req->serv->req_cnt >= 0); if (req->serv->req_cnt < req->serv->req_limit && !list_empty(&req->serv->req_queue)) { r = list_entry(req->serv->req_queue.next, typeof(*r), entry); |