Home | History | Annotate | Line # | Download | only in pppol2tp
pppol2tp.c revision 1.1.1.3
      1 /* pppol2tp.c - pppd plugin to implement PPPoL2TP protocol
      2  *   for Linux using kernel pppol2tp support.
      3  *
      4  * Requires kernel pppol2tp driver which is integrated into the kernel
      5  * from 2.6.23 onwards. For earlier kernels, a version can be obtained
      6  * from the OpenL2TP project at
      7  * http://www.sourceforge.net/projects/openl2tp/
      8  *
      9  * Original by Martijn van Oosterhout <kleptog (at) svana.org>
     10  * Modified by jchapman (at) katalix.com
     11  *
     12  * Heavily based upon pppoatm.c: original notice follows
     13  *
     14  * Copyright 2000 Mitchell Blank Jr.
     15  * Based in part on work from Jens Axboe and Paul Mackerras.
     16  * Updated to ppp-2.4.1 by Bernhard Kaindl
     17  *
     18  *  This program is free software; you can redistribute it and/or
     19  *  modify it under the terms of the GNU General Public License
     20  *  as published by the Free Software Foundation; either version
     21  *  2 of the License, or (at your option) any later version.
     22  */
     23 #include <unistd.h>
     24 #include <string.h>
     25 #include <stdlib.h>
     26 #include <errno.h>
     27 #include "pppd.h"
     28 #include "pathnames.h"
     29 #include "fsm.h"
     30 #include "lcp.h"
     31 #include "ccp.h"
     32 #include "ipcp.h"
     33 #include <sys/stat.h>
     34 #include <net/if.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/socket.h>
     37 #include <netinet/in.h>
     38 #include <signal.h>
     39 #include <linux/version.h>
     40 #include <linux/sockios.h>
     41 #ifndef aligned_u64
     42 /* should be defined in sys/types.h */
     43 #define aligned_u64 unsigned long long __attribute__((aligned(8)))
     44 #endif
     45 #include <linux/types.h>
     46 #include <linux/if_ether.h>
     47 #include <linux/ppp_defs.h>
     48 #include <linux/if_ppp.h>
     49 #include <linux/if_pppox.h>
     50 #include <linux/if_pppol2tp.h>
     51 
     52 /* should be added to system's socket.h... */
     53 #ifndef SOL_PPPOL2TP
     54 #define SOL_PPPOL2TP	273
     55 #endif
     56 
     57 const char pppd_version[] = VERSION;
     58 
     59 static int setdevname_pppol2tp(char **argv);
     60 
     61 static int pppol2tp_fd = -1;
     62 static char *pppol2tp_fd_str;
     63 static bool pppol2tp_lns_mode = 0;
     64 static bool pppol2tp_recv_seq = 0;
     65 static bool pppol2tp_send_seq = 0;
     66 static int pppol2tp_debug_mask = 0;
     67 static int pppol2tp_reorder_timeout = 0;
     68 static char pppol2tp_ifname[32] = { 0, };
     69 int pppol2tp_tunnel_id = 0;
     70 int pppol2tp_session_id = 0;
     71 
     72 static int device_got_set = 0;
     73 struct channel pppol2tp_channel;
     74 
     75 static void (*old_snoop_recv_hook)(unsigned char *p, int len) = NULL;
     76 static void (*old_snoop_send_hook)(unsigned char *p, int len) = NULL;
     77 
     78 /* Hook provided to allow other plugins to handle ACCM changes */
     79 void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
     80 				uint32_t send_accm, uint32_t recv_accm) = NULL;
     81 
     82 /* Hook provided to allow other plugins to handle IP up/down */
     83 void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up) = NULL;
     84 
     85 static option_t pppol2tp_options[] = {
     86 	{ "pppol2tp", o_special, &setdevname_pppol2tp,
     87 	  "FD for PPPoL2TP socket", OPT_DEVNAM | OPT_A2STRVAL,
     88           &pppol2tp_fd_str },
     89 	{ "pppol2tp_lns_mode", o_bool, &pppol2tp_lns_mode,
     90 	  "PPPoL2TP LNS behavior. Default off.",
     91 	  OPT_PRIO | OPRIO_CFGFILE },
     92 	{ "pppol2tp_send_seq", o_bool, &pppol2tp_send_seq,
     93 	  "PPPoL2TP enable sequence numbers in transmitted data packets. "
     94 	  "Default off.",
     95 	  OPT_PRIO | OPRIO_CFGFILE },
     96 	{ "pppol2tp_recv_seq", o_bool, &pppol2tp_recv_seq,
     97 	  "PPPoL2TP enforce sequence numbers in received data packets. "
     98 	  "Default off.",
     99 	  OPT_PRIO | OPRIO_CFGFILE },
    100 	{ "pppol2tp_reorderto", o_int, &pppol2tp_reorder_timeout,
    101 	  "PPPoL2TP data packet reorder timeout. Default 0 (no reordering).",
    102 	  OPT_PRIO },
    103 	{ "pppol2tp_debug_mask", o_int, &pppol2tp_debug_mask,
    104 	  "PPPoL2TP debug mask. Default: no debug.",
    105 	  OPT_PRIO },
    106 	{ "pppol2tp_ifname", o_string, &pppol2tp_ifname,
    107 	  "Set interface name of PPP interface",
    108 	  OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, 16 },
    109 	{ "pppol2tp_tunnel_id", o_int, &pppol2tp_tunnel_id,
    110 	  "PPPoL2TP tunnel_id.",
    111 	  OPT_PRIO },
    112 	{ "pppol2tp_session_id", o_int, &pppol2tp_session_id,
    113 	  "PPPoL2TP session_id.",
    114 	  OPT_PRIO },
    115 	{ NULL }
    116 };
    117 
    118 static int setdevname_pppol2tp(char **argv)
    119 {
    120 	union {
    121 		char buffer[128];
    122 		struct sockaddr pppol2tp;
    123 	} s;
    124 	int len = sizeof(s);
    125 	char **a;
    126 	int tmp;
    127 	int tmp_len = sizeof(tmp);
    128 
    129 	if (device_got_set)
    130 		return 0;
    131 
    132 	if (!int_option(*argv, &pppol2tp_fd))
    133 		return 0;
    134 
    135 	if(getsockname(pppol2tp_fd, (struct sockaddr *)&s, &len) < 0) {
    136 		fatal("Given FD for PPPoL2TP socket invalid (%s)",
    137 		      strerror(errno));
    138 	}
    139 	if(s.pppol2tp.sa_family != AF_PPPOX) {
    140 		fatal("Socket of not a PPPoX socket");
    141 	}
    142 
    143 	/* Do a test getsockopt() to ensure that the kernel has the necessary
    144 	 * feature available.
    145 	 */
    146 	if (getsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
    147 		       &tmp, &tmp_len) < 0) {
    148 		fatal("PPPoL2TP kernel driver not installed");
    149 	}
    150 
    151 	pppol2tp_fd_str = strdup(*argv);
    152 	if (pppol2tp_fd_str == NULL)
    153 		novm("PPPoL2TP FD");
    154 
    155 	/* Setup option defaults. Compression options are disabled! */
    156 
    157 	modem = 0;
    158 
    159 	lcp_allowoptions[0].neg_accompression = 1;
    160 	lcp_wantoptions[0].neg_accompression = 0;
    161 
    162 	lcp_allowoptions[0].neg_pcompression = 1;
    163 	lcp_wantoptions[0].neg_pcompression = 0;
    164 
    165 	ccp_allowoptions[0].deflate = 0;
    166 	ccp_wantoptions[0].deflate = 0;
    167 
    168 	ipcp_allowoptions[0].neg_vj = 0;
    169 	ipcp_wantoptions[0].neg_vj = 0;
    170 
    171 	ccp_allowoptions[0].bsd_compress = 0;
    172 	ccp_wantoptions[0].bsd_compress = 0;
    173 
    174 	the_channel = &pppol2tp_channel;
    175 	device_got_set = 1;
    176 
    177 	return 1;
    178 }
    179 
    180 static int connect_pppol2tp(void)
    181 {
    182 	if(pppol2tp_fd == -1) {
    183 		fatal("No PPPoL2TP FD specified");
    184 	}
    185 
    186 	return pppol2tp_fd;
    187 }
    188 
    189 static void disconnect_pppol2tp(void)
    190 {
    191 	if (pppol2tp_fd >= 0) {
    192 		close(pppol2tp_fd);
    193 		pppol2tp_fd = -1;
    194 	}
    195 }
    196 
    197 static void send_config_pppol2tp(int mtu,
    198 			      u_int32_t asyncmap,
    199 			      int pcomp,
    200 			      int accomp)
    201 {
    202 	struct ifreq ifr;
    203 	int on = 1;
    204 	int fd;
    205 	char reorderto[16];
    206 	char tid[8];
    207 	char sid[8];
    208 
    209 	if (pppol2tp_ifname[0]) {
    210 		struct ifreq ifr;
    211 		int fd;
    212 
    213 		fd = socket(AF_INET, SOCK_DGRAM, 0);
    214 		if (fd >= 0) {
    215 			memset (&ifr, '\0', sizeof (ifr));
    216 			strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    217 			strlcpy(ifr.ifr_newname, pppol2tp_ifname,
    218 				sizeof(ifr.ifr_name));
    219 			ioctl(fd, SIOCSIFNAME, (caddr_t) &ifr);
    220 			strlcpy(ifname, pppol2tp_ifname, 32);
    221 			if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
    222 				dbglog("ppp%d: interface name %s",
    223 				       ifunit, ifname);
    224 			}
    225 		}
    226 		close(fd);
    227 	}
    228 
    229 	if ((lcp_allowoptions[0].mru > 0) && (mtu > lcp_allowoptions[0].mru)) {
    230 		warn("Overriding mtu %d to %d", mtu, lcp_allowoptions[0].mru);
    231 		mtu = lcp_allowoptions[0].mru;
    232 	}
    233 	netif_set_mtu(ifunit, mtu);
    234 
    235 	reorderto[0] = '\0';
    236 	if (pppol2tp_reorder_timeout > 0)
    237 		sprintf(&reorderto[0], "%d ", pppol2tp_reorder_timeout);
    238 	tid[0] = '\0';
    239 	if (pppol2tp_tunnel_id > 0)
    240 		sprintf(&tid[0], "%hu ", pppol2tp_tunnel_id);
    241 	sid[0] = '\0';
    242 	if (pppol2tp_session_id > 0)
    243 		sprintf(&sid[0], "%hu ", pppol2tp_session_id);
    244 
    245 	dbglog("PPPoL2TP options: %s%s%s%s%s%s%s%s%sdebugmask %d",
    246 	       pppol2tp_recv_seq ? "recvseq " : "",
    247 	       pppol2tp_send_seq ? "sendseq " : "",
    248 	       pppol2tp_lns_mode ? "lnsmode " : "",
    249 	       pppol2tp_reorder_timeout ? "reorderto " : "", reorderto,
    250 	       pppol2tp_tunnel_id ? "tid " : "", tid,
    251 	       pppol2tp_session_id ? "sid " : "", sid,
    252 	       pppol2tp_debug_mask);
    253 
    254 	if (pppol2tp_recv_seq)
    255 		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ,
    256 			       &on, sizeof(on)) < 0)
    257 			fatal("setsockopt(PPPOL2TP_RECVSEQ): %m");
    258 	if (pppol2tp_send_seq)
    259 		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ,
    260 			       &on, sizeof(on)) < 0)
    261 			fatal("setsockopt(PPPOL2TP_SENDSEQ): %m");
    262 	if (pppol2tp_lns_mode)
    263 		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE,
    264 			       &on, sizeof(on)) < 0)
    265 			fatal("setsockopt(PPPOL2TP_LNSMODE): %m");
    266 	if (pppol2tp_reorder_timeout)
    267 		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO,
    268 			       &pppol2tp_reorder_timeout,
    269 			       sizeof(pppol2tp_reorder_timeout)) < 0)
    270 			fatal("setsockopt(PPPOL2TP_REORDERTO): %m");
    271 	if (pppol2tp_debug_mask)
    272 		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
    273 			       &pppol2tp_debug_mask, sizeof(pppol2tp_debug_mask)) < 0)
    274 			fatal("setsockopt(PPPOL2TP_DEBUG): %m");
    275 }
    276 
    277 static void recv_config_pppol2tp(int mru,
    278 			      u_int32_t asyncmap,
    279 			      int pcomp,
    280 			      int accomp)
    281 {
    282 	if ((lcp_allowoptions[0].mru > 0) && (mru > lcp_allowoptions[0].mru)) {
    283 		warn("Overriding mru %d to mtu value %d", mru,
    284 		     lcp_allowoptions[0].mru);
    285 		mru = lcp_allowoptions[0].mru;
    286 	}
    287 	if ((ifunit >= 0) && ioctl(pppol2tp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
    288 		error("Couldn't set PPP MRU: %m");
    289 }
    290 
    291 /*****************************************************************************
    292  * Snoop LCP message exchanges to capture negotiated ACCM values.
    293  * When asyncmap values have been seen from both sides, give the values to
    294  * L2TP.
    295  * This code is derived from Roaring Penguin L2TP.
    296  *****************************************************************************/
    297 
    298 static void pppol2tp_lcp_snoop(unsigned char *buf, int len, int incoming)
    299 {
    300 	static bool got_send_accm = 0;
    301 	static bool got_recv_accm = 0;
    302 	static uint32_t recv_accm = 0xffffffff;
    303 	static uint32_t send_accm = 0xffffffff;
    304 	static bool snooping = 1;
    305 
    306 	uint16_t protocol;
    307 	uint16_t lcp_pkt_len;
    308 	int opt, opt_len;
    309 	int reject;
    310 	unsigned char const *opt_data;
    311 	uint32_t accm;
    312 
    313 	/* Skip HDLC header */
    314 	buf += 2;
    315 	len -= 2;
    316 
    317 	/* Unreasonably short frame?? */
    318 	if (len <= 0) return;
    319 
    320 	/* Get protocol */
    321 	if (buf[0] & 0x01) {
    322 		/* Compressed protcol field */
    323 		protocol = buf[0];
    324 	} else {
    325 		protocol = ((unsigned int) buf[0]) * 256 + buf[1];
    326 	}
    327 
    328 	/* If it's a network protocol, stop snooping */
    329 	if (protocol <= 0x3fff) {
    330 		if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
    331 			dbglog("Turning off snooping: "
    332 			       "Network protocol %04x found.",
    333 			       protocol);
    334 		}
    335 		snooping = 0;
    336 		return;
    337 	}
    338 
    339 	/* If it's not LCP, do not snoop */
    340 	if (protocol != 0xc021) {
    341 		return;
    342 	}
    343 
    344 	/* Skip protocol; go to packet data */
    345 	buf += 2;
    346 	len -= 2;
    347 
    348 	/* Unreasonably short frame?? */
    349 	if (len <= 0) return;
    350 
    351 	/* Look for Configure-Ack or Configure-Reject code */
    352 	if (buf[0] != CONFACK && buf[0] != CONFREJ) return;
    353 
    354 	reject = (buf[0] == CONFREJ);
    355 
    356 	lcp_pkt_len = ((unsigned int) buf[2]) * 256 + buf[3];
    357 
    358 	/* Something fishy with length field? */
    359 	if (lcp_pkt_len > len) return;
    360 
    361 	/* Skip to options */
    362 	len = lcp_pkt_len - 4;
    363 	buf += 4;
    364 
    365 	while (len > 0) {
    366 		/* Pull off an option */
    367 		opt = buf[0];
    368 		opt_len = buf[1];
    369 		opt_data = &buf[2];
    370 		if (opt_len > len || opt_len < 2) break;
    371 		len -= opt_len;
    372 		buf += opt_len;
    373 		if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
    374 			dbglog("Found option type %02x; len %d", opt, opt_len);
    375 		}
    376 
    377 		/* We are specifically interested in ACCM */
    378 		if (opt == CI_ASYNCMAP && opt_len == 0x06) {
    379 			if (reject) {
    380 				/* ACCM negotiation REJECTED; use default */
    381 				accm = 0xffffffff;
    382 				if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
    383 					dbglog("Rejected ACCM negotiation; "
    384 					       "defaulting (%s)",
    385 					       incoming ? "incoming" : "outgoing");
    386 				}
    387 				recv_accm = accm;
    388 				send_accm = accm;
    389 				got_recv_accm = 1;
    390 				got_send_accm = 1;
    391 			} else {
    392 				memcpy(&accm, opt_data, sizeof(accm));
    393 				if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
    394 					dbglog("Found ACCM of %08x (%s)", accm,
    395 					       incoming ? "incoming" : "outgoing");
    396 				}
    397 				if (incoming) {
    398 					recv_accm = accm;
    399 					got_recv_accm = 1;
    400 				} else {
    401 					send_accm = accm;
    402 					got_send_accm = 1;
    403 				}
    404 			}
    405 
    406 			if (got_recv_accm && got_send_accm) {
    407 				if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
    408 					dbglog("Telling L2TP: Send ACCM = %08x; "
    409 					       "Receive ACCM = %08x", send_accm, recv_accm);
    410 				}
    411 				if (pppol2tp_send_accm_hook != NULL) {
    412 					(*pppol2tp_send_accm_hook)(pppol2tp_tunnel_id,
    413 								   pppol2tp_session_id,
    414 								   send_accm, recv_accm);
    415 				}
    416 				got_recv_accm = 0;
    417 				got_send_accm = 0;
    418 			}
    419 		}
    420 	}
    421 }
    422 
    423 static void pppol2tp_lcp_snoop_recv(unsigned char *p, int len)
    424 {
    425 	if (old_snoop_recv_hook != NULL)
    426 		(*old_snoop_recv_hook)(p, len);
    427 	pppol2tp_lcp_snoop(p, len, 1);
    428 }
    429 
    430 static void pppol2tp_lcp_snoop_send(unsigned char *p, int len)
    431 {
    432 	if (old_snoop_send_hook != NULL)
    433 		(*old_snoop_send_hook)(p, len);
    434 	pppol2tp_lcp_snoop(p, len, 0);
    435 }
    436 
    437 /*****************************************************************************
    438  * Interface up/down events
    439  *****************************************************************************/
    440 
    441 static void pppol2tp_ip_up(void *opaque, int arg)
    442 {
    443 	/* may get called twice (for IPv4 and IPv6) but the hook handles that well */
    444 	if (pppol2tp_ip_updown_hook != NULL) {
    445 		(*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
    446 					   pppol2tp_session_id, 1);
    447 	}
    448 }
    449 
    450 static void pppol2tp_ip_down(void *opaque, int arg)
    451 {
    452 	/* may get called twice (for IPv4 and IPv6) but the hook handles that well */
    453 	if (pppol2tp_ip_updown_hook != NULL) {
    454 		(*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
    455 					   pppol2tp_session_id, 0);
    456 	}
    457 }
    458 
    459 /*****************************************************************************
    460  * Application init
    461  *****************************************************************************/
    462 
    463 static void pppol2tp_check_options(void)
    464 {
    465 	/* Enable LCP snooping for ACCM options only for LNS */
    466 	if (pppol2tp_lns_mode) {
    467 		if ((pppol2tp_tunnel_id == 0) || (pppol2tp_session_id == 0)) {
    468 			fatal("tunnel_id/session_id values not specified");
    469 		}
    470 		if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
    471 			dbglog("Enabling LCP snooping");
    472 		}
    473 		old_snoop_recv_hook = snoop_recv_hook;
    474 		old_snoop_send_hook = snoop_send_hook;
    475 
    476 		snoop_recv_hook = pppol2tp_lcp_snoop_recv;
    477 		snoop_send_hook = pppol2tp_lcp_snoop_send;
    478 	}
    479 }
    480 
    481 /* Called just before pppd exits.
    482  */
    483 static void pppol2tp_cleanup(void)
    484 {
    485 	if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
    486 		dbglog("pppol2tp: exiting.");
    487 	}
    488 	disconnect_pppol2tp();
    489 }
    490 
    491 void plugin_init(void)
    492 {
    493 #if defined(__linux__)
    494 	extern int new_style_driver;	/* From sys-linux.c */
    495 	if (!ppp_available() && !new_style_driver)
    496 		fatal("Kernel doesn't support ppp_generic - "
    497 		    "needed for PPPoL2TP");
    498 #else
    499 	fatal("No PPPoL2TP support on this OS");
    500 #endif
    501 	add_options(pppol2tp_options);
    502 
    503 	/* Hook up ip up/down notifiers to send indicator to openl2tpd
    504 	 * that the link is up
    505 	 */
    506 	add_notifier(&ip_up_notifier, pppol2tp_ip_up, NULL);
    507 	add_notifier(&ip_down_notifier, pppol2tp_ip_down, NULL);
    508 	add_notifier(&ipv6_up_notifier, pppol2tp_ip_up, NULL);
    509 	add_notifier(&ipv6_down_notifier, pppol2tp_ip_down, NULL);
    510 }
    511 
    512 struct channel pppol2tp_channel = {
    513     options: pppol2tp_options,
    514     process_extra_options: NULL,
    515     check_options: &pppol2tp_check_options,
    516     connect: &connect_pppol2tp,
    517     disconnect: &disconnect_pppol2tp,
    518     establish_ppp: &generic_establish_ppp,
    519     disestablish_ppp: &generic_disestablish_ppp,
    520     send_config: &send_config_pppol2tp,
    521     recv_config: &recv_config_pppol2tp,
    522     close: NULL,
    523     cleanup: NULL
    524 };
    525