xref: /netbsd-src/external/bsd/ppp/dist/pppd/plugins/pppol2tp/pppol2tp.c (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
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@svana.org>
10  * Modified by jchapman@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