1 /* $OpenBSD: pppoed.c,v 1.11 2012/09/18 13:14:08 yasuoka Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Internet Initiative Japan Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /**@file 29 * This file provides the PPPoE(RFC2516) server(access concentrator) 30 * implementaion. 31 * $Id: pppoed.c,v 1.11 2012/09/18 13:14:08 yasuoka Exp $ 32 */ 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/endian.h> 36 #include <sys/socket.h> 37 #include <sys/ioctl.h> 38 #include <sys/uio.h> 39 #include <netinet/in.h> 40 #include <net/if.h> 41 #include <net/if_types.h> 42 #if defined(__NetBSD__) 43 #include <net/if_ether.h> 44 #else 45 #include <netinet/if_ether.h> 46 #endif 47 #include <net/if_dl.h> 48 #include <net/ethertypes.h> 49 #include <net/bpf.h> 50 #include <string.h> 51 #include <syslog.h> 52 #include <stdio.h> 53 #include <unistd.h> 54 #include <fcntl.h> 55 #include <time.h> 56 #include <event.h> 57 #include <signal.h> 58 #include <stdlib.h> 59 #include <ifaddrs.h> 60 #include <stdarg.h> 61 #include <errno.h> 62 63 #include "debugutil.h" 64 #include "slist.h" 65 #include "bytebuf.h" 66 #include "hash.h" 67 #include "privsep.h" 68 69 #include "pppoe.h" 70 #include "pppoe_local.h" 71 72 static int pppoed_seqno = 0; 73 74 #ifdef PPPOED_DEBUG 75 #define PPPOED_ASSERT(x) ASSERT(x) 76 #define PPPOED_DBG(x) pppoed_log x 77 #else 78 #define PPPOED_ASSERT(x) 79 #define PPPOED_DBG(x) 80 #endif 81 82 static void pppoed_log (pppoed *, int, const char *, ...) __printflike(3,4); 83 static void pppoed_listener_init(pppoed *, pppoed_listener *); 84 static int pppoed_output (pppoed_listener *, u_char *, u_char *, int); 85 static int pppoed_listener_start (pppoed_listener *, int); 86 static void pppoed_io_event (int, short, void *); 87 static void pppoed_input (pppoed_listener *, uint8_t [ETHER_ADDR_LEN], int, u_char *, int); 88 static void pppoed_recv_PADR (pppoed_listener *, uint8_t [ETHER_ADDR_LEN], slist *); 89 static void pppoed_recv_PADI (pppoed_listener *, uint8_t [ETHER_ADDR_LEN], slist *); 90 static int session_id_cmp (void *, void *); 91 static uint32_t session_id_hash (void *, size_t); 92 93 #ifdef PPPOE_TEST 94 static void pppoed_on_sigterm (int, short, void *); 95 static void usage (void); 96 #endif 97 static const char *pppoe_code_string(int); 98 #ifdef PPPOED_DEBUG 99 static const char *pppoe_tag_string(int); 100 #endif 101 102 /* 103 * daemon 104 */ 105 106 /* initialize PPPoE daemon */ 107 int 108 pppoed_init(pppoed *_this) 109 { 110 int i, off, id; 111 112 memset(_this, 0, sizeof(pppoed)); 113 _this->id = pppoed_seqno++; 114 115 if ((_this->session_hash = hash_create( 116 (int (*) (const void *, const void *))session_id_cmp, 117 (uint32_t (*) (const void *, int))session_id_hash, 118 PPPOE_SESSION_HASH_SIZ)) == NULL) { 119 pppoed_log(_this, LOG_ERR, "hash_create() failed on %s(): %m", 120 __func__); 121 goto fail; 122 } 123 124 slist_init(&_this->session_free_list); 125 if (slist_add(&_this->session_free_list, 126 (void *)PPPOED_SESSION_SHUFFLE_MARK) == NULL) { 127 pppoed_log(_this, LOG_ERR, "slist_add() failed on %s(): %m", 128 __func__); 129 goto fail; 130 } 131 132 /* XXX initialize hash of cookies */ 133 if ((_this->acookie_hash = hash_create( 134 (int (*) (const void *, const void *))session_id_cmp, 135 (uint32_t (*) (const void *, int))session_id_hash, 136 PPPOE_SESSION_HASH_SIZ)) == NULL) { 137 pppoed_log(_this, LOG_WARNING, 138 "hash_create() failed on %s(): %m", __func__); 139 pppoed_log(_this, LOG_WARNING, "hash_create() failed on %s(): " 140 "ac-cookie hash create failed.", __func__); 141 _this->acookie_hash = NULL; 142 } 143 _this->acookie_next = random(); 144 145 #if PPPOE_NSESSION > 0xffff 146 #error PPPOE_NSESSION must be less than 65536 147 #endif 148 off = random() % 0xffff; 149 for (i = 0; i < PPPOE_NSESSION; i++) { 150 id = (i + off) % 0xffff; 151 if (id == 0) 152 id = (off - 1) % 0xffff; 153 if (slist_add(&_this->session_free_list, (void *)(intptr_t)id) 154 == NULL) { 155 pppoed_log(_this, LOG_ERR, 156 "slist_add() failed on %s(): %m", __func__); 157 goto fail; 158 } 159 } 160 161 _this->state = PPPOED_STATE_INIT; 162 163 return 0; 164 fail: 165 pppoed_uninit(_this); 166 return 1; 167 } 168 169 static void 170 pppoed_listener_init(pppoed *_this, pppoed_listener *listener) 171 { 172 memset(listener, 0, sizeof(pppoed_listener)); 173 listener->bpf = -1; 174 listener->self = _this; 175 listener->index = PPPOED_LISTENER_INVALID_INDEX; 176 } 177 178 /* reload listner */ 179 int 180 pppoed_reload_listeners(pppoed *_this) 181 { 182 int rval = 0; 183 184 if (_this->state == PPPOED_STATE_RUNNING && 185 _this->listen_incomplete != 0) 186 rval = pppoed_start(_this); 187 188 return rval; 189 } 190 191 /* 192 * Reject any packet except the packet to self and broadcasts, 193 * as bpf(4) potentially receive packets for others. 194 */ 195 #define REJECT_FOREIGN_ADDRESS 1 196 197 #define ETHER_FIRST_INT(e) ((e)[0]<<24|(e)[1]<<16|(e)[2]<<8|(e)[3]) 198 #define ETHER_LAST_SHORT(e) ((e)[4]<<8|(e)[5]) 199 200 static int 201 pppoed_listener_start(pppoed_listener *_this, int restart) 202 { 203 int i; 204 int log_level; 205 char buf[BUFSIZ]; 206 struct ifreq ifreq; 207 int ival; 208 int found; 209 struct ifaddrs *ifa0, *ifa; 210 struct sockaddr_dl *sdl; 211 struct bpf_insn insns[] = { 212 /* check etyer type = PPPOEDESC or PPPOE */ 213 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), 214 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_PPPOEDISC, 2, 0), 215 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_PPPOE, 1, 0), 216 BPF_STMT(BPF_RET+BPF_K, (u_int)0), 217 #ifndef REJECT_FOREIGN_ADDRESS 218 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 219 #else 220 /* to ff:ff:ff:ff:ff:ff */ 221 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), 222 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xffffffff, 0, 3), 223 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), 224 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xffff, 0, 1), 225 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 226 /* to self */ 227 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), 228 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 229 ETHER_FIRST_INT(_this->ether_addr), 0, 3), 230 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), 231 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 232 ETHER_LAST_SHORT(_this->ether_addr), 0, 1), 233 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 234 BPF_STMT(BPF_RET+BPF_K, (u_int)0), 235 #endif 236 }; 237 struct bpf_program bf_filter = { 238 .bf_len = countof(insns), 239 .bf_insns = insns 240 }; 241 pppoed *_pppoed; 242 243 if (restart == 0) 244 log_level = LOG_ERR; 245 else 246 log_level = LOG_INFO; 247 248 _pppoed = _this->self; 249 250 ifa0 = NULL; 251 if (getifaddrs(&ifa0) != 0) { 252 pppoed_log(_pppoed, log_level, 253 "getifaddrs() failed on %s(): %m", __func__); 254 return -1; 255 } 256 found = 0; 257 for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { 258 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 259 if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER || 260 sdl->sdl_alen != ETHER_ADDR_LEN) 261 continue; 262 if (strcmp(ifa->ifa_name, _this->listen_ifname) == 0) { 263 memcpy(_this->ether_addr, 264 (caddr_t)LLADDR(sdl), ETHER_ADDR_LEN); 265 found = 1; 266 break; 267 } 268 } 269 freeifaddrs(ifa0); 270 if (!found) { 271 pppoed_log(_pppoed, log_level, "%s is not available.", 272 _this->listen_ifname); 273 goto fail; 274 } 275 276 /* Open /dev/bpfXX */ 277 /* FIXME: /dev/bpf of NetBSD3.0 can simultaneity open */ 278 for (i = 0; i < 256; i++) { 279 snprintf(buf, sizeof(buf), "/dev/bpf%d", i); 280 if ((_this->bpf = priv_open(buf, O_RDWR, 0600)) >= 0) { 281 break; 282 } else if (errno == ENXIO || errno == ENOENT) 283 break; /* no more entries */ 284 } 285 if (_this->bpf < 0) { 286 pppoed_log(_pppoed, log_level, "Cannot open bpf"); 287 goto fail; 288 } 289 290 ival = BPF_CAPTURE_SIZ; 291 if (ioctl(_this->bpf, BIOCSBLEN, &ival) != 0) { 292 pppoed_log(_pppoed, log_level, "ioctl(bpf, BIOCSBLEN(%d)): %m", 293 ival); 294 goto fail; 295 } 296 ival = 1; 297 if (ioctl(_this->bpf, BIOCIMMEDIATE, &ival) != 0) { 298 pppoed_log(_pppoed, log_level, "Cannot start bpf on %s: %m", 299 _this->listen_ifname); 300 goto fail; 301 } 302 303 /* bind interface */ 304 memset(&ifreq, 0, sizeof(ifreq)); 305 strlcpy(ifreq.ifr_name, _this->listen_ifname, sizeof(ifreq.ifr_name)); 306 if (ioctl(_this->bpf, BIOCSETIF, &ifreq) != 0) { 307 pppoed_log(_pppoed, log_level, "Cannot start bpf on %s: %m", 308 _this->listen_ifname); 309 goto fail; 310 } 311 312 /* set linklocal address */ 313 #ifdef REJECT_FOREIGN_ADDRESS 314 insns[10].k = ETHER_FIRST_INT(_this->ether_addr); 315 insns[12].k = ETHER_LAST_SHORT(_this->ether_addr); 316 #endif 317 318 /* set filter */ 319 if (ioctl(_this->bpf, BIOCSETF, &bf_filter) != 0) { 320 pppoed_log(_pppoed, log_level, "ioctl(bpf, BIOCSETF()): %m"); 321 goto fail; 322 } 323 324 event_set(&_this->ev_bpf, _this->bpf, EV_READ | EV_PERSIST, 325 pppoed_io_event, _this); 326 event_add(&_this->ev_bpf, NULL); 327 328 pppoed_log(_pppoed, LOG_INFO, "Listening on %s (PPPoE) [%s] using=%s " 329 "address=%02x:%02x:%02x:%02x:%02x:%02x", _this->listen_ifname, 330 _this->tun_name, buf, _this->ether_addr[0], _this->ether_addr[1], 331 _this->ether_addr[2], _this->ether_addr[3], _this->ether_addr[4], 332 _this->ether_addr[5]); 333 334 return 0; 335 fail: 336 if (_this->bpf >= 0) { 337 close(_this->bpf); 338 _this->bpf = -1; 339 } 340 341 return 1; 342 } 343 344 /* start PPPoE daemon */ 345 int 346 pppoed_start(pppoed *_this) 347 { 348 int rval = 0; 349 int nlistener_fail = 0; 350 pppoed_listener *plistener; 351 352 slist_itr_first(&_this->listener); 353 while (slist_itr_has_next(&_this->listener)) { 354 plistener = slist_itr_next(&_this->listener); 355 PPPOED_ASSERT(plistener != NULL); 356 if (plistener->bpf < 0) { 357 if (pppoed_listener_start(plistener, 358 _this->listen_incomplete) != 0) 359 nlistener_fail++; 360 } 361 } 362 if (nlistener_fail > 0) 363 _this->listen_incomplete = 1; 364 else 365 _this->listen_incomplete = 0; 366 367 _this->state = PPPOED_STATE_RUNNING; 368 369 return rval; 370 } 371 372 /* stop listener */ 373 static void 374 pppoed_listener_stop(pppoed_listener *_this) 375 { 376 pppoed *_pppoed; 377 378 PPPOED_ASSERT(_this != NULL); 379 _pppoed = _this->self; 380 PPPOED_ASSERT(_pppoed != NULL); 381 382 if (_this->bpf >= 0) { 383 event_del(&_this->ev_bpf); 384 close(_this->bpf); 385 pppoed_log(_pppoed, LOG_INFO, "Shutdown %s (PPPoE) [%s] " 386 "address=%02x:%02x:%02x:%02x:%02x:%02x", 387 _this->listen_ifname, _this->tun_name, 388 _this->ether_addr[0], _this->ether_addr[1], 389 _this->ether_addr[2], _this->ether_addr[3], 390 _this->ether_addr[4], _this->ether_addr[5]); 391 _this->bpf = -1; 392 } 393 } 394 395 /* stop PPPoE daemon */ 396 void 397 pppoed_stop(pppoed *_this) 398 { 399 pppoed_listener *plistener; 400 hash_link *hl; 401 pppoe_session *session; 402 403 if (!pppoed_is_running(_this)) 404 return; 405 406 _this->state = PPPOED_STATE_STOPPED; 407 if (_this->session_hash != NULL) { 408 for (hl = hash_first(_this->session_hash); 409 hl != NULL; 410 hl = hash_next(_this->session_hash)) { 411 session = (pppoe_session *)hl->item; 412 pppoe_session_disconnect(session); 413 pppoe_session_stop(session); 414 } 415 } 416 for (slist_itr_first(&_this->listener); 417 slist_itr_has_next(&_this->listener);) { 418 plistener = slist_itr_next(&_this->listener); 419 pppoed_listener_stop(plistener); 420 free(plistener); 421 slist_itr_remove(&_this->listener); 422 } 423 pppoed_log(_this, LOG_NOTICE, "Stopped"); 424 } 425 426 /* uninitialize (free) PPPoE daemon */ 427 void 428 pppoed_uninit(pppoed *_this) 429 { 430 if (_this->session_hash != NULL) { 431 hash_free(_this->session_hash); 432 _this->session_hash = NULL; 433 } 434 if (_this->acookie_hash != NULL) { 435 hash_free(_this->acookie_hash); 436 _this->acookie_hash = NULL; 437 } 438 slist_fini(&_this->session_free_list); 439 /* listener themself has been released already */ 440 slist_fini(&_this->listener); 441 } 442 443 /* it called when the PPPoE session was closed */ 444 void 445 pppoed_pppoe_session_close_notify(pppoed *_this, pppoe_session *session) 446 { 447 slist_add(&_this->session_free_list, 448 (void *)(intptr_t)session->session_id); 449 450 if (_this->acookie_hash != NULL) 451 hash_delete(_this->acookie_hash, 452 (void *)(intptr_t)session->acookie, 0); 453 if (_this->session_hash != NULL) 454 hash_delete(_this->session_hash, 455 (void *)(intptr_t)session->session_id, 0); 456 457 pppoe_session_fini(session); 458 free(session); 459 } 460 461 /* 462 * PPPoE Configuration 463 */ 464 /* reload configurations for the PPPoE daemon */ 465 int 466 pppoed_reload(pppoed *_this, struct pppoe_confs *pppoe_conf) 467 { 468 int i, count, do_start, found; 469 struct pppoe_conf *conf; 470 struct ifaddrs *ifa0; 471 slist rmlist, newlist; 472 struct { 473 char ifname[IF_NAMESIZE]; 474 char name[PPPOED_PHY_LABEL_SIZE]; 475 } listeners[PPPOE_NLISTENER]; 476 pppoed_listener *l; 477 pppoe_session *session; 478 hash_link *hl; 479 480 do_start = 0; 481 ifa0 = NULL; 482 slist_init(&rmlist); 483 slist_init(&newlist); 484 485 if (getifaddrs(&ifa0) != 0) { 486 pppoed_log(_this, LOG_ERR, 487 "getifaddrs() failed on %s(): %m", __func__); 488 goto fail; 489 } 490 count = 0; 491 TAILQ_FOREACH(conf, pppoe_conf, entry) { 492 strlcpy(listeners[count].ifname, conf->if_name, 493 sizeof(listeners[count].ifname)); 494 strlcpy(listeners[count].name, conf->name, 495 sizeof(listeners[count].name)); 496 count++; 497 } 498 499 if (slist_add_all(&rmlist, &_this->listener) != 0) 500 goto fail; 501 502 for (i = 0; i < count; i++) { 503 found = 0; 504 l = NULL; 505 slist_itr_first(&rmlist); 506 while (slist_itr_has_next(&rmlist)) { 507 l = slist_itr_next(&rmlist); 508 if (strcmp(l->listen_ifname, listeners[i].ifname) == 0){ 509 slist_itr_remove(&rmlist); 510 found = 1; 511 break; 512 } 513 } 514 if (!found) { 515 if ((l = malloc(sizeof(pppoed_listener))) == NULL) 516 goto fail; 517 pppoed_listener_init(_this, l); 518 } 519 l->self = _this; 520 strlcpy(l->tun_name, listeners[i].name, sizeof(l->tun_name)); 521 strlcpy(l->listen_ifname, listeners[i].ifname, 522 sizeof(l->listen_ifname)); 523 if (slist_add(&newlist, l) == NULL) { 524 pppoed_log(_this, LOG_ERR, 525 "slist_add() failed in %s(): %m", __func__); 526 goto fail; 527 } 528 } 529 530 if (slist_set_size(&_this->listener, count) != 0) 531 goto fail; 532 533 /* garbage collection of listner context */ 534 slist_itr_first(&rmlist); 535 while (slist_itr_has_next(&rmlist)) { 536 l = slist_itr_next(&rmlist); 537 /* handle child PPPoE session */ 538 if (_this->session_hash != NULL) { 539 for (hl = hash_first(_this->session_hash); hl != NULL; 540 hl = hash_next(_this->session_hash)) { 541 session = (pppoe_session *)hl->item; 542 if (session->listener_index == l->index) 543 pppoe_session_stop(session); 544 } 545 } 546 pppoed_listener_stop(l); 547 free(l); 548 } 549 slist_remove_all(&_this->listener); 550 /* as slist_set_size-ed, it must not fail */ 551 (void)slist_add_all(&_this->listener, &newlist); 552 553 /* reset indexes */ 554 slist_itr_first(&newlist); 555 for (i = 0; slist_itr_has_next(&newlist); i++) { 556 l = slist_itr_next(&newlist); 557 if (l->index != i && l->index != PPPOED_LISTENER_INVALID_INDEX){ 558 PPPOED_DBG((_this, LOG_DEBUG, "listener %d => %d", 559 l->index, i)); 560 for (hl = hash_first(_this->session_hash); hl != NULL; 561 hl = hash_next(_this->session_hash)) { 562 session = (pppoe_session *)hl->item; 563 if (session->listener_index == l->index) 564 session->listener_index = i; 565 } 566 } 567 l->index = i; 568 } 569 570 slist_fini(&rmlist); 571 slist_fini(&newlist); 572 if (ifa0 != NULL) 573 freeifaddrs(ifa0); 574 575 if (pppoed_start(_this) != 0) 576 return 1; 577 578 return 0; 579 fail: 580 slist_fini(&rmlist); 581 slist_fini(&newlist); 582 if (ifa0 != NULL) 583 freeifaddrs(ifa0); 584 585 return 1; 586 } 587 588 /* 589 * I/O 590 */ 591 592 static void 593 pppoed_io_event(int fd, short evmask, void *ctx) 594 { 595 u_char buf[BPF_CAPTURE_SIZ], *pkt; 596 int lpkt, off; 597 pppoed_listener *_this; 598 struct ether_header *ether; 599 struct bpf_hdr *bpf; 600 601 _this = ctx; 602 603 PPPOED_ASSERT(_this != NULL); 604 605 lpkt = read(_this->bpf, buf, sizeof(buf)); 606 pkt = buf; 607 while (lpkt > 0) { 608 if (lpkt < sizeof(struct bpf_hdr)) { 609 pppoed_log(_this->self, LOG_WARNING, 610 "Received bad PPPoE packet: packet too short(%d)", 611 lpkt); 612 break; 613 } 614 bpf = (struct bpf_hdr *)pkt; 615 ether = (struct ether_header *)(pkt + bpf->bh_hdrlen); 616 ether->ether_type = ntohs(ether->ether_type); 617 if (memcmp(ether->ether_shost, _this->ether_addr, 618 ETHER_ADDR_LEN) == 0) 619 /* the packet is from myself */ 620 goto next_pkt; 621 off = bpf->bh_hdrlen + sizeof(struct ether_header); 622 if (lpkt < off + sizeof(struct pppoe_header)) { 623 pppoed_log(_this->self, LOG_WARNING, 624 "Received bad PPPoE packet: packet too short(%d)", 625 lpkt); 626 break; 627 } 628 pppoed_input(_this, ether->ether_shost, 629 (ether->ether_type == ETHERTYPE_PPPOEDISC)? 1 : 0, 630 pkt + off, lpkt - off); 631 next_pkt: 632 pkt = pkt + BPF_WORDALIGN(bpf->bh_hdrlen + 633 bpf->bh_caplen); 634 lpkt -= BPF_WORDALIGN(bpf->bh_hdrlen + bpf->bh_caplen); 635 } 636 return; 637 } 638 639 static void 640 pppoed_input(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN], int is_disc, 641 u_char *pkt, int lpkt) 642 { 643 hash_link *hl; 644 pppoe_session *session; 645 struct pppoe_header *pppoe; 646 struct pppoe_tlv *tlv; 647 u_char tlvspace[2048], *p_tlvspace; 648 int session_id; 649 slist tag_list; 650 const char *reason; 651 #define tlvspace_remaining() (sizeof(tlvspace) - (p_tlvspace - tlvspace)) 652 653 reason = ""; 654 p_tlvspace = tlvspace; 655 session = NULL; 656 657 pppoe = (struct pppoe_header *)pkt; 658 session_id = pppoe->session_id = ntohs(pppoe->session_id); 659 pppoe->length = ntohs(pppoe->length); 660 661 #ifdef PPPOED_DEBUG 662 if (is_disc) { 663 PPPOED_DBG((_this->self, DEBUG_LEVEL_1, 664 "Recv%s(%02x) ver=%d type=%d session-id=%d if=%s", 665 pppoe_code_string(pppoe->code), pppoe->code, 666 pppoe->ver, pppoe->type, pppoe->session_id, 667 _this->listen_ifname)); 668 } 669 #endif 670 pkt += sizeof(struct pppoe_header); 671 lpkt -= sizeof(struct pppoe_header); 672 673 if (lpkt < pppoe->length) { 674 reason = "received packet is shorter than " 675 "pppoe length field."; 676 goto bad_packet; 677 } 678 /* use PPPoE heade value as lpkt */ 679 lpkt = pppoe->length; 680 681 if (pppoe->type != PPPOE_RFC2516_TYPE || 682 pppoe->ver != PPPOE_RFC2516_VER) { 683 reason = "received packet has wrong version or type."; 684 goto bad_packet; 685 } 686 687 if (session_id != 0) { 688 hl = hash_lookup(_this->self->session_hash, 689 (void *)(intptr_t)session_id); 690 if (hl != NULL) 691 session = (pppoe_session *)hl->item; 692 } 693 if (!is_disc) { 694 if (session != NULL) 695 pppoe_session_input(session, pkt, pppoe->length); 696 return; 697 } 698 699 /* 700 * PPPoE-Discovery Packet proccessing. 701 */ 702 slist_init(&tag_list); 703 while (lpkt > 0) { 704 if (lpkt < 4) { 705 reason = "tlv list is broken. " 706 "Remaining octet is too short."; 707 goto fail; 708 } 709 if (tlvspace_remaining() < 4) { 710 reason = "parsing TAGs reached the buffer size limit."; 711 goto fail; 712 } 713 tlv = (struct pppoe_tlv *)p_tlvspace; 714 GETSHORT(tlv->type, pkt); 715 GETSHORT(tlv->length, pkt); 716 p_tlvspace += 4; 717 lpkt -= 4; 718 if (tlv->length > lpkt) { 719 reason = "tlv list is broken. length is wrong."; 720 goto fail; 721 } 722 if (tlvspace_remaining() < tlv->length) { 723 reason = "parsing TAGs reached the buffer size limit."; 724 goto fail; 725 } 726 if (tlv->length > 0) { 727 memcpy(tlv->value, pkt, tlv->length); 728 pkt += tlv->length; 729 lpkt -= tlv->length; 730 p_tlvspace += tlv->length; 731 p_tlvspace = (u_char *)ALIGN(p_tlvspace); 732 } 733 #ifdef PPPOED_DEBUG 734 if (debuglevel >= 2) 735 pppoed_log(_this->self, DEBUG_LEVEL_2, 736 "Recv%s tag %s(%04x)=%s", 737 pppoe_code_string(pppoe->code), 738 pppoe_tag_string(tlv->type), tlv->type, 739 pppoed_tlv_value_string(tlv)); 740 #endif 741 if (tlv->type == PPPOE_TAG_END_OF_LIST) 742 break; 743 if (slist_add(&tag_list, tlv) == NULL) { 744 goto fail; 745 } 746 } 747 switch (pppoe->code) { 748 case PPPOE_CODE_PADI: 749 if (_this->self->state != PPPOED_STATE_RUNNING) 750 break; 751 pppoed_recv_PADI(_this, shost, &tag_list); 752 break; 753 case PPPOE_CODE_PADR: 754 if (_this->self->state != PPPOED_STATE_RUNNING) 755 break; 756 pppoed_recv_PADR(_this, shost, &tag_list); 757 break; 758 case PPPOE_CODE_PADT: 759 PPPOED_DBG((_this->self, LOG_DEBUG, "RecvPADT")); 760 if (session != NULL) 761 pppoe_session_recv_PADT(session, &tag_list); 762 break; 763 } 764 slist_fini(&tag_list); 765 766 return; 767 fail: 768 slist_fini(&tag_list); 769 bad_packet: 770 pppoed_log(_this->self, LOG_INFO, 771 "Received a bad packet: code=%s(%02x) ver=%d type=%d session-id=%d" 772 " if=%s: %s", pppoe_code_string(pppoe->code), pppoe->code, 773 pppoe->ver, pppoe->type, pppoe->session_id, _this->listen_ifname, 774 reason); 775 } 776 777 static int 778 pppoed_output(pppoed_listener *_this, u_char *dhost, u_char *pkt, int lpkt) 779 { 780 int sz, iovc; 781 struct iovec iov[3]; 782 struct ether_header ether; 783 struct pppoe_header *pppoe; 784 u_char pad[ETHERMIN]; 785 786 memcpy(ether.ether_dhost, dhost, ETHER_ADDR_LEN); 787 memcpy(ether.ether_shost, _this->ether_addr, ETHER_ADDR_LEN); 788 789 iov[0].iov_base = ðer; 790 iov[0].iov_len = sizeof(struct ether_header); 791 ether.ether_type = htons(ETHERTYPE_PPPOEDISC); 792 iov[1].iov_base = pkt; 793 iov[1].iov_len = lpkt; 794 pppoe = (struct pppoe_header *)pkt; 795 pppoe->length = htons(lpkt - sizeof(struct pppoe_header)); 796 797 iovc = 2; 798 799 if (lpkt < ETHERMIN) { 800 memset(pad, 0, ETHERMIN - lpkt); 801 iov[2].iov_base = pad; 802 iov[2].iov_len = ETHERMIN - lpkt; 803 iovc++; 804 } 805 806 sz = writev(_this->bpf, iov, iovc); 807 808 return (sz > 0)? 0 : -1; 809 } 810 811 static void 812 pppoed_recv_PADR(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN], 813 slist *tag_list) 814 { 815 int session_id, shuffle_cnt; 816 pppoe_session *session; 817 pppoed *_pppoed; 818 819 _pppoed = _this->self; 820 if ((session = malloc(sizeof(pppoe_session))) == NULL) { 821 pppoed_log(_pppoed, LOG_ERR, "malloc() failed on %s(): %m", 822 __func__); 823 goto fail; 824 } 825 826 /* create session_id */ 827 shuffle_cnt = 0; 828 do { 829 session_id = (intptr_t)slist_remove_first( 830 &_pppoed->session_free_list); 831 if (session_id != PPPOED_SESSION_SHUFFLE_MARK) 832 break; 833 PPPOED_ASSERT(shuffle_cnt == 0); 834 if (shuffle_cnt++ > 0) { 835 pppoed_log(_pppoed, LOG_ERR, 836 "unexpected errror in %s(): session_free_list full", 837 __func__); 838 slist_add(&_pppoed->session_free_list, 839 (void *)PPPOED_SESSION_SHUFFLE_MARK); 840 goto fail; 841 } 842 slist_shuffle(&_pppoed->session_free_list); 843 slist_add(&_pppoed->session_free_list, 844 (void *)PPPOED_SESSION_SHUFFLE_MARK); 845 } while (1); 846 847 if (pppoe_session_init(session, _pppoed, _this->index, session_id, 848 shost) != 0) 849 goto fail; 850 851 hash_insert(_pppoed->session_hash, (void *)(intptr_t)session_id, 852 session); 853 854 if (pppoe_session_recv_PADR(session, tag_list) != 0) 855 goto fail; 856 857 session = NULL; /* don't free */ 858 /* FALLTHROUGH */ 859 fail: 860 if (session != NULL) 861 pppoe_session_fini(session); 862 return; 863 } 864 865 static void 866 pppoed_recv_PADI(pppoed_listener *_this, uint8_t shost[ETHER_ADDR_LEN], 867 slist *tag_list) 868 { 869 int len; 870 const char *service_name, *ac_name; 871 u_char bufspace[2048]; 872 u_char sn[2048], ac_name0[40]; 873 struct pppoe_header pppoe; 874 struct pppoe_tlv tlv, *tlv_hostuniq, *tlv0, *tlv_service_name; 875 bytebuffer *buf; 876 877 if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL) { 878 pppoed_log(_this->self, LOG_ERR, 879 "bytebuffer_wrap() failed on %s(): %m", __func__); 880 return; 881 } 882 bytebuffer_clear(buf); 883 884 tlv_hostuniq = NULL; 885 tlv_service_name = NULL; 886 887 service_name = ""; 888 if (_this->conf->service_name != NULL) 889 service_name = _this->conf->service_name; 890 891 for (slist_itr_first(tag_list); slist_itr_has_next(tag_list);) { 892 tlv0 = slist_itr_next(tag_list); 893 if (tlv0->type == PPPOE_TAG_HOST_UNIQ) 894 tlv_hostuniq = tlv0; 895 if (tlv0->type == PPPOE_TAG_SERVICE_NAME) { 896 897 len = tlv0->length; 898 if (len >= sizeof(sn)) 899 goto fail; 900 901 memcpy(sn, tlv0->value, len); 902 sn[len] = '\0'; 903 904 if (strcmp(service_name, sn) == 0 || 905 (sn[0] == '\0' && _this->conf->accept_any_service)) 906 tlv_service_name = tlv0; 907 } 908 } 909 if (tlv_service_name == NULL) { 910 pppoed_log(_this->self, LOG_INFO, 911 "Deny PADI from=%02x:%02x:%02x:%02x:%02x:%02x " 912 "service-name=%s host-uniq=%s if=%s: serviceName is " 913 "not allowed.", shost[0], shost[1], 914 shost[2], shost[3], shost[4], shost[5], sn, tlv_hostuniq? 915 pppoed_tlv_value_string(tlv_hostuniq) : "none", 916 _this->listen_ifname); 917 goto fail; 918 } 919 920 pppoed_log(_this->self, LOG_INFO, 921 "RecvPADI from=%02x:%02x:%02x:%02x:%02x:%02x service-name=%s " 922 "host-uniq=%s if=%s", shost[0], shost[1], shost[2], shost[3], 923 shost[4], shost[5], sn, tlv_hostuniq? 924 pppoed_tlv_value_string(tlv_hostuniq) : "none", 925 _this->listen_ifname); 926 927 /* 928 * PPPoE Header 929 */ 930 memset(&pppoe, 0, sizeof(pppoe)); 931 pppoe.ver = PPPOE_RFC2516_VER; 932 pppoe.type = PPPOE_RFC2516_TYPE; 933 pppoe.code = PPPOE_CODE_PADO; 934 bytebuffer_put(buf, &pppoe, sizeof(pppoe)); 935 936 /* 937 * Tag - Service-Name 938 */ 939 tlv.type = htons(PPPOE_TAG_SERVICE_NAME); 940 len = strlen(service_name); 941 tlv.length = htons(len); 942 bytebuffer_put(buf, &tlv, sizeof(tlv)); 943 if (len > 0) 944 bytebuffer_put(buf, service_name, len); 945 946 /* 947 * Tag - Access Concentrator Name 948 */ 949 ac_name = _this->conf->ac_name; 950 if (ac_name == NULL) { 951 /* 952 * use the ethernet address as default AC-Name. 953 * suggested by RFC 2516. 954 */ 955 snprintf(ac_name0, sizeof(ac_name0), 956 "%02x:%02x:%02x:%02x:%02x:%02x", _this->ether_addr[0], 957 _this->ether_addr[1], _this->ether_addr[2], 958 _this->ether_addr[3], _this->ether_addr[4], 959 _this->ether_addr[5]); 960 ac_name = ac_name0; 961 } 962 963 tlv.type = htons(PPPOE_TAG_AC_NAME); 964 len = strlen(ac_name); 965 tlv.length = htons(len); 966 bytebuffer_put(buf, &tlv, sizeof(tlv)); 967 bytebuffer_put(buf, ac_name, len); 968 969 /* 970 * Tag - ac-cookie 971 */ 972 if (_this->self->acookie_hash != NULL) { 973 /* 974 * search next ac-cookie. 975 * (XXX it will loop in uint32_t boundaly) 976 */ 977 do { 978 _this->self->acookie_next += 1; 979 } 980 while(hash_lookup(_this->self->acookie_hash, 981 (void *)(intptr_t)_this->self->acookie_next) != NULL); 982 983 tlv.type = htons(PPPOE_TAG_AC_COOKIE); 984 tlv.length = ntohs(sizeof(uint32_t)); 985 bytebuffer_put(buf, &tlv, sizeof(tlv)); 986 bytebuffer_put(buf, &_this->self->acookie_next, 987 sizeof(uint32_t)); 988 } 989 990 /* 991 * Tag - Host-Uniq 992 */ 993 if (tlv_hostuniq != NULL) { 994 tlv.type = htons(PPPOE_TAG_HOST_UNIQ); 995 tlv.length = ntohs(tlv_hostuniq->length); 996 bytebuffer_put(buf, &tlv, sizeof(tlv)); 997 bytebuffer_put(buf, tlv_hostuniq->value, 998 tlv_hostuniq->length); 999 } 1000 1001 /* 1002 * Tag - End-Of-List 1003 */ 1004 tlv.type = htons(PPPOE_TAG_END_OF_LIST); 1005 tlv.length = ntohs(0); 1006 bytebuffer_put(buf, &tlv, sizeof(tlv)); 1007 1008 bytebuffer_flip(buf); 1009 1010 if (pppoed_output(_this, shost, bytebuffer_pointer(buf), 1011 bytebuffer_remaining(buf)) != 0) { 1012 pppoed_log(_this->self, LOG_ERR, "pppoed_output() failed:%m"); 1013 } 1014 pppoed_log(_this->self, LOG_INFO, 1015 "SendPADO to=%02x:%02x:%02x:%02x:%02x:%02x serviceName=%s " 1016 "acName=%s hostUniq=%s eol if=%s", shost[0], shost[1], shost[2], 1017 shost[3], shost[4], shost[5], service_name, ac_name, 1018 tlv_hostuniq? pppoed_tlv_value_string(tlv_hostuniq) : "none", 1019 _this->listen_ifname); 1020 /* FALLTHROUGH */ 1021 fail: 1022 bytebuffer_unwrap(buf); 1023 bytebuffer_destroy(buf); 1024 } 1025 1026 /* 1027 * log 1028 */ 1029 static void 1030 pppoed_log(pppoed *_this, int prio, const char *fmt, ...) 1031 { 1032 char logbuf[BUFSIZ]; 1033 va_list ap; 1034 1035 PPPOED_ASSERT(_this != NULL); 1036 va_start(ap, fmt); 1037 #ifdef PPPOED_MULTIPLE 1038 snprintf(logbuf, sizeof(logbuf), "pppoed id=%u %s", _this->id, fmt); 1039 #else 1040 snprintf(logbuf, sizeof(logbuf), "pppoed %s", fmt); 1041 #endif 1042 vlog_printf(prio, logbuf, ap); 1043 va_end(ap); 1044 } 1045 1046 #define NAME_VAL(x) { x, #x } 1047 static struct _label_name { 1048 int label; 1049 const char *name; 1050 } pppoe_code_labels[] = { 1051 NAME_VAL(PPPOE_CODE_PADI), 1052 NAME_VAL(PPPOE_CODE_PADO), 1053 NAME_VAL(PPPOE_CODE_PADR), 1054 NAME_VAL(PPPOE_CODE_PADS), 1055 NAME_VAL(PPPOE_CODE_PADT), 1056 #ifdef PPPOED_DEBUG 1057 }, pppoe_tlv_labels[] = { 1058 NAME_VAL(PPPOE_TAG_END_OF_LIST), 1059 NAME_VAL(PPPOE_TAG_SERVICE_NAME), 1060 NAME_VAL(PPPOE_TAG_AC_NAME), 1061 NAME_VAL(PPPOE_TAG_HOST_UNIQ), 1062 NAME_VAL(PPPOE_TAG_AC_COOKIE), 1063 NAME_VAL(PPPOE_TAG_VENDOR_SPECIFIC), 1064 NAME_VAL(PPPOE_TAG_RELAY_SESSION_ID), 1065 NAME_VAL(PPPOE_TAG_SERVICE_NAME_ERROR), 1066 NAME_VAL(PPPOE_TAG_AC_SYSTEM_ERROR), 1067 NAME_VAL(PPPOE_TAG_GENERIC_ERROR) 1068 #endif 1069 }; 1070 #define LABEL_TO_STRING(func_name, label_names, prefix_len) \ 1071 static const char * \ 1072 func_name(int code) \ 1073 { \ 1074 int i; \ 1075 \ 1076 for (i = 0; i < countof(label_names); i++) { \ 1077 if (label_names[i].label == code) \ 1078 return label_names[i].name + prefix_len;\ 1079 } \ 1080 \ 1081 return "UNKNOWN"; \ 1082 } 1083 LABEL_TO_STRING(pppoe_code_string, pppoe_code_labels, 11) 1084 #ifdef PPPOED_DEBUG 1085 LABEL_TO_STRING(pppoe_tag_string, pppoe_tlv_labels, 10) 1086 #endif 1087 1088 const char * 1089 pppoed_tlv_value_string(struct pppoe_tlv *tlv) 1090 { 1091 int i; 1092 char buf[3]; 1093 static char _tlv_string_value[8192]; 1094 1095 _tlv_string_value[0] = '\0'; 1096 for (i = 0; i < tlv->length; i++) { 1097 snprintf(buf, sizeof(buf), "%02x", tlv->value[i]); 1098 strlcat(_tlv_string_value, buf, 1099 sizeof(_tlv_string_value)); 1100 } 1101 return _tlv_string_value; 1102 } 1103 1104 /* 1105 * misc 1106 */ 1107 static int 1108 session_id_cmp(void *a, void *b) 1109 { 1110 int ia, ib; 1111 1112 ia = (intptr_t)a; 1113 ib = (intptr_t)b; 1114 1115 return ib - ia; 1116 } 1117 1118 static uint32_t 1119 session_id_hash(void *a, size_t siz) 1120 { 1121 int ia; 1122 1123 ia = (intptr_t)a; 1124 1125 return ia % siz; 1126 } 1127