diff options
-rw-r--r-- | accel-pppd/accel-ppp.conf | 2 | ||||
-rw-r--r-- | accel-pppd/cli/show_sessions.c | 6 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/dhcpv4.c | 94 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/dhcpv4.h | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 20 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 2 | ||||
-rw-r--r-- | accel-pppd/ctrl/sstp/sstp.c | 6 | ||||
-rw-r--r-- | accel-pppd/iprange.c | 159 | ||||
-rw-r--r-- | accel-pppd/libnetlink/iputils.c | 29 | ||||
-rw-r--r-- | accel-pppd/libnetlink/iputils.h | 2 | ||||
-rw-r--r-- | accel-pppd/radius/radius.c | 2 | ||||
-rw-r--r-- | accel-pppd/shaper/shaper.c | 47 | ||||
-rw-r--r-- | accel-pppd/utils.c | 132 | ||||
-rw-r--r-- | accel-pppd/utils.h | 7 | ||||
-rw-r--r-- | accel-pppd/vlan-mon/vlan_mon.c | 2 |
15 files changed, 328 insertions, 183 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index f28a3aa7..929402b0 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -142,7 +142,7 @@ shared=0 ifcfg=1 mode=L2 start=dhcpv4 -#start=UP +#start=up #ip-unnumbered=1 #proxy-arp=0 #nat=0 diff --git a/accel-pppd/cli/show_sessions.c b/accel-pppd/cli/show_sessions.c index 0ea3c94e..10e16b13 100644 --- a/accel-pppd/cli/show_sessions.c +++ b/accel-pppd/cli/show_sessions.c @@ -475,7 +475,7 @@ static void print_uptime(struct ap_session *ses, char *buf) { time_t uptime; int day,hour,min,sec; - char time_str[14]; + char time_str[24]; if (ses->stop_time) uptime = ses->stop_time - ses->start_time; @@ -489,9 +489,9 @@ static void print_uptime(struct ap_session *ses, char *buf) min = uptime / 60; sec = uptime % 60; if (day) - snprintf(time_str, 13, "%i.%02i:%02i:%02i", day, hour, min, sec); + snprintf(time_str, sizeof(time_str), "%i.%02i:%02i:%02i", day, hour, min, sec); else - snprintf(time_str, 13, "%02i:%02i:%02i", hour, min, sec); + snprintf(time_str, sizeof(time_str), "%02i:%02i:%02i", hour, min, sec); sprintf(buf, "%s", time_str); } diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c index 8a395ea8..9427e142 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4.c @@ -38,6 +38,8 @@ struct dhcpv4_relay_ctx { static int conf_verbose; static in_addr_t conf_dns1; static in_addr_t conf_dns2; +static in_addr_t conf_wins1; +static in_addr_t conf_wins2; static mempool_t pack_pool; static mempool_t opt_pool; @@ -693,13 +695,11 @@ static inline int dhcpv4_packet_add_opt_u32(struct dhcpv4_packet *pack, int type int dhcpv4_send_reply(int msg_type, struct dhcpv4_serv *serv, struct dhcpv4_packet *req, uint32_t yiaddr, uint32_t siaddr, uint32_t router, uint32_t mask, int lease_time, int renew_time, struct dhcpv4_packet *relay) { struct dhcpv4_packet *pack; - int val, r; - struct dns { - in_addr_t dns1; - in_addr_t dns2; - } dns; - int dns_avail = 0; struct dhcpv4_option *opt; + in_addr_t addr[2]; + int dns_avail = 0; + int wins_avail = 0; + int val, r; pack = dhcpv4_packet_alloc(); if (!pack) { @@ -743,23 +743,31 @@ int dhcpv4_send_reply(int msg_type, struct dhcpv4_serv *serv, struct dhcpv4_pack list_for_each_entry(opt, &relay->options, entry) { if (opt->type == 53 || opt->type == 54 || opt->type == 51 || opt->type == 58 || opt->type == 1 || (opt->type == 3 && router)) continue; - if (opt->type == 6) + else if (opt->type == 6) dns_avail = 1; + else if (opt->type == 44) + wins_avail = 1; if (dhcpv4_packet_add_opt(pack, opt->type, opt->data, opt->len)) goto out_err; } } if (!dns_avail) { - if (conf_dns1 && conf_dns2) { - dns.dns1 = conf_dns1; - dns.dns2 = conf_dns2; - if (dhcpv4_packet_add_opt(pack, 6, &dns, 8)) - goto out_err; - } else if (conf_dns1) { - if (dhcpv4_packet_add_opt(pack, 6, &conf_dns1, 4)) - goto out_err; - } + if (conf_dns1) + addr[dns_avail++] = conf_dns1; + if (conf_dns2) + addr[dns_avail++] = conf_dns2; + if (dns_avail && dhcpv4_packet_add_opt(pack, 6, addr, dns_avail * sizeof(addr[0]))) + goto out_err; + } + + if (!wins_avail) { + if (conf_wins1) + addr[wins_avail++] = conf_wins1; + if (conf_wins2) + addr[wins_avail++] = conf_wins2; + if (wins_avail && dhcpv4_packet_add_opt(pack, 44, addr, wins_avail * sizeof(addr[0]))) + goto out_err; } *pack->ptr++ = 255; @@ -1146,8 +1154,9 @@ struct dhcpv4_packet *dhcpv4_clone_radius(struct rad_packet_t *rad) { struct dhcpv4_packet *pkt = dhcpv4_packet_alloc(); uint8_t *ptr, *endptr; - struct dhcpv4_option *opt; + struct dhcpv4_option *opt, *next; struct rad_attr_t *attr; + struct list_head *list; if (!pkt) return NULL; @@ -1166,20 +1175,57 @@ struct dhcpv4_packet *dhcpv4_clone_radius(struct rad_packet_t *rad) log_emerg("out of memory\n"); goto out; } + memset(opt, 0, sizeof(*opt)); + INIT_LIST_HEAD(&opt->list); opt->type = attr->attr->id; opt->len = attr->len; - opt->data = ptr; - memcpy(ptr, attr->raw, attr->len); + opt->data = attr->raw; ptr += attr->len; - list_add_tail(&opt->entry, &pkt->options); + list = &pkt->options; + if (attr->attr->array) { + list_for_each_entry(next, &pkt->options, entry) { + if (next->type == opt->type) { + list = &next->list; + break; + } + } + } + + list_add_tail(&opt->entry, list); + } + } + + ptr = pkt->data; + + list_for_each_entry(opt, &pkt->options, entry) { + memcpy(ptr, opt->data, opt->len); + opt->data = ptr; + ptr += opt->len; + + while (!list_empty(&opt->list)) { + next = list_entry(opt->list.next, typeof(*next), entry); + memcpy(ptr, next->data, next->len); + opt->len += next->len; + ptr += next->len; + + list_del(&next->entry); + mempool_free(next); } } return pkt; out: + list_for_each_entry(opt, &pkt->options, entry) { + while (!list_empty(&opt->list)) { + next = list_entry(opt->list.next, typeof(*next), entry); + list_del(&next->entry); + mempool_free(next); + } + } + dhcpv4_packet_free(pkt); return NULL; } @@ -1199,6 +1245,14 @@ static void load_config() opt = conf_get_opt("dns", "dns2"); if (opt) conf_dns2 = inet_addr(opt); + + opt = conf_get_opt("wins", "wins1"); + if (opt) + conf_wins1 = inet_addr(opt); + + opt = conf_get_opt("wins", "wins2"); + if (opt) + conf_wins2 = inet_addr(opt); } static void init() diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.h b/accel-pppd/ctrl/ipoe/dhcpv4.h index ebb67cfb..3e90cc34 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.h +++ b/accel-pppd/ctrl/ipoe/dhcpv4.h @@ -54,6 +54,7 @@ struct dhcpv4_hdr { struct dhcpv4_option { struct list_head entry; + struct list_head list; uint8_t type; uint8_t len; uint8_t *data; diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index ed79b656..b8082a64 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -981,9 +981,9 @@ static void __ipoe_session_activate(struct ipoe_session *ses) ap_session_activate(&ses->ses); if (ses->ifindex == -1 && !serv->opt_ifcfg) { - if (serv->opt_ip_unnumbered == 0) + if (!serv->opt_ip_unnumbered) iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); - else if (!serv->opt_ifcfg) + else iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); } @@ -1166,10 +1166,10 @@ static void ipoe_session_finished(struct ap_session *s) ipoe_nl_delete(ses->ifindex); } else if (ses->started) { if (!serv->opt_ifcfg) { - if (serv->opt_ip_unnumbered) - iproute_del(serv->ifindex, ses->yiaddr, conf_proto, 32, 0); + if (!serv->opt_ip_unnumbered) + iproute_del(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); else - iproute_del(serv->ifindex, ses->yiaddr, conf_proto, ses->mask, 0); + iproute_del(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); } } @@ -1514,7 +1514,7 @@ static void ipoe_serv_disc_timer(struct triton_timer_t *t) { struct ipoe_serv *serv = container_of(t, typeof(*serv), disc_timer); struct timespec ts; - int delay, delay1 = INT_MAX, delay2 = INT_MAX, offer_delay; + int delay, delay1 = INT_MAX, delay2 = INT_MAX, offer_delay = 0; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -2910,15 +2910,15 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int } } - if (!opt_arp && opt_up && opt_mode == MODE_L2) - opt_arp = 1; - if (!opt_up && !opt_dhcpv4 && !opt_auto) { opt_up = conf_up; opt_dhcpv4 = conf_dhcpv4; opt_auto = conf_auto; } + if (!opt_arp && opt_up && opt_mode == MODE_L2) + opt_arp = 1; + opt_auto &= !opt_shared; if (opt_relay && !opt_giaddr && opt_dhcpv4) { @@ -3846,6 +3846,8 @@ static void load_config(void) conf_up = 1; else if (!strcmp(opt1->val, "auto")) conf_auto = 1; + else + log_error("ipoe: failed to parse 'start=%s'\n", opt1->val); } if (!conf_dhcpv4 && !conf_up) diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index 4331e804..e42bf34c 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -626,7 +626,7 @@ static void init(void) { int mcg_id; - if (system("modprobe -q ipoe")) + if (access("/sys/module/ipoe", F_OK) && system("modprobe -q ipoe")) log_warn("failed to load ipoe module\n"); mcg_id = genl_resolve_mcg(IPOE_GENL_NAME, IPOE_GENL_MCG_PKT, &ipoe_genl_id); diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 3b65103a..0e991bc0 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -667,7 +667,7 @@ static int proxy_parse_v2(struct buffer_t *buf, struct sockaddr_t *peer, struct case PROXY2_PROXY: switch (hdr->fam >> 4) { case PROXY2_AF_INET: - if (n < sizeof(hdr) + sizeof(hdr->ipv4_addr)) + if (n < sizeof(*hdr) + sizeof(hdr->ipv4_addr)) goto error; peer->len = addr->len = sizeof(addr->u.sin); peer->u.sin.sin_family = addr->u.sin.sin_family = AF_INET; @@ -677,7 +677,7 @@ static int proxy_parse_v2(struct buffer_t *buf, struct sockaddr_t *peer, struct addr->u.sin.sin_port = hdr->ipv4_addr.dst_port; break; case PROXY2_AF_INET6: - if (n < sizeof(hdr) + sizeof(hdr->ipv6_addr)) + if (n < sizeof(*hdr) + sizeof(hdr->ipv6_addr)) goto error; peer->len = addr->len = sizeof(addr->u.sin6); peer->u.sin6.sin6_family = addr->u.sin6.sin6_family = AF_INET6; @@ -687,7 +687,7 @@ static int proxy_parse_v2(struct buffer_t *buf, struct sockaddr_t *peer, struct addr->u.sin6.sin6_port = hdr->ipv6_addr.dst_port; break; case PROXY2_AF_UNIX: - if (n < sizeof(hdr) + sizeof(hdr->unix_addr)) + if (n < sizeof(*hdr) + sizeof(hdr->unix_addr)) goto error; peer->len = addr->len = sizeof(addr->u.sun); peer->u.sun.sun_family = addr->u.sun.sun_family = AF_UNIX; diff --git a/accel-pppd/iprange.c b/accel-pppd/iprange.c index f7b77a27..58321bd3 100644 --- a/accel-pppd/iprange.c +++ b/accel-pppd/iprange.c @@ -29,12 +29,6 @@ static pthread_mutex_t iprange_lock = PTHREAD_MUTEX_INITIALIZER; static bool conf_disable = false; static LIST_HEAD(client_ranges); -/* Maximum IPv4 address length with CIDR notation but no extra 0, - * e.g. "0xff.0xff.0xff.0xff/32". - */ -#define CIDR_MAXLEN 22 - - static void free_ranges(struct list_head *head) { struct iprange_t *range; @@ -46,116 +40,89 @@ static void free_ranges(struct list_head *head) } } +/* Parse a [client-ip-iprange] configuration entry. + * Ranges can be defined in CIDR notation ("192.0.2.0/24") or by specifying an + * upper bound for the last IPv4 byte, after a '-' character ("192.0.2.0-255"). + * For simplicity, only mention the CIDR notation in error messages. + */ static int parse_iprange(const char *str, struct iprange_t **range) { - char ipstr[CIDR_MAXLEN + 1] = { 0 }; - struct iprange_t *_range; - struct in_addr addr; - const char *errmsg; - char *suffix_str; - uint32_t ipmin; - uint32_t ipmax; - bool is_cidr; - - /* Extra spaces and comments must have already been removed */ - if (strpbrk(str, " \t#")) { - log_error("iprange: impossible to parse range \"%s\":" - " invalid space or comment character found\n", - str); - return -1; - } + struct iprange_t *new_range; + struct in_addr base_addr; + const char *ptr; + uint32_t ip_min; + uint32_t ip_max; + uint8_t suffix; + size_t len; if (!strcmp(str, "disable")) goto disable; - strncpy(ipstr, str, CIDR_MAXLEN + 1); - if (ipstr[CIDR_MAXLEN] != '\0') { - log_error("iprange: impossible to parse range \"%s\":" - " line too long\n", - str); - return -1; - } - - suffix_str = strpbrk(ipstr, "-/"); - if (!suffix_str) { - log_error("iprange: impossible to parse range \"%s\":" - " unrecognised range format\n", - str); - return -1; - } - - is_cidr = *suffix_str == '/'; - *suffix_str = '\0'; - ++suffix_str; - - if (u_parse_ip4addr(ipstr, &addr, &errmsg)) { - log_error("iprange: impossible to parse range \"%s\":" - " invalid IPv4 address \"%s\"\n", - str, ipstr); - return -1; - } - ipmin = ntohl(addr.s_addr); + ptr = str; - - /* If is_cidr is set, range is given with CIDR notation, - * e.g. "192.0.2.0/24". - * If unset, range is an IP address where the last octet is replaced by - * an octet range, e.g. "192.0.2.0-255". - */ - if (is_cidr) { - long int prefix_len; + /* Try IPv4 CIDR notation first */ + len = u_parse_ip4cidr(ptr, &base_addr, &suffix); + if (len) { + uint32_t addr_hbo; uint32_t mask; - if (u_readlong(&prefix_len, suffix_str, 0, 32)) { - log_error("iprange: impossible to parse range \"%s\":" - " invalid CIDR prefix length \"/%s\"\n", - str, suffix_str); - return -1; - } + /* Cast to uint64_t to avoid undefined 32 bits shift on 32 bits + * integer if 'suffix' is 0. + */ + mask = (uint64_t)0xffffffff << (32 - suffix); + addr_hbo = ntohl(base_addr.s_addr); + ip_min = addr_hbo & mask; + ip_max = addr_hbo | ~mask; + + if (ip_min != addr_hbo) { + struct in_addr min_addr = { .s_addr = htonl(ip_min) }; + char ipbuf[INET_ADDRSTRLEN]; - /* Interpret /0 as disable request */ - if (prefix_len == 0) { - if (ipmin != INADDR_ANY) - log_warn("iprange: %s is equivalent to 0.0.0.0/0 and disables the iprange module\n", - str); - goto disable; + log_warn("iprange: network %s is equivalent to %s/%hhu\n", + str, u_ip4str(&min_addr, ipbuf), suffix); } + goto addrange; + } - mask = INADDR_BROADCAST << (32 - prefix_len); - if (ipmin != (ipmin & mask)) { - char buf[INET_ADDRSTRLEN] = { 0 }; + /* Not an IPv4 CIDR, try the IPv4 range notation */ + len = u_parse_ip4range(ptr, &base_addr, &suffix); + if (len) { + ip_min = ntohl(base_addr.s_addr); + ip_max = (ip_min & 0xffffff00) | suffix; + goto addrange; + } - ipmin &= mask; - addr.s_addr = htonl(ipmin); - log_warn("iprange: first IP of range %s will be %s\n", - str, inet_ntop(AF_INET, &addr, buf, - sizeof(buf))); - } + log_error("iprange: parsing range \"%s\" failed:" + " expecting an IPv4 network prefix in CIDR notation\n", + str); - ipmax = ipmin | ~mask; - } else { - long int max; + return -1; - if (u_readlong(&max, suffix_str, ipmin & 0xff, 255)) { - log_error("iprange: impossible to parse range \"%s\":" - " invalid upper bound \"-%s\"\n", - str, suffix_str); - return -1; - } +addrange: + ptr += len; - ipmax = (ipmin & 0xffffff00) | max; + if (!u_parse_endstr(ptr)) { + log_error("iprange: parsing range \"%s\" failed:" + " unexpected data at \"%s\"\n", + str, ptr); + return -1; } - _range = _malloc(sizeof(*_range)); - if (!_range) { - log_error("iprange: impossible to allocate range \"%s\":" - " memory allocation failed\n", str); + if (ip_min == INADDR_ANY && ip_max == INADDR_BROADCAST) + goto disable; + + new_range = _malloc(sizeof(*new_range)); + if (!new_range) { + log_error("iprange: impossible to load range \"%s\":" + " memory allocation failed\n", + str); return -1; } - _range->begin = ipmin; - _range->end = ipmax; - *range = _range; + new_range->begin = ip_min; + new_range->end = ip_max; + + *range = new_range; return 0; @@ -176,7 +143,7 @@ static bool load_ranges(struct list_head *list, const char *conf_sect) list_for_each_entry(opt, &s->items, entry) { /* Ignore parsing errors, parse_iprange() already logs suitable - * error message. + * error messages. */ if (parse_iprange(opt->name, &r) < 0) continue; diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c index 343088f3..a1ededbf 100644 --- a/accel-pppd/libnetlink/iputils.c +++ b/accel-pppd/libnetlink/iputils.c @@ -169,7 +169,7 @@ int __export iplink_set_mtu(int ifindex, int mtu) memset(&req, 0, sizeof(req) - 1024); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_SETLINK; req.i.ifi_family = AF_UNSPEC; req.i.ifi_index = ifindex; @@ -200,7 +200,7 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid) memset(&req, 0, sizeof(req) - 4096); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL; + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWLINK; req.i.ifi_family = AF_UNSPEC; @@ -243,7 +243,7 @@ int __export iplink_vlan_del(int ifindex) memset(&req, 0, sizeof(req) - 4096); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELLINK; req.i.ifi_family = AF_UNSPEC; req.i.ifi_index = ifindex; @@ -477,7 +477,7 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET; req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = ifindex ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; @@ -500,7 +500,7 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw return r; } -int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask, uint32_t prio) +int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio) { struct ipaddr_req { struct nlmsghdr n; @@ -516,21 +516,24 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask, uint32 memset(&req, 0, sizeof(req) - 4096); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET; req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = ifindex ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; - addattr32(&req.n, sizeof(req), RTA_DST, dst); - if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); + if (src) + addattr32(&req.n, sizeof(req), RTA_PREFSRC, src); + if (gw) + addattr32(&req.n, sizeof(req), RTA_GATEWAY, gw); if (prio) addattr32(&req.n, sizeof(req), RTA_PRIORITY, prio); + addattr32(&req.n, sizeof(req), RTA_DST, dst); if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) r = -1; @@ -560,7 +563,7 @@ int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET6; req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = (pref_len == 128) ? RT_SCOPE_HOST : RT_SCOPE_LINK; + req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; @@ -597,11 +600,11 @@ int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, memset(&req, 0, sizeof(req) - 4096); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET6; req.i.rtm_table = RT_TABLE_MAIN; - req.i.rtm_scope = (pref_len == 128) ? RT_SCOPE_HOST : RT_SCOPE_LINK; + req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; @@ -705,7 +708,7 @@ int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len) memset(&req, 0, sizeof(req) - 4096); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELADDR; req.i.ifa_family = AF_INET6; req.i.ifa_index = ifindex; diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h index 15104b16..78224745 100644 --- a/accel-pppd/libnetlink/iputils.h +++ b/accel-pppd/libnetlink/iputils.h @@ -21,7 +21,7 @@ int ipaddr_del(int ifindex, in_addr_t addr, int mask); int ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer); int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); -int iproute_del(int ifindex, in_addr_t dst, int proto, int mask, uint32_t prio); +int iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); in_addr_t iproute_get(in_addr_t dst, in_addr_t *gw); int ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio); diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index 062e3b72..d910c9ce 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -628,7 +628,7 @@ static void ses_finishing(struct ap_session *ses) for (fr = rpd->fr; fr; fr = fr->next) { if (fr->gw) - iproute_del(0, fr->dst, 3, fr->mask, fr->prio); + iproute_del(0, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio); } if (rpd->acct_started || rpd->acct_req) diff --git a/accel-pppd/shaper/shaper.c b/accel-pppd/shaper/shaper.c index 0a1e5f87..304a129e 100644 --- a/accel-pppd/shaper/shaper.c +++ b/accel-pppd/shaper/shaper.c @@ -89,6 +89,7 @@ struct time_range_pd_t { int down_burst; int up_speed; int up_burst; + int act; }; struct time_range_t { @@ -277,15 +278,20 @@ static struct time_range_pd_t *get_tr_pd(struct shaper_pd_t *pd, int id) struct time_range_pd_t *tr_pd; list_for_each_entry(tr_pd, &pd->tr_list, entry) { - if (tr_pd->id == id) + if (tr_pd->id == id) { + tr_pd->act = 1; + if (id == time_range_id) + pd->cur_tr = tr_pd; return tr_pd; + } } tr_pd = _malloc(sizeof(*tr_pd)); memset(tr_pd, 0, sizeof(*tr_pd)); tr_pd->id = id; + tr_pd->act = 1; - if (id == time_range_id || id == 0) + if (id == time_range_id) pd->cur_tr = tr_pd; list_add_tail(&tr_pd->entry, &pd->tr_list); @@ -304,6 +310,20 @@ static void clear_tr_pd(struct shaper_pd_t *pd) } } +static void clear_old_tr_pd(struct shaper_pd_t *pd) +{ + struct time_range_pd_t *tr_pd; + struct list_head *pos, *n; + + list_for_each_safe(pos, n, &pd->tr_list) { + tr_pd = list_entry(pos, typeof(*tr_pd), entry); + if (!tr_pd->act) { + list_del(&tr_pd->entry); + _free(tr_pd); + } + } +} + #ifdef RADIUS static void parse_attr(struct rad_attr_t *attr, int dir, int *speed, int *burst, int *tr_id) { @@ -313,13 +333,19 @@ static void parse_attr(struct rad_attr_t *attr, int dir, int *speed, int *burst, *speed = conf_multiplier * attr->val.integer; } -static void check_radius_attrs(struct shaper_pd_t *pd, struct rad_packet_t *pack) +static int check_radius_attrs(struct shaper_pd_t *pd, struct rad_packet_t *pack) { struct rad_attr_t *attr; int down_speed, down_burst; int up_speed, up_burst; int tr_id; struct time_range_pd_t *tr_pd; + int r = 0; + + list_for_each_entry(tr_pd, &pd->tr_list, entry) + tr_pd->act = 0; + + pd->cur_tr = NULL; list_for_each_entry(attr, &pack->attrs, entry) { if (attr->vendor && attr->vendor->id != conf_vendor) @@ -328,6 +354,7 @@ static void check_radius_attrs(struct shaper_pd_t *pd, struct rad_packet_t *pack continue; if (attr->attr->id != conf_attr_down && attr->attr->id != conf_attr_up) continue; + r = 1; tr_id = 0; down_speed = 0; down_burst = 0; @@ -347,6 +374,16 @@ static void check_radius_attrs(struct shaper_pd_t *pd, struct rad_packet_t *pack if (up_burst) tr_pd->up_burst = up_burst; } + + if (!r) + return 0; + + if (!pd->cur_tr) + pd->cur_tr = get_tr_pd(pd, 0); + + clear_old_tr_pd(pd); + + return 1; } static void ev_radius_access_accept(struct ev_radius_t *ev) @@ -368,8 +405,8 @@ static void ev_radius_coa(struct ev_radius_t *ev) return; } - clear_tr_pd(pd); - check_radius_attrs(pd, ev->request); + if (!check_radius_attrs(pd, ev->request)) + return; if (pd->temp_down_speed || pd->temp_up_speed) return; diff --git a/accel-pppd/utils.c b/accel-pppd/utils.c index 544c59e7..018b6efa 100644 --- a/accel-pppd/utils.c +++ b/accel-pppd/utils.c @@ -1,7 +1,6 @@ #include <arpa/inet.h> #include <ctype.h> #include <errno.h> -#include <netdb.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -31,6 +30,21 @@ char __export *u_ip6str(const struct in6_addr *addr, char *buf) return buf; } +/* Convenient wrapper around inet_ntop() to print IPv4 addresses. + * It stores a string representation of addr into buf, which must be at + * least INET_ADDRSTRLEN bytes long. + * + * Returns buf, which is guaranteed to contain a valid string even if an error + * occured. + */ +char __export *u_ip4str(const struct in_addr *addr, char *buf) +{ + if (!inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN)) + snprintf(buf, INET_ADDRSTRLEN, "< ERROR! >"); + + return buf; +} + void __export u_inet_ntoa(in_addr_t addr, char *str) { addr = ntohl(addr); @@ -70,7 +84,7 @@ size_t __export u_parse_spaces(const char *str) * Reads a sequence of space characters, followed by the end-of-string * mark ('\0'). * Returns the number of characters parsed on success (that is, the number of - * space characters plus one for '\0'). Beware that 'str + u_parse_eos(str)' + * space characters plus one for '\0'). Beware that 'str + u_parse_endstr(str)' * points to the next byte after the end of the string in this case. * Returns 0 if parsing fails (that is, if unexpected characers are found * before the end of the string). @@ -167,31 +181,6 @@ size_t __export u_parse_u32(const char *str, uint32_t *val) return endptr - str; } -int __export u_parse_ip4addr(const char *src, struct in_addr *addr, - const char **err_msg) -{ - struct addrinfo hint = { - .ai_flags = AI_NUMERICHOST, - .ai_family = AF_INET, - .ai_socktype = 0, - .ai_protocol = 0, - }; - struct addrinfo *ainfo; - int err; - - err = getaddrinfo(src, NULL, &hint, &ainfo); - if (err) { - *err_msg = gai_strerror(err); - return err; - } - - *addr = ((struct sockaddr_in *)ainfo->ai_addr)->sin_addr; - - freeaddrinfo(ainfo); - - return 0; -} - /* Parse an IPv6 address (for example "2001:db8::1"). * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv6 * address. @@ -214,6 +203,31 @@ size_t __export u_parse_ip6addr(const char *str, struct in6_addr *addr) return len; } +/* Parse an IPv4 address in dotted-decimal format (for example "198.51.100.1"). + * Other formats (hex "0xc6.0x33.0x64.0x1", octal "0306.063.0144.01", mixed + * "0xc6.51.0144.1", non dotted-quad "198.51.25601"...) are rejected. + * + * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 + * address. + */ +size_t __export u_parse_ip4addr(const char *str, struct in_addr *addr) +{ + char buf[INET_ADDRSTRLEN]; + size_t len; + + len = strspn(str, ".0123456789"); + if (!len || len >= sizeof(buf)) + return 0; + + memcpy(buf, str, len); + buf[len] = '\0'; + + if (inet_pton(AF_INET, buf, addr) != 1) + return 0; + + return len; +} + /* Parse an IPv6 network prefix in CIDR notation (for example "2001:db8::/32"). * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv6 * network prefix. @@ -243,6 +257,70 @@ size_t __export u_parse_ip6cidr(const char *str, struct in6_addr *netp, uint8_t return ptr - str; } +/* Parse an IPv4 network prefix in CIDR notation (for example "192.0.2.0/24"). + * The IP address must be in dotted-decimal format. + * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 + * network prefix. + */ +size_t __export u_parse_ip4cidr(const char *str, struct in_addr *netp, uint8_t *plen) +{ + const char *ptr = str; + size_t len; + + len = u_parse_ip4addr(ptr, netp); + if (!len) + return 0; + + ptr += len; + if (*ptr != '/') + return 0; + + len = u_parse_u8(++ptr, plen); + if (!len) + return 0; + + if (*plen > 32) + return 0; + + ptr += len; + + return ptr - str; +} + +/* Parse an IPv4 address range (for example "192.0.2.0-255"). + * The IP address must be in dotted-decimal format. The number following '-' + * is the upper bound of the address' least significant byte (the lower bound + * is given by the address itself). The upper bound must be bigger or equal + * than the lower bound. + * + * Returns the number of bytes parsed, or 0 if str doesn't start with an IPv4 + * address range. + */ +size_t __export u_parse_ip4range(const char *str, struct in_addr *base_ip, uint8_t *max) +{ + const char *ptr = str; + size_t len; + + len = u_parse_ip4addr(ptr, base_ip); + if (!len) + return 0; + + ptr += len; + if (*ptr != '-') + return 0; + + len = u_parse_u8(++ptr, max); + if (!len) + return 0; + + if (*max < (ntohl(base_ip->s_addr) & 0xff)) + return 0; + + ptr += len; + + return ptr - str; +} + int __export u_randbuf(void *buf, size_t buf_len, int *err) { uint8_t *u8buf = buf; diff --git a/accel-pppd/utils.h b/accel-pppd/utils.h index d3e06083..06859a6b 100644 --- a/accel-pppd/utils.h +++ b/accel-pppd/utils.h @@ -5,6 +5,7 @@ #include <stdint.h> char *u_ip6str(const struct in6_addr *addr, char *buf); +char *u_ip4str(const struct in_addr *addr, char *buf); void u_inet_ntoa(in_addr_t, char *str); int u_readlong(long int *dst, const char *src, long int min, long int max); @@ -16,10 +17,12 @@ size_t u_parse_u8(const char *str, uint8_t *val); size_t u_parse_u16(const char *str, uint16_t *val); size_t u_parse_u32(const char *str, uint32_t *val); -int u_parse_ip4addr(const char *src, struct in_addr *addr, - const char **err_msg); size_t u_parse_ip6addr(const char *str, struct in6_addr *addr); +size_t u_parse_ip4addr(const char *str, struct in_addr *addr); + size_t u_parse_ip6cidr(const char *str, struct in6_addr *netp, uint8_t *plen); +size_t u_parse_ip4cidr(const char *str, struct in_addr *netp, uint8_t *plen); +size_t u_parse_ip4range(const char *str, struct in_addr *base_ip, uint8_t *max); int u_randbuf(void *buf, size_t buf_len, int *err); diff --git a/accel-pppd/vlan-mon/vlan_mon.c b/accel-pppd/vlan-mon/vlan_mon.c index 2892f4f3..f2109eda 100644 --- a/accel-pppd/vlan-mon/vlan_mon.c +++ b/accel-pppd/vlan-mon/vlan_mon.c @@ -522,7 +522,7 @@ static void init(void) { int mcg_id; - if (system("modprobe -q vlan_mon")) + if (access("/sys/module/vlan_mon", F_OK) && system("modprobe -q vlan_mon")) log_warn("failed to load vlan_mon module\n"); mcg_id = genl_resolve_mcg(VLAN_MON_GENL_NAME, VLAN_MON_GENL_MCG, &vlan_mon_genl_id); |