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 static void (*old_ip_up_hook)(void) = NULL; 78 static void (*old_ip_down_hook)(void) = NULL; 79 80 /* Hook provided to allow other plugins to handle ACCM changes */ 81 void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id, 82 uint32_t send_accm, uint32_t recv_accm) = NULL; 83 84 /* Hook provided to allow other plugins to handle IP up/down */ 85 void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up) = NULL; 86 87 static option_t pppol2tp_options[] = { 88 { "pppol2tp", o_special, &setdevname_pppol2tp, 89 "FD for PPPoL2TP socket", OPT_DEVNAM | OPT_A2STRVAL, 90 &pppol2tp_fd_str }, 91 { "pppol2tp_lns_mode", o_bool, &pppol2tp_lns_mode, 92 "PPPoL2TP LNS behavior. Default off.", 93 OPT_PRIO | OPRIO_CFGFILE }, 94 { "pppol2tp_send_seq", o_bool, &pppol2tp_send_seq, 95 "PPPoL2TP enable sequence numbers in transmitted data packets. " 96 "Default off.", 97 OPT_PRIO | OPRIO_CFGFILE }, 98 { "pppol2tp_recv_seq", o_bool, &pppol2tp_recv_seq, 99 "PPPoL2TP enforce sequence numbers in received data packets. " 100 "Default off.", 101 OPT_PRIO | OPRIO_CFGFILE }, 102 { "pppol2tp_reorderto", o_int, &pppol2tp_reorder_timeout, 103 "PPPoL2TP data packet reorder timeout. Default 0 (no reordering).", 104 OPT_PRIO }, 105 { "pppol2tp_debug_mask", o_int, &pppol2tp_debug_mask, 106 "PPPoL2TP debug mask. Default: no debug.", 107 OPT_PRIO }, 108 { "pppol2tp_ifname", o_string, &pppol2tp_ifname, 109 "Set interface name of PPP interface", 110 OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, 16 }, 111 { "pppol2tp_tunnel_id", o_int, &pppol2tp_tunnel_id, 112 "PPPoL2TP tunnel_id.", 113 OPT_PRIO }, 114 { "pppol2tp_session_id", o_int, &pppol2tp_session_id, 115 "PPPoL2TP session_id.", 116 OPT_PRIO }, 117 { NULL } 118 }; 119 120 static int setdevname_pppol2tp(char **argv) 121 { 122 union { 123 char buffer[128]; 124 struct sockaddr pppol2tp; 125 } s; 126 int len = sizeof(s); 127 char **a; 128 int tmp; 129 int tmp_len = sizeof(tmp); 130 131 if (device_got_set) 132 return 0; 133 134 if (!int_option(*argv, &pppol2tp_fd)) 135 return 0; 136 137 if(getsockname(pppol2tp_fd, (struct sockaddr *)&s, &len) < 0) { 138 fatal("Given FD for PPPoL2TP socket invalid (%s)", 139 strerror(errno)); 140 } 141 if(s.pppol2tp.sa_family != AF_PPPOX) { 142 fatal("Socket of not a PPPoX socket"); 143 } 144 145 /* Do a test getsockopt() to ensure that the kernel has the necessary 146 * feature available. 147 */ 148 if (getsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG, 149 &tmp, &tmp_len) < 0) { 150 fatal("PPPoL2TP kernel driver not installed"); 151 } 152 153 /* Setup option defaults. Compression options are disabled! */ 154 155 modem = 0; 156 157 lcp_allowoptions[0].neg_accompression = 1; 158 lcp_wantoptions[0].neg_accompression = 0; 159 160 lcp_allowoptions[0].neg_pcompression = 1; 161 lcp_wantoptions[0].neg_pcompression = 0; 162 163 ccp_allowoptions[0].deflate = 0; 164 ccp_wantoptions[0].deflate = 0; 165 166 ipcp_allowoptions[0].neg_vj = 0; 167 ipcp_wantoptions[0].neg_vj = 0; 168 169 ccp_allowoptions[0].bsd_compress = 0; 170 ccp_wantoptions[0].bsd_compress = 0; 171 172 the_channel = &pppol2tp_channel; 173 device_got_set = 1; 174 175 return 1; 176 } 177 178 static int connect_pppol2tp(void) 179 { 180 if(pppol2tp_fd == -1) { 181 fatal("No PPPoL2TP FD specified"); 182 } 183 184 return pppol2tp_fd; 185 } 186 187 static void disconnect_pppol2tp(void) 188 { 189 if (pppol2tp_fd >= 0) { 190 close(pppol2tp_fd); 191 pppol2tp_fd = -1; 192 } 193 } 194 195 static void send_config_pppol2tp(int mtu, 196 u_int32_t asyncmap, 197 int pcomp, 198 int accomp) 199 { 200 struct ifreq ifr; 201 int on = 1; 202 int fd; 203 char reorderto[16]; 204 char tid[8]; 205 char sid[8]; 206 207 if (pppol2tp_ifname[0]) { 208 struct ifreq ifr; 209 int fd; 210 211 fd = socket(AF_INET, SOCK_DGRAM, 0); 212 if (fd >= 0) { 213 memset (&ifr, '\0', sizeof (ifr)); 214 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 215 strlcpy(ifr.ifr_newname, pppol2tp_ifname, 216 sizeof(ifr.ifr_name)); 217 ioctl(fd, SIOCSIFNAME, (caddr_t) &ifr); 218 strlcpy(ifname, pppol2tp_ifname, 32); 219 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) { 220 dbglog("ppp%d: interface name %s", 221 ifunit, ifname); 222 } 223 } 224 close(fd); 225 } 226 227 if ((lcp_allowoptions[0].mru > 0) && (mtu > lcp_allowoptions[0].mru)) { 228 warn("Overriding mtu %d to %d", mtu, lcp_allowoptions[0].mru); 229 mtu = lcp_allowoptions[0].mru; 230 } 231 netif_set_mtu(ifunit, mtu); 232 233 reorderto[0] = '\0'; 234 if (pppol2tp_reorder_timeout > 0) 235 sprintf(&reorderto[0], "%d ", pppol2tp_reorder_timeout); 236 tid[0] = '\0'; 237 if (pppol2tp_tunnel_id > 0) 238 sprintf(&tid[0], "%hu ", pppol2tp_tunnel_id); 239 sid[0] = '\0'; 240 if (pppol2tp_session_id > 0) 241 sprintf(&sid[0], "%hu ", pppol2tp_session_id); 242 243 dbglog("PPPoL2TP options: %s%s%s%s%s%s%s%s%sdebugmask %d", 244 pppol2tp_recv_seq ? "recvseq " : "", 245 pppol2tp_send_seq ? "sendseq " : "", 246 pppol2tp_lns_mode ? "lnsmode " : "", 247 pppol2tp_reorder_timeout ? "reorderto " : "", reorderto, 248 pppol2tp_tunnel_id ? "tid " : "", tid, 249 pppol2tp_session_id ? "sid " : "", sid, 250 pppol2tp_debug_mask); 251 252 if (pppol2tp_recv_seq) 253 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ, 254 &on, sizeof(on)) < 0) 255 fatal("setsockopt(PPPOL2TP_RECVSEQ): %m"); 256 if (pppol2tp_send_seq) 257 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ, 258 &on, sizeof(on)) < 0) 259 fatal("setsockopt(PPPOL2TP_SENDSEQ): %m"); 260 if (pppol2tp_lns_mode) 261 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE, 262 &on, sizeof(on)) < 0) 263 fatal("setsockopt(PPPOL2TP_LNSMODE): %m"); 264 if (pppol2tp_reorder_timeout) 265 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO, 266 &pppol2tp_reorder_timeout, 267 sizeof(pppol2tp_reorder_timeout)) < 0) 268 fatal("setsockopt(PPPOL2TP_REORDERTO): %m"); 269 if (pppol2tp_debug_mask) 270 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG, 271 &pppol2tp_debug_mask, sizeof(pppol2tp_debug_mask)) < 0) 272 fatal("setsockopt(PPPOL2TP_DEBUG): %m"); 273 } 274 275 static void recv_config_pppol2tp(int mru, 276 u_int32_t asyncmap, 277 int pcomp, 278 int accomp) 279 { 280 if ((lcp_allowoptions[0].mru > 0) && (mru > lcp_allowoptions[0].mru)) { 281 warn("Overriding mru %d to mtu value %d", mru, 282 lcp_allowoptions[0].mru); 283 mru = lcp_allowoptions[0].mru; 284 } 285 if ((ifunit >= 0) && ioctl(pppol2tp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) 286 error("Couldn't set PPP MRU: %m"); 287 } 288 289 /***************************************************************************** 290 * Snoop LCP message exchanges to capture negotiated ACCM values. 291 * When asyncmap values have been seen from both sides, give the values to 292 * L2TP. 293 * This code is derived from Roaring Penguin L2TP. 294 *****************************************************************************/ 295 296 static void pppol2tp_lcp_snoop(unsigned char *buf, int len, int incoming) 297 { 298 static bool got_send_accm = 0; 299 static bool got_recv_accm = 0; 300 static uint32_t recv_accm = 0xffffffff; 301 static uint32_t send_accm = 0xffffffff; 302 static bool snooping = 1; 303 304 uint16_t protocol; 305 uint16_t lcp_pkt_len; 306 int opt, opt_len; 307 int reject; 308 unsigned char const *opt_data; 309 uint32_t accm; 310 311 /* Skip HDLC header */ 312 buf += 2; 313 len -= 2; 314 315 /* Unreasonably short frame?? */ 316 if (len <= 0) return; 317 318 /* Get protocol */ 319 if (buf[0] & 0x01) { 320 /* Compressed protcol field */ 321 protocol = buf[0]; 322 } else { 323 protocol = ((unsigned int) buf[0]) * 256 + buf[1]; 324 } 325 326 /* If it's a network protocol, stop snooping */ 327 if (protocol <= 0x3fff) { 328 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) { 329 dbglog("Turning off snooping: " 330 "Network protocol %04x found.", 331 protocol); 332 } 333 snooping = 0; 334 return; 335 } 336 337 /* If it's not LCP, do not snoop */ 338 if (protocol != 0xc021) { 339 return; 340 } 341 342 /* Skip protocol; go to packet data */ 343 buf += 2; 344 len -= 2; 345 346 /* Unreasonably short frame?? */ 347 if (len <= 0) return; 348 349 /* Look for Configure-Ack or Configure-Reject code */ 350 if (buf[0] != CONFACK && buf[0] != CONFREJ) return; 351 352 reject = (buf[0] == CONFREJ); 353 354 lcp_pkt_len = ((unsigned int) buf[2]) * 256 + buf[3]; 355 356 /* Something fishy with length field? */ 357 if (lcp_pkt_len > len) return; 358 359 /* Skip to options */ 360 len = lcp_pkt_len - 4; 361 buf += 4; 362 363 while (len > 0) { 364 /* Pull off an option */ 365 opt = buf[0]; 366 opt_len = buf[1]; 367 opt_data = &buf[2]; 368 if (opt_len > len || opt_len < 2) break; 369 len -= opt_len; 370 buf += opt_len; 371 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) { 372 dbglog("Found option type %02x; len %d", opt, opt_len); 373 } 374 375 /* We are specifically interested in ACCM */ 376 if (opt == CI_ASYNCMAP && opt_len == 0x06) { 377 if (reject) { 378 /* ACCM negotiation REJECTED; use default */ 379 accm = 0xffffffff; 380 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) { 381 dbglog("Rejected ACCM negotiation; " 382 "defaulting (%s)", 383 incoming ? "incoming" : "outgoing"); 384 } 385 recv_accm = accm; 386 send_accm = accm; 387 got_recv_accm = 1; 388 got_send_accm = 1; 389 } else { 390 memcpy(&accm, opt_data, sizeof(accm)); 391 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) { 392 dbglog("Found ACCM of %08x (%s)", accm, 393 incoming ? "incoming" : "outgoing"); 394 } 395 if (incoming) { 396 recv_accm = accm; 397 got_recv_accm = 1; 398 } else { 399 send_accm = accm; 400 got_send_accm = 1; 401 } 402 } 403 404 if (got_recv_accm && got_send_accm) { 405 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) { 406 dbglog("Telling L2TP: Send ACCM = %08x; " 407 "Receive ACCM = %08x", send_accm, recv_accm); 408 } 409 if (pppol2tp_send_accm_hook != NULL) { 410 (*pppol2tp_send_accm_hook)(pppol2tp_tunnel_id, 411 pppol2tp_session_id, 412 send_accm, recv_accm); 413 } 414 got_recv_accm = 0; 415 got_send_accm = 0; 416 } 417 } 418 } 419 } 420 421 static void pppol2tp_lcp_snoop_recv(unsigned char *p, int len) 422 { 423 if (old_snoop_recv_hook != NULL) 424 (*old_snoop_recv_hook)(p, len); 425 pppol2tp_lcp_snoop(p, len, 1); 426 } 427 428 static void pppol2tp_lcp_snoop_send(unsigned char *p, int len) 429 { 430 if (old_snoop_send_hook != NULL) 431 (*old_snoop_send_hook)(p, len); 432 pppol2tp_lcp_snoop(p, len, 0); 433 } 434 435 /***************************************************************************** 436 * Interface up/down events 437 *****************************************************************************/ 438 439 static void pppol2tp_ip_up_hook(void) 440 { 441 if (old_ip_up_hook != NULL) 442 (*old_ip_up_hook)(); 443 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_hook(void) 451 { 452 if (old_ip_down_hook != NULL) 453 (*old_ip_down_hook)(); 454 455 if (pppol2tp_ip_updown_hook != NULL) { 456 (*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id, 457 pppol2tp_session_id, 0); 458 } 459 } 460 461 /***************************************************************************** 462 * Application init 463 *****************************************************************************/ 464 465 static void pppol2tp_check_options(void) 466 { 467 /* Enable LCP snooping for ACCM options only for LNS */ 468 if (pppol2tp_lns_mode) { 469 if ((pppol2tp_tunnel_id == 0) || (pppol2tp_session_id == 0)) { 470 fatal("tunnel_id/session_id values not specified"); 471 } 472 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) { 473 dbglog("Enabling LCP snooping"); 474 } 475 old_snoop_recv_hook = snoop_recv_hook; 476 old_snoop_send_hook = snoop_send_hook; 477 478 snoop_recv_hook = pppol2tp_lcp_snoop_recv; 479 snoop_send_hook = pppol2tp_lcp_snoop_send; 480 } 481 482 /* Hook up ip up/down hooks to send indicator to openl2tpd 483 * that the link is up 484 */ 485 old_ip_up_hook = ip_up_hook; 486 ip_up_hook = pppol2tp_ip_up_hook; 487 old_ip_down_hook = ip_down_hook; 488 ip_down_hook = pppol2tp_ip_down_hook; 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_available() && !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 add_options(pppol2tp_options); 512 } 513 514 struct channel pppol2tp_channel = { 515 options: pppol2tp_options, 516 process_extra_options: NULL, 517 check_options: &pppol2tp_check_options, 518 connect: &connect_pppol2tp, 519 disconnect: &disconnect_pppol2tp, 520 establish_ppp: &generic_establish_ppp, 521 disestablish_ppp: &generic_disestablish_ppp, 522 send_config: &send_config_pppol2tp, 523 recv_config: &recv_config_pppol2tp, 524 close: NULL, 525 cleanup: NULL 526 }; 527