X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/8f944eeb2197070c98c0e98b92d95cf3d35fdf67..92db0e2617cec9b118708c722c1a9f273001f87d:/l2tpns.c?ds=sidebyside diff --git a/l2tpns.c b/l2tpns.c index 8224275..0721f5c 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,8 +4,6 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $"; - #include #include #include @@ -14,7 +12,6 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp #define SYSLOG_NAMES #include #include -#include #include #include #include @@ -31,7 +28,7 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp #include #include #include -#include +#include #include #include #include @@ -70,7 +67,7 @@ int rand_fd = -1; // Random data source int cluster_sockfd = -1; // Intra-cluster communications socket. int epollfd = -1; // event polling time_t basetime = 0; // base clock -char hostname[1000] = ""; // us. +char hostname[MAXHOSTNAME] = ""; // us. static int tunidx; // ifr_ifindex of tun device int nlseqnum = 0; // netlink sequence number int min_initok_nlseqnum = 0; // minimun seq number for messages after init is ok @@ -160,6 +157,10 @@ config_descriptt config_values[] = { CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT), CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT), CONFIG("ipv6_prefix", ipv6_prefix, IPv6), + CONFIG("cli_bind_address", cli_bind_address, IPv4), + CONFIG("hostname", hostname, STRING), + CONFIG("nexthop_address", nexthop_address, IPv4), + CONFIG("nexthop6_address", nexthop6_address, IPv6), { NULL, 0, 0, 0 }, }; @@ -167,8 +168,6 @@ static char *plugin_functions[] = { NULL, "plugin_pre_auth", "plugin_post_auth", - "plugin_packet_rx", - "plugin_packet_tx", "plugin_timer", "plugin_new_session", "plugin_kill_session", @@ -200,6 +199,8 @@ struct Tstats *_statistics = NULL; struct Tringbuffer *ringbuffer = NULL; #endif +static ssize_t netlink_send(struct nlmsghdr *nh); +static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen); static void cache_ipmap(in_addr_t ip, sessionidt s); static void uncache_ipmap(in_addr_t ip); static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s); @@ -419,43 +420,65 @@ void random_data(uint8_t *buf, int len) // via BGP if enabled, and stuffs it into the // 'sessionbyip' cache. // -// 'ip' and 'mask' must be in _host_ order. +// 'ip' must be in _host_ order. // -static void routeset(sessionidt s, in_addr_t ip, in_addr_t mask, in_addr_t gw, int add) +static void routeset(sessionidt s, in_addr_t ip, int prefixlen, in_addr_t gw, int add) { - struct rtentry r; + struct { + struct nlmsghdr nh; + struct rtmsg rt; + char buf[32]; + } req; int i; + in_addr_t n_ip; + + if (!prefixlen) prefixlen = 32; + + ip &= 0xffffffff << (32 - prefixlen);; // Force the ip to be the first one in the route. + + memset(&req, 0, sizeof(req)); + + if (add) + { + req.nh.nlmsg_type = RTM_NEWROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; + } + else + { + req.nh.nlmsg_type = RTM_DELROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST; + } - if (!mask) mask = 0xffffffff; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)); - ip &= mask; // Force the ip to be the first one in the route. + req.rt.rtm_family = AF_INET; + req.rt.rtm_dst_len = prefixlen; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = 42; + req.rt.rtm_scope = RT_SCOPE_LINK; + req.rt.rtm_type = RTN_UNICAST; - memset(&r, 0, sizeof(r)); - r.rt_dev = config->tundevice; - r.rt_dst.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr) = htonl(ip); - r.rt_gateway.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr) = htonl(gw); - r.rt_genmask.sa_family = AF_INET; - *(uint32_t *) & (((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr) = htonl(mask); - r.rt_flags = (RTF_UP | RTF_STATIC); + netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int)); + n_ip = htonl(ip); + netlink_addattr(&req.nh, RTA_DST, &n_ip, sizeof(n_ip)); if (gw) - r.rt_flags |= RTF_GATEWAY; - else if (mask == 0xffffffff) - r.rt_flags |= RTF_HOST; + { + n_ip = htonl(gw); + netlink_addattr(&req.nh, RTA_GATEWAY, &n_ip, sizeof(n_ip)); + } - LOG(1, s, 0, "Route %s %s/%s%s%s\n", add ? "add" : "del", - fmtaddr(htonl(ip), 0), fmtaddr(htonl(mask), 1), + LOG(1, s, session[s].tunnel, "Route %s %s/%d%s%s\n", add ? "add" : "del", + fmtaddr(htonl(ip), 0), prefixlen, gw ? " via" : "", gw ? fmtaddr(htonl(gw), 2) : ""); - if (ioctl(ifrfd, add ? SIOCADDRT : SIOCDELRT, (void *) &r) < 0) - LOG(0, 0, 0, "routeset() error in ioctl: %s\n", strerror(errno)); + if (netlink_send(&req.nh) < 0) + LOG(0, 0, 0, "routeset() error in sending netlink message: %s\n", strerror(errno)); #ifdef BGP if (add) - bgp_add_route(htonl(ip), htonl(mask)); + bgp_add_route(htonl(ip), prefixlen); else - bgp_del_route(htonl(ip), htonl(mask)); + bgp_del_route(htonl(ip), prefixlen); #endif /* BGP */ // Add/Remove the IPs to the 'sessionbyip' cache. @@ -471,40 +494,68 @@ static void routeset(sessionidt s, in_addr_t ip, in_addr_t mask, in_addr_t gw, i if (!add) // Are we deleting a route? s = 0; // Caching the session as '0' is the same as uncaching. - for (i = ip; (i&mask) == (ip&mask) ; ++i) + for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i) cache_ipmap(i, s); } } void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add) { - struct in6_rtmsg rt; + struct { + struct nlmsghdr nh; + struct rtmsg rt; + char buf[64]; + } req; + int metric; char ipv6addr[INET6_ADDRSTRLEN]; - if (ifr6fd < 0) + if (!config->ipv6_prefix.s6_addr[0]) { LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n"); return; } - memset(&rt, 0, sizeof(rt)); + memset(&req, 0, sizeof(req)); - memcpy(&rt.rtmsg_dst, &ip, sizeof(struct in6_addr)); - rt.rtmsg_dst_len = prefixlen; - rt.rtmsg_metric = 1; - rt.rtmsg_flags = RTF_UP; - rt.rtmsg_ifindex = tunidx; + if (add) + { + req.nh.nlmsg_type = RTM_NEWROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; + } + else + { + req.nh.nlmsg_type = RTM_DELROUTE; + req.nh.nlmsg_flags = NLM_F_REQUEST; + } + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)); + + req.rt.rtm_family = AF_INET6; + req.rt.rtm_dst_len = prefixlen; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = 42; + req.rt.rtm_scope = RT_SCOPE_LINK; + req.rt.rtm_type = RTN_UNICAST; + + netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int)); + netlink_addattr(&req.nh, RTA_DST, &ip, sizeof(ip)); + metric = 1; + netlink_addattr(&req.nh, RTA_METRICS, &metric, sizeof(metric)); - LOG(1, 0, 0, "Route %s %s/%d\n", + LOG(1, s, session[s].tunnel, "Route %s %s/%d\n", add ? "add" : "del", inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN), prefixlen); - if (ioctl(ifr6fd, add ? SIOCADDRT : SIOCDELRT, (void *) &rt) < 0) - LOG(0, 0, 0, "route6set() error in ioctl: %s\n", - strerror(errno)); + if (netlink_send(&req.nh) < 0) + LOG(0, 0, 0, "route6set() error in sending netlink message: %s\n", strerror(errno)); - // FIXME: need to add BGP routing (RFC2858) +#ifdef BGP + if (add) + bgp_add_route6(ip, prefixlen); + else + bgp_del_route6(ip, prefixlen); +#endif /* BGP */ if (s) { @@ -576,6 +627,19 @@ static ssize_t netlink_recv(void *buf, ssize_t len) return recvmsg(nlfd, &msg, 0); } +/* adapted from iproute2 */ +static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + rta = (struct rtattr *)(((void *)nh) + NLMSG_ALIGN(nh->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(len); +} + // messages corresponding to different phases seq number static char *tun_nl_phase_msg[] = { "initialized", @@ -590,7 +654,6 @@ static char *tun_nl_phase_msg[] = { // Set up TUN interface static void inittun(void) { - struct ifinfomsg ifinfo; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); @@ -611,50 +674,16 @@ static void inittun(void) LOG(0, 0, 0, "Can't set tun interface: %s\n", strerror(errno)); exit(1); } - assert(strlen(ifr.ifr_name) < sizeof(config->tundevice)); - strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice) - 1); + assert(strlen(ifr.ifr_name) < sizeof(config->tundevice) - 1); + strncpy(config->tundevice, ifr.ifr_name, sizeof(config->tundevice)); + tunidx = if_nametoindex(config->tundevice); + if (tunidx == 0) { - // get the interface index - struct { - struct nlmsghdr nh; - struct ifinfomsg ifinfo __attribute__ ((aligned(NLMSG_ALIGNTO))); - struct rtattr ifname_rta __attribute__ ((aligned(RTA_ALIGNTO))); - char ifname[IFNAMSIZ]; - } req; - char buf[4096]; - ssize_t len; - struct nlmsghdr *resp_nh; - - req.nh.nlmsg_type = RTM_GETLINK; - req.nh.nlmsg_flags = NLM_F_REQUEST; - - req.ifinfo.ifi_family = AF_UNSPEC; // as the man says - - req.ifname_rta.rta_len = RTA_LENGTH(strlen(config->tundevice)+1); - req.ifname_rta.rta_type = IFLA_IFNAME; - strncpy(req.ifname, config->tundevice, IFNAMSIZ-1); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfo) - + req.ifname_rta.rta_len); - - if(netlink_send(&req.nh) < 0 || (len = netlink_recv(buf, sizeof(buf))) < 0) - { - LOG(0, 0, 0, "Error getting tun ifindex: %s\n", strerror(errno)); - exit(1); - } - - resp_nh = (struct nlmsghdr *)buf; - if (!NLMSG_OK (resp_nh, len)) - { - LOG(0, 0, 0, "Malformed answer getting tun ifindex %ld\n", len); - exit(1); - } - - memcpy(&ifinfo, NLMSG_DATA(resp_nh), sizeof(ifinfo)); - // got index - tunidx = ifinfo.ifi_index; + LOG(0, 0, 0, "Can't get tun interface index\n"); + exit(1); } + { struct { // interface setting @@ -662,136 +691,96 @@ static void inittun(void) union { struct ifinfomsg ifinfo; struct ifaddrmsg ifaddr; - } ifmsg __attribute__ ((aligned(NLMSG_ALIGNTO))); + } ifmsg; char rtdata[32]; // 32 should be enough } req; - struct { - struct rtattr rta; - uint32_t u32 __attribute__ ((aligned(RTA_ALIGNTO)));; - } u32_attr; - struct { - struct rtattr rta; - struct in_addr addr __attribute__ ((aligned(RTA_ALIGNTO)));; - } ipv4_attr; - struct { - struct rtattr rta; - struct in6_addr addr6 __attribute__ ((aligned(RTA_ALIGNTO)));; - } ipv6_attr; - char *buf_ptr; + uint32_t txqlen, mtu; + in_addr_t ip; memset(&req, 0, sizeof(req)); - req.nh.nlmsg_type = RTM_SETLINK; + req.nh.nlmsg_type = RTM_NEWLINK; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifinfo)); - req.ifmsg.ifinfo = ifinfo; + req.ifmsg.ifinfo.ifi_family = AF_UNSPEC; + req.ifmsg.ifinfo.ifi_index = tunidx; req.ifmsg.ifinfo.ifi_flags |= IFF_UP; // set interface up req.ifmsg.ifinfo.ifi_change = IFF_UP; // only change this flag - buf_ptr = NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifinfo); - - u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32)); - u32_attr.rta.rta_type = IFLA_TXQLEN; /* Bump up the qlen to deal with bursts from the network */ - u32_attr.u32 = 1000; - memcpy(buf_ptr, &u32_attr, sizeof(u32_attr)); - - buf_ptr += RTA_ALIGN(u32_attr.rta.rta_len); - - u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32)); - u32_attr.rta.rta_type = IFLA_MTU; + txqlen = 1000; + netlink_addattr(&req.nh, IFLA_TXQLEN, &txqlen, sizeof(txqlen)); /* set MTU to modem MRU */ - u32_attr.u32 = MRU; - memcpy(buf_ptr, &u32_attr, sizeof(u32_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifinfo) - + u32_attr.rta.rta_len * 2); + mtu = MRU; + netlink_addattr(&req.nh, IFLA_MTU, &mtu, sizeof(mtu)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device interface: %s\n", strerror(errno)); - exit(1); - } + goto senderror; memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET; req.ifmsg.ifaddr.ifa_prefixlen = 32; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; - - ipv4_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv4_attr.addr)); - ipv4_attr.rta.rta_type = IFA_LOCAL; - ipv4_attr.addr.s_addr = config->bind_address ? - config->bind_address : 0x01010101; // 1.1.1.1 - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv4_attr, sizeof(ipv4_attr)); + req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE; + req.ifmsg.ifaddr.ifa_index = tunidx; - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv4_attr.rta.rta_len); + if (config->bind_address) + ip = config->bind_address; + else + ip = 0x01010101; // 1.1.1.1 + netlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device IPv4 address: %s\n", strerror(errno)); - exit(1); - } + goto senderror; // Only setup IPv6 on the tun device if we have a configured prefix if (config->ipv6_prefix.s6_addr[0]) { + struct in6_addr ip6; + memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET6; req.ifmsg.ifaddr.ifa_prefixlen = 64; req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_LINK; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; + req.ifmsg.ifaddr.ifa_index = tunidx; - ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6)); - ipv6_attr.rta.rta_type = IFA_LOCAL; // Link local address is FE80::1 - memset(&ipv6_attr.addr6, 0, sizeof(ipv6_attr.addr6)); - ipv6_attr.addr6.s6_addr[0] = 0xFE; - ipv6_attr.addr6.s6_addr[1] = 0x80; - ipv6_attr.addr6.s6_addr[15] = 1; - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv6_attr.rta.rta_len); + memset(&ip6, 0, sizeof(ip6)); + ip6.s6_addr[0] = 0xFE; + ip6.s6_addr[1] = 0x80; + ip6.s6_addr[15] = 1; + netlink_addattr(&req.nh, IFA_LOCAL, &ip6, sizeof(ip6)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device IPv6 LL address: %s\n", strerror(errno)); - exit(1); - } + goto senderror; memset(&req, 0, sizeof(req)); req.nh.nlmsg_type = RTM_NEWADDR; - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); req.ifmsg.ifaddr.ifa_family = AF_INET6; req.ifmsg.ifaddr.ifa_prefixlen = 64; req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE; - req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index; + req.ifmsg.ifaddr.ifa_index = tunidx; - ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6)); - ipv6_attr.rta.rta_type = IFA_LOCAL; // Global address is prefix::1 - ipv6_attr.addr6 = config->ipv6_prefix; - ipv6_attr.addr6.s6_addr[15] = 1; - memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr)); - - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr) - + ipv6_attr.rta.rta_len); + ip6 = config->ipv6_prefix; + ip6.s6_addr[15] = 1; + netlink_addattr(&req.nh, IFA_LOCAL, &ip6, sizeof(ip6)); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error setting up tun device IPv6 global address: %s\n", strerror(errno)); - exit(1); - } + goto senderror; } memset(&req, 0, sizeof(req)); @@ -800,10 +789,7 @@ static void inittun(void) req.nh.nlmsg_len = NLMSG_LENGTH(0); if (netlink_send(&req.nh) < 0) - { - LOG(0, 0, 0, "Error finishing setting up tun device: %s\n", strerror(errno)); - exit(1); - } + goto senderror; // if we get an error for seqnum < min_initok_nlseqnum, // we must exit as initialization went wrong @@ -812,6 +798,12 @@ static void inittun(void) else min_initok_nlseqnum = 3 + 1; // idx + if + addr } + + return; + +senderror: + LOG(0, 0, 0, "Error while setting up tun device: %s\n", strerror(errno)); + exit(1); } // set up UDP ports @@ -1468,75 +1460,76 @@ static void processipout(uint8_t *buf, int len) return; } - // Add on L2TP header - { - bundleidt bid = 0; - if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) - { - bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; - t = session[s].tunnel; - sp = &session[s]; - LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - if(len > MINFRAGLEN) - { - // Partition the packet to "bundle[b].num_of_links" fragments - bundlet *b = &bundle[bid]; - uint32_t num_of_links = b->num_of_links; - uint32_t fraglen = len / num_of_links; - fraglen = (fraglen > session[s].mru ? session[s].mru : fraglen); - uint32_t last_fraglen = fraglen + len % num_of_links; - last_fraglen = (last_fraglen > session[s].mru ? len % num_of_links : last_fraglen); - uint32_t remain = len; - - // send the first packet - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... - // statistics - update_session_out_stat(s, sp, fraglen); - remain -= fraglen; - while (remain > last_fraglen) - { - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; - t = session[s].tunnel; - sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... - update_session_out_stat(s, sp, fraglen); - remain -= fraglen; - } - // send the last fragment - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) + { + // Add on L2TP header + bundleidt bid = session[s].bundle; + bundlet *b = &bundle[bid]; + + b->current_ses = (b->current_ses + 1) % b->num_of_links; + s = b->members[b->current_ses]; + t = session[s].tunnel; + sp = &session[s]; + LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); + if(len > MINFRAGLEN) + { + // Partition the packet to "bundle[b].num_of_links" fragments + uint32_t num_of_links = b->num_of_links; + uint32_t fraglen = len / num_of_links; + fraglen = (fraglen > session[s].mru ? session[s].mru : fraglen); + uint32_t last_fraglen = fraglen + len % num_of_links; + last_fraglen = (last_fraglen > session[s].mru ? len % num_of_links : last_fraglen); + uint32_t remain = len; + + // send the first packet + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + // statistics + update_session_out_stat(s, sp, fraglen); + remain -= fraglen; + while (remain > last_fraglen) + { + b->current_ses = (b->current_ses + 1) % num_of_links; + s = b->members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); - if (!p) return; - tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... - update_session_out_stat(s, sp, remain); - if (remain != last_fraglen) - LOG(3, s, t, "PROCESSIPOUT ERROR REMAIN != LAST_FRAGLEN, %d != %d\n", remain, last_fraglen); - } - else { - // Send it as one frame - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... - LOG(4, s, t, "MPPP: packet sent as one frame\n"); - update_session_out_stat(s, sp, len); - } - } - else - { - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + update_session_out_stat(s, sp, fraglen); + remain -= fraglen; + } + // send the last fragment + b->current_ses = (b->current_ses + 1) % num_of_links; + s = b->members[b->current_ses]; + t = session[s].tunnel; + sp = &session[s]; + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); + if (!p) return; + tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... + update_session_out_stat(s, sp, remain); + if (remain != last_fraglen) + LOG(3, s, t, "PROCESSIPOUT ERROR REMAIN != LAST_FRAGLEN, %d != %d\n", remain, last_fraglen); + } + else { + // Send it as one frame + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: packet sent as one frame\n"); update_session_out_stat(s, sp, len); - } - } + } + } + else + { + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + update_session_out_stat(s, sp, len); + } // Snooping this session, send it to intercept box if (sp->snoop_ip && sp->snoop_port) @@ -1616,7 +1609,10 @@ static void processipv6out(uint8_t * buf, int len) if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1) { bundleidt bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; + bundlet *b = &bundle[bid]; + + b->current_ses = (b->current_ses + 1) % b->num_of_links; + s = b->members[b->current_ses]; LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %u\n", s); } t = session[s].tunnel; @@ -1671,7 +1667,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) { sessiont *sp; tunnelidt t; - in_addr_t ip; uint8_t b[MAXETHER + 20]; @@ -1685,8 +1680,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) buf += 4; len -= 4; - ip = *(in_addr_t *)(buf + 16); - if (!session[s].ip) return; @@ -1719,10 +1712,10 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) { uint16_t l = (m ? 0x8008 : 0x0008); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint16_t *) (c->buf + c->length + 6) = htons(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + c->buf16[c->length/2 + 3] = htons(val); c->length += 8; } @@ -1730,10 +1723,10 @@ static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) { uint16_t l = (m ? 0x800A : 0x000A); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint32_t *) (c->buf + c->length + 6) = htonl(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + *(uint32_t *) &c->buf[c->length + 6] = htonl(val); c->length += 10; } @@ -1741,10 +1734,10 @@ static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, strlen(val)); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, strlen(val)); c->length += 6 + strlen(val); } @@ -1752,10 +1745,10 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + len + 6); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, len); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, len); c->length += 6 + len; } @@ -1772,7 +1765,7 @@ static controlt *controlnew(uint16_t mtype) } assert(c); c->next = 0; - *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver + c->buf16[0] = htons(0xC802); // flags/ver c->length = 12; control16(c, 0, mtype, 1); return c; @@ -1782,26 +1775,26 @@ static controlt *controlnew(uint16_t mtype) // (ZLB send). static void controlnull(tunnelidt t) { - uint8_t buf[12]; + uint16_t buf[6]; if (tunnel[t].controlc) // Messages queued; They will carry the ack. return; - *(uint16_t *) (buf + 0) = htons(0xC802); // flags/ver - *(uint16_t *) (buf + 2) = htons(12); // length - *(uint16_t *) (buf + 4) = htons(tunnel[t].far); // tunnel - *(uint16_t *) (buf + 6) = htons(0); // session - *(uint16_t *) (buf + 8) = htons(tunnel[t].ns); // sequence - *(uint16_t *) (buf + 10) = htons(tunnel[t].nr); // sequence - tunnelsend(buf, 12, t); + buf[0] = htons(0xC802); // flags/ver + buf[1] = htons(12); // length + buf[2] = htons(tunnel[t].far); // tunnel + buf[3] = htons(0); // session + buf[4] = htons(tunnel[t].ns); // sequence + buf[5] = htons(tunnel[t].nr); // sequence + tunnelsend((uint8_t *)buf, 12, t); } // add a control message to a tunnel, and send if within window static void controladd(controlt *c, sessionidt far, tunnelidt t) { - *(uint16_t *) (c->buf + 2) = htons(c->length); // length - *(uint16_t *) (c->buf + 4) = htons(tunnel[t].far); // tunnel - *(uint16_t *) (c->buf + 6) = htons(far); // session - *(uint16_t *) (c->buf + 8) = htons(tunnel[t].ns); // sequence + c->buf16[1] = htons(c->length); // length + c->buf16[2] = htons(tunnel[t].far); // tunnel + c->buf16[3] = htons(far); // session + c->buf16[4] = htons(tunnel[t].ns); // sequence tunnel[t].ns++; // advance sequence // link in message in to queue if (tunnel[t].controlc) @@ -1957,11 +1950,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e int routed = 0; for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++) { - if ((session[s].ip & session[s].route[r].mask) == - (session[s].route[r].ip & session[s].route[r].mask)) + if ((session[s].ip >> (32-session[s].route[r].prefixlen)) == + (session[s].route[r].ip >> (32-session[s].route[r].prefixlen))) routed++; - if (del_routes) routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 0); + if (del_routes) routeset(s, session[s].route[r].ip, session[s].route[r].prefixlen, 0, 0); session[s].route[r].ip = 0; } @@ -1981,11 +1974,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e { // This session was part of a bundle bundle[b].num_of_links--; - LOG(3, s, 0, "MPPP: Dropping member link: %d from bundle %d\n",s,b); + LOG(3, s, session[s].tunnel, "MPPP: Dropping member link: %d from bundle %d\n",s,b); if(bundle[b].num_of_links == 0) { bundleclear(b); - LOG(3, s, 0, "MPPP: Kill bundle: %d (No remaing member links)\n",b); + LOG(3, s, session[s].tunnel, "MPPP: Kill bundle: %d (No remaing member links)\n",b); } else { @@ -2002,7 +1995,7 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e break; } bundle[b].members[mem_num] = bundle[b].members[bundle[b].num_of_links]; - LOG(3, s, 0, "MPPP: Adjusted member links array\n"); + LOG(3, s, session[s].tunnel, "MPPP: Adjusted member links array\n"); } } cluster_send_bundle(b); @@ -2017,10 +2010,10 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e controlt *c = controlnew(14); // sending CDN if (cdn_error) { - uint8_t buf[4]; - *(uint16_t *) buf = htons(cdn_result); - *(uint16_t *) (buf+2) = htons(cdn_error); - controlb(c, 1, buf, 4, 1); + uint16_t buf[2]; + buf[0] = htons(cdn_result); + buf[1] = htons(cdn_error); + controlb(c, 1, (uint8_t *)buf, 4, 1); } else control16(c, 1, cdn_result, 1); @@ -2209,21 +2202,21 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha controlt *c = controlnew(4); // sending StopCCN if (error) { - uint8_t buf[64]; + uint16_t buf[32]; int l = 4; - *(uint16_t *) buf = htons(result); - *(uint16_t *) (buf+2) = htons(error); + buf[0] = htons(result); + buf[1] = htons(error); if (msg) { int m = strlen(msg); if (m + 4 > sizeof(buf)) m = sizeof(buf) - 4; - memcpy(buf+4, msg, m); + memcpy(buf+2, msg, m); l += m; } - controlb(c, 1, buf, l, 1); + controlb(c, 1, (uint8_t *)buf, l, 1); } else control16(c, 1, result, 1); @@ -2965,7 +2958,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) // Set multilink options before sending initial LCP packet sess_local[s].mp_mrru = 1614; - sess_local[s].mp_epdis = config->bind_address ? config->bind_address : my_address; + sess_local[s].mp_epdis = ntohl(config->bind_address ? config->bind_address : my_address); sendlcp(s, t); change_state(s, lcp, RequestSent); @@ -3593,35 +3586,36 @@ static int still_busy(void) static clockt last_talked = 0; static clockt start_busy_wait = 0; - if (!config->cluster_iam_master) - { #ifdef BGP - static time_t stopped_bgp = 0; - if (bgp_configured) + static time_t stopped_bgp = 0; + if (bgp_configured) + { + if (!stopped_bgp) { - if (!stopped_bgp) - { - LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY); + LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY); - for (i = 0; i < BGP_NUM_PEERS; i++) - if (bgp_peers[i].state == Established) - bgp_stop(&bgp_peers[i]); + for (i = 0; i < BGP_NUM_PEERS; i++) + if (bgp_peers[i].state == Established) + bgp_stop(&bgp_peers[i]); - stopped_bgp = time_now; + stopped_bgp = time_now; + if (!config->cluster_iam_master) + { // we don't want to become master cluster_send_ping(0); return 1; } - - if (time_now < (stopped_bgp + QUIT_DELAY)) - return 1; } + + if (!config->cluster_iam_master && time_now < (stopped_bgp + QUIT_DELAY)) + return 1; + } #endif /* BGP */ + if (!config->cluster_iam_master) return 0; - } if (main_quit == QUIT_SHUTDOWN) { @@ -3766,7 +3760,8 @@ static void mainloop(void) if (config->neighbour[i].name[0]) bgp_start(&bgp_peers[i], config->neighbour[i].name, config->neighbour[i].as, config->neighbour[i].keepalive, - config->neighbour[i].hold, 0); /* 0 = routing disabled */ + config->neighbour[i].hold, config->neighbour[i].update_source, + 0); /* 0 = routing disabled */ } #endif /* BGP */ @@ -3986,6 +3981,11 @@ static void mainloop(void) more++; } } +#ifdef BGP + else + /* no event received, but timers could still have expired */ + bgp_process_peers_timers(); +#endif /* BGP */ if (time_changed) { @@ -4473,18 +4473,18 @@ static void fix_address_pool(int sid) // // Add a block of addresses to the IP pool to hand out. // -static void add_to_ip_pool(in_addr_t addr, in_addr_t mask) +static void add_to_ip_pool(in_addr_t addr, int prefixlen) { int i; - if (mask == 0) - mask = 0xffffffff; // Host route only. + if (prefixlen == 0) + prefixlen = 32; // Host route only. - addr &= mask; + addr &= 0xffffffff << (32 - prefixlen); if (ip_pool_size >= MAXIPPOOL) // Pool is full! return ; - for (i = addr ;(i & mask) == addr; ++i) + for (i = addr ; i < addr+(1<<(32-prefixlen)); ++i) { if ((i & 0xff) == 0 || (i&0xff) == 255) continue; // Skip 0 and broadcast addresses. @@ -4542,7 +4542,7 @@ static void initippool() { // It's a range int numbits = 0; - in_addr_t start = 0, mask = 0; + in_addr_t start = 0; LOG(2, 0, 0, "Adding IP address range %s\n", buf); *p++ = 0; @@ -4552,15 +4552,14 @@ static void initippool() continue; } start = ntohl(inet_addr(pool)); - mask = (in_addr_t) (pow(2, numbits) - 1) << (32 - numbits); // Add a static route for this pool - LOG(5, 0, 0, "Adding route for address pool %s/%u\n", - fmtaddr(htonl(start), 0), 32 + mask); + LOG(5, 0, 0, "Adding route for address pool %s/%d\n", + fmtaddr(htonl(start), 0), numbits); - routeset(0, start, mask, 0, 1); + routeset(0, start, numbits, 0, 1); - add_to_ip_pool(start, mask); + add_to_ip_pool(start, numbits); } else { @@ -4711,8 +4710,12 @@ int main(int argc, char *argv[]) initplugins(); initdata(optdebug, optconfig); - init_cli(hostname); + init_cli(); read_config_file(); + /* set hostname /after/ having read the config file */ + if (*config->hostname) + strcpy(hostname, config->hostname); + cli_init_complete(hostname); update_config(); init_tbf(config->num_tbfs); @@ -5209,11 +5212,11 @@ int sessionsetup(sessionidt s, tunnelidt t) // Add the route for this session. for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++) { - if ((session[s].ip & session[s].route[r].mask) == - (session[s].route[r].ip & session[s].route[r].mask)) + if ((session[s].ip >> (32-session[s].route[r].prefixlen)) == + (session[s].route[r].ip >> (32-session[s].route[r].prefixlen))) routed++; - routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 1); + routeset(s, session[s].route[r].ip, session[s].route[r].prefixlen, 0, 1); } // Static IPs need to be routed if not already @@ -5284,7 +5287,7 @@ int load_session(sessionidt s, sessiont *new) for (i = 0; !newip && i < MAXROUTE && (session[s].route[i].ip || new->route[i].ip); i++) if (new->route[i].ip != session[s].route[i].ip || - new->route[i].mask != session[s].route[i].mask) + new->route[i].prefixlen != session[s].route[i].prefixlen) newip++; // needs update @@ -5295,11 +5298,11 @@ int load_session(sessionidt s, sessiont *new) // remove old routes... for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++) { - if ((session[s].ip & session[s].route[i].mask) == - (session[s].route[i].ip & session[s].route[i].mask)) + if ((session[s].ip >> (32-session[s].route[i].prefixlen)) == + (session[s].route[i].ip >> (32-session[s].route[i].prefixlen))) routed++; - routeset(s, session[s].route[i].ip, session[s].route[i].mask, 0, 0); + routeset(s, session[s].route[i].ip, session[s].route[i].prefixlen, 0, 0); } // ...ip @@ -5318,11 +5321,11 @@ int load_session(sessionidt s, sessiont *new) // add new routes... for (i = 0; i < MAXROUTE && new->route[i].ip; i++) { - if ((new->ip & new->route[i].mask) == - (new->route[i].ip & new->route[i].mask)) + if ((new->ip >> (32-new->route[i].prefixlen)) == + (new->route[i].ip >> (32-new->route[i].prefixlen))) routed++; - routeset(s, new->route[i].ip, new->route[i].mask, 0, 1); + routeset(s, new->route[i].ip, new->route[i].prefixlen, 0, 1); } // ...ip