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