X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/442b04cea2db5efc9636bb6a7d5b7166dee8fb3c..0834bba08ed4f1e507320306dc682d7e62371af5:/l2tpns.c?ds=inline diff --git a/l2tpns.c b/l2tpns.c index d1c1337..694726d 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -53,11 +53,23 @@ #include "bgp.h" #endif +#ifdef LAC +#include "l2tplac.h" +#endif + +#ifdef LAC +char * Vendor_name = "Linux L2TPNS"; +uint32_t call_serial_number = 0; +#endif + // Globals configt *config = NULL; // all configuration int nlfd = -1; // netlink socket int tunfd = -1; // tun interface file handle. (network device) int udpfd = -1; // UDP file handle +#ifdef LAC +int udplacfd = -1; // UDP LAC file handle +#endif int controlfd = -1; // Control signal handle int clifd = -1; // Socket listening for CLI connections. int daefd = -1; // Socket listening for DAE connections. @@ -102,6 +114,7 @@ uint32_t eth_tx = 0; static uint32_t ip_pool_size = 1; // Size of the pool of addresses used for dynamic address allocation. time_t time_now = 0; // Current time in seconds since epoch. +uint64_t time_now_ms = 0; // Current time in milliseconds since epoch. static char time_now_string[64] = {0}; // Current time as a string. static int time_changed = 0; // time_now changed char main_quit = 0; // True if we're in the process of exiting. @@ -159,8 +172,16 @@ config_descriptt config_values[] = { CONFIG("ipv6_prefix", ipv6_prefix, IPv6), CONFIG("cli_bind_address", cli_bind_address, IPv4), CONFIG("hostname", hostname, STRING), +#ifdef BGP CONFIG("nexthop_address", nexthop_address, IPv4), CONFIG("nexthop6_address", nexthop6_address, IPv6), +#endif + CONFIG("echo_timeout", echo_timeout, INT), + CONFIG("idle_echo_timeout", idle_echo_timeout, INT), +#ifdef LAC + CONFIG("disable_lac_func", disable_lac_func, BOOL), + CONFIG("bind_portremotelns", bind_portremotelns, SHORT), +#endif { NULL, 0, 0, 0 }, }; @@ -221,13 +242,6 @@ static tunnelidt new_tunnel(void); static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len); static void bundleclear(bundleidt b); -// on slaves, alow BGP to withdraw cleanly before exiting -#define QUIT_DELAY 5 - -// quit actions (master) -#define QUIT_FAILOVER 1 // SIGTERM: exit when all control messages have been acked (for cluster failover) -#define QUIT_SHUTDOWN 2 // SIGQUIT: shutdown sessions/tunnels, reject new connections - // return internal time (10ths since process startup), set f if given // as a side-effect sets time_now, and time_changed static clockt now(double *f) @@ -240,6 +254,10 @@ static clockt now(double *f) time_now = t.tv_sec; time_changed++; } + + // Time in milliseconds + time_now_ms = (t.tv_sec * 1000) + (t.tv_usec/1000); + return (t.tv_sec - basetime) * 10 + t.tv_usec / 100000 + 1; } @@ -855,6 +873,24 @@ static void initudp(void) exit(1); } +#ifdef LAC + // Tunnel to Remote LNS + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->bind_portremotelns); + udplacfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(udplacfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + { + int flags = fcntl(udplacfd, F_GETFL, 0); + fcntl(udplacfd, F_SETFL, flags | O_NONBLOCK); + } + if (bind(udplacfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + { + LOG(0, 0, 0, "Error in UDP REMOTE LNS bind: %s\n", strerror(errno)); + exit(1); + } +#endif + // Intercept snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } @@ -1175,8 +1211,11 @@ void tunnelsend(uint8_t * buf, uint16_t l, tunnelidt t) LOG(3, 0, t, "Control message resend try %d\n", tunnel[t].try); } } - +#ifdef LAC + if (sendto((tunnel[t].isremotelns?udplacfd:udpfd), buf, l, 0, (void *) &addr, sizeof(addr)) < 0) +#else if (sendto(udpfd, buf, l, 0, (void *) &addr, sizeof(addr)) < 0) +#endif { LOG(0, ntohs((*(uint16_t *) (buf + 6))), t, "Error sending data out tunnel: %s (udpfd=%d, buf=%p, len=%d, dest=%s)\n", strerror(errno), udpfd, buf, l, inet_ntoa(addr.sin_addr)); @@ -1323,7 +1362,8 @@ static void update_session_out_stat(sessionidt s, sessiont *sp, int len) // process outgoing (to tunnel) IP // -static void processipout(uint8_t *buf, int len) +// (i.e. this routine writes to data[-8]). +void processipout(uint8_t *buf, int len) { sessionidt s; sessiont *sp; @@ -1462,6 +1502,14 @@ static void processipout(uint8_t *buf, int len) if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) { + + if (!config->cluster_iam_master) + { + // The MPPP packets must be managed by the Master. + master_forward_mppp_packet(s, data, size); + return; + } + // Add on L2TP header sessionidt members[MAXBUNDLESES]; bundleidt bid = session[s].bundle; @@ -1483,7 +1531,7 @@ static void processipout(uint8_t *buf, int len) if (nb_opened < 1) { - LOG(2, s, t, "MPPP: PROCESSIPOUT ERROR, no session opened in bundle:%d\n", bid); + LOG(3, s, t, "MPPP: PROCESSIPOUT ERROR, no session opened in bundle:%d\n", bid); return; } @@ -1492,58 +1540,70 @@ static void processipout(uint8_t *buf, int len) s = members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; + LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - if ((num_of_links > 1) && (len > MINFRAGLEN)) + if (num_of_links > 1) { - LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - - //for rotate traffic among the member links - uint32_t divisor = num_of_links; - if (divisor > 2) - divisor--; - - // Partition the packet to "num_of_links" fragments - uint32_t fraglen = len / divisor; - uint32_t last_fraglen = fraglen + len % divisor; - 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... + if(len > MINFRAGLEN) + { + //for rotate traffic among the member links + uint32_t divisor = num_of_links; + if (divisor > 2) + divisor = divisor/2 + (divisor & 1); + + // Partition the packet to "num_of_links" fragments + uint32_t fraglen = len / divisor; + uint32_t last_fraglen = fraglen + len % divisor; + 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); + // statistics + update_session_out_stat(s, sp, fraglen); - remain -= fraglen; - while (remain > last_fraglen) - { + remain -= fraglen; + while (remain > last_fraglen) + { + b->current_ses = (b->current_ses + 1) % num_of_links; + s = 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), 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 = 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), fraglen, s, t, PPPIP, 0, bid, 0); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... - update_session_out_stat(s, sp, fraglen); - remain -= fraglen; + 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); } - // send the last fragment - b->current_ses = (b->current_ses + 1) % num_of_links; - s = 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 + else + { + // Send it as one frame (NO MPPP Frame) 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... @@ -2016,11 +2076,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e { uint8_t ml; for(ml = 0; mlcluster_iam_master) @@ -3082,7 +3234,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) return; } - LOG(1, s, t, "UDP packet contains session which is not opened. Dropping packet.\n"); STAT(tunnel_rx_errors); return; @@ -3191,6 +3342,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } // read and process packet on tun +// (i.e. this routine writes to buf[-8]). static void processtun(uint8_t * buf, int len) { LOG_HEX(5, "Receive TUN Data", buf, len); @@ -3464,8 +3616,8 @@ static void regular_cleanups(double period) } } - // Drop sessions who have not responded within IDLE_TIMEOUT seconds - if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT)) + // Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds + if (session[s].last_packet && (time_now - session[s].last_packet >= config->idle_echo_timeout)) { sessionshutdown(s, "No response to LCP ECHO requests.", CDN_ADMIN_DISC, TERM_LOST_SERVICE); STAT(session_timeout); @@ -3474,7 +3626,7 @@ static void regular_cleanups(double period) } // No data in ECHO_TIMEOUT seconds, send LCP ECHO - if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT) && + if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) && (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT)) { uint8_t b[MAXETHER]; @@ -3740,8 +3892,13 @@ static int still_busy(void) # include "fake_epoll.h" #endif +#ifdef LAC +// the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink, udplac +#define BASE_FDS 8 +#else // the base set of fds polled: cli, cluster, tun, udp, control, dae, netlink #define BASE_FDS 7 +#endif // additional polled fds #ifdef BGP @@ -3755,6 +3912,8 @@ static void mainloop(void) { int i; uint8_t buf[65536]; + uint8_t *p = buf + 8; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD) + int size_bufp = sizeof(buf) - 8; clockt next_cluster_ping = 0; // send initial ping immediately struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS]; int maxevent = sizeof(events)/sizeof(*events); @@ -3765,8 +3924,13 @@ static void mainloop(void) exit(1); } +#ifdef LAC + LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d , udplacfd=%d\n", + clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd, udplacfd); +#else LOG(4, 0, 0, "Beginning of main loop. clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d, nlfd=%d\n", clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd, nlfd); +#endif /* setup our fds to poll for input */ { @@ -3806,6 +3970,12 @@ static void mainloop(void) d[i].type = FD_TYPE_NETLINK; e.data.ptr = &d[i++]; epoll_ctl(epollfd, EPOLL_CTL_ADD, nlfd, &e); + +#ifdef LAC + d[i].type = FD_TYPE_UDPLAC; + e.data.ptr = &d[i++]; + epoll_ctl(epollfd, EPOLL_CTL_ADD, udplacfd, &e); +#endif } #ifdef BGP @@ -3868,6 +4038,10 @@ static void mainloop(void) socklen_t alen; int c, s; int udp_ready = 0; +#ifdef LAC + int udplac_ready = 0; + int udplac_pkts = 0; +#endif int tun_ready = 0; int cluster_ready = 0; int udp_pkts = 0; @@ -3905,7 +4079,9 @@ static void mainloop(void) case FD_TYPE_CLUSTER: cluster_ready++; break; case FD_TYPE_TUN: tun_ready++; break; case FD_TYPE_UDP: udp_ready++; break; - +#ifdef LAC + case FD_TYPE_UDPLAC: udplac_ready++; break; +#endif case FD_TYPE_CONTROL: // nsctl commands alen = sizeof(addr); s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local); @@ -3995,13 +4171,31 @@ static void mainloop(void) n--; } } +#ifdef LAC + // L2TP REMOTE LNS + if (udplac_ready) + { + alen = sizeof(addr); + if ((s = recvfrom(udplacfd, buf, sizeof(buf), 0, (void *) &addr, &alen)) > 0) + { + if (!config->disable_lac_func) + processudp(buf, s, &addr); + udplac_pkts++; + } + else + { + udplac_ready = 0; + n--; + } + } +#endif // incoming IP if (tun_ready) { - if ((s = read(tunfd, buf, sizeof(buf))) > 0) + if ((s = read(tunfd, p, size_bufp)) > 0) { - processtun(buf, s); + processtun(p, s); tun_pkts++; } else @@ -4033,9 +4227,13 @@ static void mainloop(void) if (c >= config->multi_read_count) { +#ifdef LAC + LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster %d rmlns packets\n", + config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts); +#else LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster packets\n", config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts); - +#endif STAT(multi_read_exceeded); more++; } @@ -4250,6 +4448,9 @@ static void initdata(int optdebug, char *optconfig) config->ppp_max_failure = 5; config->kill_timedout_sessions = 1; strcpy(config->random_device, RANDOMDEVICE); + // Set default value echo_timeout and idle_echo_timeout + config->echo_timeout = ECHO_TIMEOUT; + config->idle_echo_timeout = IDLE_ECHO_TIMEOUT; log_stream = stderr; @@ -4366,6 +4567,10 @@ static void initdata(int optdebug, char *optconfig) exit(1); } #endif /* BGP */ + +#ifdef LAC + lac_initremotelnsdata(); +#endif } static int assign_ip_address(sessionidt s) @@ -4652,7 +4857,11 @@ void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, ui static int dump_session(FILE **f, sessiont *s) { +#ifdef LAC + if (!s->opened || (!s->ip && !s->forwardtosession) || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden) +#else if (!s->opened || !s->ip || !(s->cin_delta || s->cout_delta) || !*s->user || s->walled_garden) +#endif return 1; if (!*f) @@ -5059,6 +5268,11 @@ static void update_config() if (!config->radius_dae_port) config->radius_dae_port = DAEPORT; +#ifdef LAC + if(!config->bind_portremotelns) + config->bind_portremotelns = L2TPLACPORT; +#endif + // re-initialise the random number source initrandom(config->random_device); @@ -5193,18 +5407,18 @@ int sessionsetup(sessionidt s, tunnelidt t) LOG(3, s, t, "Doing session setup for session\n"); // Join a bundle if the MRRU option is accepted - if(session[s].mrru > 0 && session[s].bundle == 0) - { - LOG(3, s, t, "This session can be part of multilink bundle\n"); - if (join_bundle(s) > 0) - cluster_send_bundle(session[s].bundle); + if(session[s].mrru > 0 && session[s].bundle == 0) + { + LOG(3, s, t, "This session can be part of multilink bundle\n"); + if (join_bundle(s) > 0) + cluster_send_bundle(session[s].bundle); else { LOG(0, s, t, "MPPP: Mismaching mssf option with other sessions in bundle\n"); sessionshutdown(s, "Mismaching mssf option.", CDN_NONE, TERM_SERVICE_UNAVAILABLE); return 0; } - } + } if (!session[s].ip) { @@ -5219,7 +5433,6 @@ int sessionsetup(sessionidt s, tunnelidt t) fmtaddr(htonl(session[s].ip), 0)); } - // Make sure this is right session[s].tunnel = t; @@ -5232,13 +5445,14 @@ int sessionsetup(sessionidt s, tunnelidt t) for (i = 1; i <= config->cluster_highest_sessionid; i++) { if (i == s) continue; - if (!session[s].opened) continue; + if (!session[s].opened) break; // Allow duplicate sessions for multilink ones of the same bundle. - if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) - continue; + if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) continue; + if (ip == session[i].ip) { sessionkill(i, "Duplicate IP address"); + cluster_listinvert_session(s, i); continue; } @@ -5246,16 +5460,16 @@ int sessionsetup(sessionidt s, tunnelidt t) if (session[s].walled_garden || session[i].walled_garden) continue; // Guest change int found = 0; - int gu; - for (gu = 0; gu < guest_accounts_num; gu++) - { - if (!strcasecmp(user, guest_users[gu])) - { - found = 1; - break; - } - } - if (found) continue; + int gu; + for (gu = 0; gu < guest_accounts_num; gu++) + { + if (!strcasecmp(user, guest_users[gu])) + { + found = 1; + break; + } + } + if (found) continue; // Drop the new session in case of duplicate sessionss, not the old one. if (!strcasecmp(user, session[i].user)) @@ -5266,7 +5480,7 @@ int sessionsetup(sessionidt s, tunnelidt t) // no need to set a route for the same IP address of the bundle if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1)) { - int routed = 0; + int routed = 0; // Add the route for this session. for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++) @@ -6112,3 +6326,52 @@ int ip_filter(uint8_t *buf, int len, uint8_t filter) // default deny return 0; } + +#ifdef LAC + +tunnelidt lac_new_tunnel() +{ + return new_tunnel(); +} + +void lac_tunnelclear(tunnelidt t) +{ + tunnelclear(t); +} + +void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len) +{ + uint16_t version = 0x0100; // protocol version + + tunnel[t].state = TUNNELOPENING; + + // Sent SCCRQ - Start Control Connection Request + controlt *c = controlnew(1); // sending SCCRQ + controls(c, 7, hostname, 1); // host name + controls(c, 8, Vendor_name, 1); // Vendor name + control16(c, 2, version, 1); // protocol version + control32(c, 3, 3, 1); // framing Capabilities + control16(c, 9, t, 1); // assigned tunnel + controlb(c, 11, (uint8_t *) auth, auth_len, 1); // CHAP Challenge + LOG(3, 0, t, "Sent SCCRQ to REMOTE LNS\n"); + controladd(c, 0, t); // send +} + +void lac_send_ICRQ(tunnelidt t, sessionidt s) +{ + // Sent ICRQ Incoming-call-request + controlt *c = controlnew(10); // ICRQ + + control16(c, 14, s, 1); // assigned sesion + call_serial_number++; + control32(c, 15, call_serial_number, 1); // call serial number + LOG(3, s, t, "Sent ICRQ to REMOTE LNS (far ID %u)\n", tunnel[t].far); + controladd(c, 0, t); // send +} + +void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg) +{ + tunnelshutdown(t, reason, result, error, msg); +} + +#endif