From bde7904f922ed78582ef6289c3896978b51ce7cf Mon Sep 17 00:00:00 2001 From: Brendan O'Dea Date: Fri, 16 Sep 2005 05:04:28 +0000 Subject: [PATCH] - Add l2tp_mtu configuration option, used to define MRU, MSS. - Adjust TCP MSS options in SYN and SYN,ACK packets to avoid fragmentation of tcp packets. --- Changes | 6 ++- Docs/manual.html | 9 ++-- Docs/startup-config.5 | 9 ++-- etc/startup-config.default | 6 +-- l2tpns.c | 89 ++++++++++++++++++++++++++++++++------ l2tpns.h | 23 +++++++--- l2tpns.spec | 2 +- ppp.c | 43 +++++++++--------- 8 files changed, 132 insertions(+), 55 deletions(-) diff --git a/Changes b/Changes index a4cf2da..41c55be 100644 --- a/Changes +++ b/Changes @@ -1,8 +1,10 @@ -* Thu Sep 15 2005 Brendan O'Dea 2.1.6 +* Fri Sep 16 2005 Brendan O'Dea 2.1.6 - Any traffic on a tunnel resets lastrec, not just control messages. - Use a unique identifier for LCP. - Fix Code-Reject/Protocol-Reject. -- Make MRU configurable, NAK config requests for larger values. +- Add l2tp_mtu configuration option, used to define MRU, MSS. +- Adjust TCP MSS options in SYN and SYN,ACK packets to avoid + fragmentation of tcp packets. * Sat Sep 3 2005 Brendan O'Dea 2.1.5 - Avoid Code-Reject loop. diff --git a/Docs/manual.html b/Docs/manual.html index a963e19..d09e667 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -185,6 +185,11 @@ the same as the LAC, or authentication will fail. Only actually be used if the LAC requests authentication. +
  • l2tp_mtu (int)
    +MTU of interface for L2TP traffic (default: 1500). Used to set link +MRU and adjust TCP MSS. +
  • +
  • ppp_restart_time (int)
    ppp_max_configure (int)
    ppp_max_failure (int)
    @@ -192,10 +197,6 @@ PPP counter and timer values, as described in §4.1 of RFC1661.
  • -
  • ppp_mru (int)
    -PPP link MRU (default: 1452). -
  • -
  • primary_dns (ip address)
  • secondary_dns (ip address)
    Whenever a PPP connection is established, DNS servers will be sent to the diff --git a/Docs/startup-config.5 b/Docs/startup-config.5 index 4736e8c..97ebab9 100644 --- a/Docs/startup-config.5 +++ b/Docs/startup-config.5 @@ -2,7 +2,7 @@ .de Id .ds Dt \\$4 \\$5 .. -.Id $Id: startup-config.5,v 1.14 2005-09-15 09:34:49 bodea Exp $ +.Id $Id: startup-config.5,v 1.15 2005-09-16 05:04:31 bodea Exp $ .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions" .SH NAME startup\-config \- configuration file for l2tpns @@ -63,6 +63,10 @@ for authenticating tunnel request. Must be the same as the LAC, or authentication will fail. Only actually be used if the LAC requests authentication. .TP +.B l2tp_mtu +MTU of interface for L2TP traffic (default: 1500). Used to set link +MRU and adjust TCP MSS. +.TP .B ppp_restart_time Restart timer for PPP protocol negotiation in seconds (default: 3). .TP @@ -73,9 +77,6 @@ Number of configure requests to send before giving up (default: 10). Number of Configure-Nak requests to send before sending a Configure-Reject (default: 5). .TP -.B ppp_mru -PPP link MRU (default: 1452). -.TP .BR primary_dns , " secondary_dns" Whenever a PPP connection is established, DNS servers will be sent to the user, both a primary and a secondary. If either is set to 0.0.0.0, then that diff --git a/etc/startup-config.default b/etc/startup-config.default index 85f8bd1..0c5051c 100644 --- a/etc/startup-config.default +++ b/etc/startup-config.default @@ -10,14 +10,14 @@ set pid_file "/var/run/l2tpns.pid" # Shared secret with LAC set l2tp_secret "secret" +# MTU of interface for L2TP traffic +#set l2tp_mtu 1500 + # PPP counter and timer values #set ppp_restart_time 3 #set ppp_max_configure 10 #set ppp_max_failure 5 -# Link MRU -#set ppp_mru 1452 - # Only 2 DNS server entries are allowed set primary_dns 10.0.0.1 set secondary_dns 10.0.0.2 diff --git a/l2tpns.c b/l2tpns.c index 9671a69..de1aecc 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // 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.132 2005-09-15 09:34:48 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.133 2005-09-16 05:04:29 bodea Exp $"; #include #include @@ -75,6 +75,10 @@ static int syslog_log = 0; // are we logging to syslog static FILE *log_stream = 0; // file handle for direct logging (i.e. direct into file, not via syslog). uint32_t last_id = 0; // Unique ID for radius accounting +// calculated from config->l2tp_mtu +uint16_t MRU = 0; // PPP MRU +uint16_t MSS = 0; // TCP MSS + struct cli_session_actions *cli_session_actions = NULL; // Pending session changes requested by CLI struct cli_tunnel_actions *cli_tunnel_actions = NULL; // Pending tunnel changes required by CLI @@ -104,11 +108,11 @@ config_descriptt config_values[] = { CONFIG("log_file", log_filename, STRING), CONFIG("pid_file", pid_file, STRING), CONFIG("random_device", random_device, STRING), - CONFIG("l2tp_secret", l2tpsecret, STRING), + CONFIG("l2tp_secret", l2tp_secret, STRING), + CONFIG("l2tp_mtu", l2tp_mtu, INT), CONFIG("ppp_restart_time", ppp_restart_time, INT), CONFIG("ppp_max_configure", ppp_max_configure, INT), CONFIG("ppp_max_failure", ppp_max_failure, INT), - CONFIG("ppp_mru", ppp_mru, INT), CONFIG("primary_dns", default_dns1, IPv4), CONFIG("secondary_dns", default_dns2, IPv4), CONFIG("primary_radius", radiusserver[0], IPv4), @@ -979,6 +983,50 @@ int tun_write(uint8_t * data, int size) return write(tunfd, data, size); } +// adjust tcp mss to avoid fragmentation (called only for tcp packets with syn set) +void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *tcp) +{ + int d = (tcp[12] >> 4) * 4; + uint8_t *mss = 0; + uint8_t *data; + + if ((tcp[13] & 0x3f) & ~(TCP_FLAG_SYN|TCP_FLAG_ACK)) // only want SYN and SYN,ACK + return; + + if (tcp + d > buf + len) // short? + return; + + data = tcp + d; + tcp += 20; + + while (tcp < data) + { + if (*tcp == 2 && tcp[1] == 4) // mss option (2), length 4 + { + mss = tcp + 2; + if (mss + 2 > data) return; // short? + break; + } + + if (*tcp == 0) return; // end of options + if (*tcp == 1 || !tcp[1]) // no op (one byte), or no length (prevent loop) + tcp++; + else + tcp += tcp[1]; // skip over option + } + + if (!mss) return; // not found + if (ntohl(*(uint16_t *) mss) <= MSS) return; // mss OK + + LOG(5, s, t, "TCP: %s:%u -> %s:%u SYN%s, adjusted mss from %u to %u\n", + fmtaddr(*(in_addr_t *)(buf + 12), 0), *(uint16_t *)tcp, + fmtaddr(*(in_addr_t *)(buf + 16), 1), *(uint16_t *)(tcp + 2), + (tcp[13] & TCP_FLAG_ACK) ? ",ACK" : "", + ntohl(*(uint16_t *) mss), MSS); + + // FIXME +} + // process outgoing (to tunnel) IP // static void processipout(uint8_t *buf, int len) @@ -1086,6 +1134,14 @@ static void processipout(uint8_t *buf, int len) if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1)) return; + // adjust MSS on SYN and SYN,ACK packets with options + if ((ntohs(*(uint16_t *) (buf + 6)) & 0x1fff) == 0 && buf[9] == IPPROTO_TCP) // first tcp fragment + { + int ihl = (buf[0] & 0xf) * 4; // length of IP header + if (len >= ihl + 20 && (buf[ihl + 13] & TCP_FLAG_SYN) && ((buf[ihl + 12] >> 4) > 5)) + adjust_tcp_mss(s, t, buf, len, buf + ihl); + } + if (sp->tbf_out) { // Are we throttling this session? @@ -2009,7 +2065,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) uint16_t orig_len; // handle hidden AVPs - if (!*config->l2tpsecret) + if (!*config->l2tp_secret) { LOG(1, s, t, "Hidden AVP requested, but no L2TP secret.\n"); fatal = flags; @@ -2382,7 +2438,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) if (amagic == 0) amagic = time_now; session[s].magic = amagic; // set magic number session[s].l2tp_flags = aflags; // set flags received - session[s].mru = config->ppp_mru; + session[s].mru = PPPMTU; // default controlnull(t); // ack // start LCP @@ -2390,6 +2446,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) sess_local[s].lcp.conf_sent = 1; sess_local[s].lcp.nak_sent = 0; sess_local[s].lcp_authtype = config->radius_authprefer; + sess_local[s].ppp_mru = MRU; session[s].ppp.lcp = RequestSent; sendlcp(s, t); @@ -2535,8 +2592,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) uint8_t buf[MAXETHER]; uint8_t *q; int mru = session[s].mru; - - if (!mru) mru = MAXMRU; if (mru > sizeof(buf)) mru = sizeof(buf); l += 6; @@ -3501,7 +3556,6 @@ static void initdata(int optdebug, char *optconfig) config->ppp_restart_time = 3; config->ppp_max_configure = 10; config->ppp_max_failure = 5; - config->ppp_mru = DEFAULT_MRU; strcpy(config->random_device, RANDOMDEVICE); log_stream = stderr; @@ -4171,7 +4225,7 @@ static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challen MD5_CTX ctx; *challenge_response = NULL; - if (!*config->l2tpsecret) + if (!*config->l2tp_secret) { LOG(0, 0, 0, "LNS requested CHAP authentication, but no l2tp secret is defined\n"); return; @@ -4183,7 +4237,7 @@ static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challen MD5_Init(&ctx); MD5_Update(&ctx, &id, 1); - MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); MD5_Update(&ctx, challenge, challenge_length); MD5_Final(*challenge_response, &ctx); @@ -4250,7 +4304,16 @@ static void update_config() setbuf(log_stream, NULL); } - if (config->ppp_mru < 0) config->ppp_mru = 0; +#define L2TP_HDRS (20+8+6+4) // L2TP data encaptulation: ip + udp + l2tp (data) + ppp (inc hdlc) +#define TCP_HDRS (20+20) // TCP encapsulation: ip + tcp + + if (config->l2tp_mtu <= 0) config->l2tp_mtu = PPPMTU; + else if (config->l2tp_mtu < MINMTU) config->l2tp_mtu = MINMTU; + else if (config->l2tp_mtu > MAXMTU) config->l2tp_mtu = MAXMTU; + + // reset MRU/MSS globals + MRU = config->l2tp_mtu - L2TP_HDRS; + MSS = MRU - TCP_HDRS; // Update radius config->numradiusservers = 0; @@ -5150,7 +5213,7 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec // Compute initial pad MD5_Init(&ctx); MD5_Update(&ctx, (unsigned char *) &m, 2); - MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); MD5_Update(&ctx, vector, vec_len); MD5_Final(digest, &ctx); @@ -5163,7 +5226,7 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec if (d >= sizeof(digest)) { MD5_Init(&ctx); - MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret)); + MD5_Update(&ctx, config->l2tp_secret, strlen(config->l2tp_secret)); MD5_Update(&ctx, last, sizeof(digest)); MD5_Final(digest, &ctx); diff --git a/l2tpns.h b/l2tpns.h index 71f8ddc..577de9c 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // L2TPNS Global Stuff -// $Id: l2tpns.h,v 1.90 2005-09-15 09:34:49 bodea Exp $ +// $Id: l2tpns.h,v 1.91 2005-09-16 05:04:29 bodea Exp $ #ifndef __L2TPNS_H__ #define __L2TPNS_H__ @@ -31,8 +31,10 @@ #define T_FREE (0) // A tunnel ID that won't ever be used. Mark session as free. #define MAXCONTROL 1000 // max length control message we ever send... -#define MAXMRU 1500 // max MRU as defined by RFC1661 -#define MAXETHER (MAXMRU+18) // max packet we try sending to tun +#define MINMTU 576 // minimum recommended MTU (rfc1063) +#define PPPMTU 1500 // default PPP MTU +#define MAXMTU 2600 // arbitrary maximum MTU +#define MAXETHER (MAXMTU+18) // max packet we try sending to tun #define MAXTEL 96 // telephone number #define MAXUSER 128 // username #define MAXPASS 128 // password @@ -45,7 +47,6 @@ #define ECHO_TIMEOUT 60 // Time between last packet sent and LCP ECHO generation #define IDLE_TIMEOUT 240 // Time between last packet sent and LCP ECHO generation #define BUSY_WAIT_TIME 3000 // 5 minutes in 1/10th seconds to wait for radius to cleanup on shutdown -#define DEFAULT_MRU 1452 // maximum packet size to avoid fragmentation when LNS ethernet MTU is 1500 // Constants #ifndef ETCDIR @@ -293,6 +294,9 @@ typedef struct // authentication to use int lcp_authtype; + // our MRU + uint16_t ppp_mru; + // DoS prevention clockt last_packet_out; uint32_t packets_out; @@ -512,14 +516,15 @@ typedef struct char tundevice[10]; // tun device name char log_filename[128]; - char l2tpsecret[64]; + + char l2tp_secret[64]; // L2TP shared secret + int l2tp_mtu; // MTU of interface used for L2TP char random_device[256]; // random device path, defaults to RANDOMDEVICE int ppp_restart_time; // timeout for PPP restart int ppp_max_configure; // max lcp configure requests to send int ppp_max_failure; // max lcp configure naks to send - int ppp_mru; // MRU to advertise char radiussecret[64]; int radius_accounting; @@ -704,6 +709,8 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error); void filter_session(sessionidt s, int filter_in, int filter_out); void send_garp(in_addr_t ip); void tunnelsend(uint8_t *buf, uint16_t l, tunnelidt t); +int tun_write(uint8_t *data, int size); +void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *tcp); void sendipcp(sessionidt s, tunnelidt t); void sendipv6cp(sessionidt s, tunnelidt t); void processudp(uint8_t *buf, int len, struct sockaddr_in *addr); @@ -770,7 +777,6 @@ extern char main_quit; extern uint32_t last_id; extern struct Tstats *_statistics; extern in_addr_t my_address; -extern int tun_write(uint8_t *data, int size); extern int clifd; extern int epollfd; @@ -790,6 +796,9 @@ struct event_data { #define TIME (config->current_time) +extern uint16_t MRU; +extern uint16_t MSS; + // macros for handling help in cli commands #define CLI_HELP_REQUESTED (argc > 0 && argv[argc-1][strlen(argv[argc-1])-1] == '?') #define CLI_HELP_NO_ARGS (argc > 1 || argv[0][1]) ? CLI_OK : cli_arg_help(cli, 1, NULL) diff --git a/l2tpns.spec b/l2tpns.spec index 2acc203..fc0141b 100644 --- a/l2tpns.spec +++ b/l2tpns.spec @@ -43,5 +43,5 @@ rm -rf %{buildroot} %attr(644,root,root) /usr/share/man/man[58]/* %changelog -* Thu Sep 15 2005 Brendan O'Dea 2.1.6-1 +* Fri Sep 16 2005 Brendan O'Dea 2.1.6-1 - 2.1.6 release, see /usr/share/doc/l2tpns-2.1.6/Changes diff --git a/ppp.c b/ppp.c index 9f0a713..fd5f460 100644 --- a/ppp.c +++ b/ppp.c @@ -1,6 +1,6 @@ // L2TPNS PPP Stuff -char const *cvs_id_ppp = "$Id: ppp.c,v 1.81 2005-09-15 09:34:49 bodea Exp $"; +char const *cvs_id_ppp = "$Id: ppp.c,v 1.82 2005-09-16 05:04:29 bodea Exp $"; #include #include @@ -449,8 +449,6 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto, { uint8_t *q; int mru = session[s].mru; - - if (!mru) mru = MAXMRU; if (mru > size) mru = size; l += 4; @@ -577,18 +575,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) switch (type) { case 1: // Maximum-Receive-Unit - { - uint16_t mru = ntohs(*(uint16_t *)(o + 2)); - if (!config->ppp_mru || mru <= config->ppp_mru) - { - session[s].mru = mru; - break; - } - - LOG(3, s, t, " Remote requesting MRU of %u. Rejecting.\n", mru); - mru = htons(config->ppp_mru); - q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, (uint8_t *) &mru, sizeof(mru)); - } + session[s].mru = ntohs(*(uint16_t *)(o + 2)); break; case 2: // Async-Control-Character-Map @@ -749,13 +736,12 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) case 1: // Maximum-Receive-Unit if (*p == ConfigNak) { - session[s].mru = 0; - LOG(3, s, t, " Remote requested MRU of %u; removing option\n", - ntohs(*(uint16_t *)(o + 2))); + sess_local[s].ppp_mru = ntohs(*(uint16_t *)(o + 2)); + LOG(3, s, t, " Remote requested MRU of %u\n", sess_local[s].ppp_mru); } else { - session[s].mru = 0; + sess_local[s].ppp_mru = 0; LOG(3, s, t, " Remote rejected MRU negotiation\n"); } @@ -1349,6 +1335,13 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) LOG_HEX(5, "IP", p, l); + if (l < 20 || l < ntohl(*(uint32_t *)(p + 2))) + { + LOG(1, s, t, "IP packet too short %d\n", l); + STAT(tunnel_rx_errors); + return ; + } + ip = ntohl(*(uint32_t *)(p + 12)); if (l > MAXETHER) @@ -1372,6 +1365,14 @@ void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) if (session[s].filter_in && !ip_filter(p, l, session[s].filter_in - 1)) return; + // adjust MSS on SYN and SYN,ACK packets with options + if ((ntohs(*(uint16_t *) (p + 6)) & 0x1fff) == 0 && p[9] == IPPROTO_TCP) // first tcp fragment + { + int ihl = (p[0] & 0xf) * 4; // length of IP header + if (l >= ihl + 20 && (p[ihl + 13] & TCP_FLAG_SYN) && ((p[ihl + 12] >> 4) > 5)) + adjust_tcp_mss(s, t, p, l, p + ihl); + } + // Add on the tun header p -= 4; *(uint32_t *) p = htonl(PKTIP); @@ -1819,10 +1820,10 @@ void sendlcp(sessionidt s, tunnelidt t) l += 2; //Save space for length - if (session[s].mru) + if (sess_local[s].ppp_mru) { *l++ = 1; *l++ = 4; // Maximum-Receive-Unit (length 4) - *(uint16_t *) l = htons(session[s].mru); l += 2; + *(uint16_t *) l = htons(sess_local[s].ppp_mru); l += 2; } if (authtype) -- 2.20.1