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