summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/accel-ppp.conf2
-rw-r--r--accel-pppd/cli/show_sessions.c6
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c94
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.h1
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c20
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c2
-rw-r--r--accel-pppd/ctrl/sstp/sstp.c6
-rw-r--r--accel-pppd/iprange.c159
-rw-r--r--accel-pppd/libnetlink/iputils.c29
-rw-r--r--accel-pppd/libnetlink/iputils.h2
-rw-r--r--accel-pppd/radius/radius.c2
-rw-r--r--accel-pppd/shaper/shaper.c47
-rw-r--r--accel-pppd/utils.c132
-rw-r--r--accel-pppd/utils.h7
-rw-r--r--accel-pppd/vlan-mon/vlan_mon.c2
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);