From 768ad4d4f1930ffe1630e82789cd58191b651a64 Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Thu, 24 Jul 2014 22:11:33 +0400 Subject: radius: exit from active interim request when termination event occures --- accel-pppd/ipv6/dhcpv6.c | 189 ++++++++++++++++++----------------------------- accel-pppd/ipv6/dhcpv6.h | 44 +++++------ accel-pppd/ipv6/nd.c | 32 +++----- 3 files changed, 101 insertions(+), 164 deletions(-) (limited to 'accel-pppd/ipv6') diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index 809496e..67b1b75 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 4afb5fa..82e366e 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 67a4a0f..669840a 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) -- cgit v1.2.3