1 /* $NetBSD: pppoectl.c,v 1.32 2026/07/28 07:28:02 yamaguchi Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Joerg Wunsch 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * From: spppcontrol.c,v 1.3 1998/01/07 07:55:26 charnier Exp 29 * From: ispppcontrol 30 */ 31 #include <sys/cdefs.h> 32 33 #ifndef lint 34 __RCSID("$NetBSD: pppoectl.c,v 1.32 2026/07/28 07:28:02 yamaguchi Exp $"); 35 #endif 36 37 38 #include <sys/param.h> 39 #include <sys/callout.h> 40 #include <sys/ioctl.h> 41 #include <sys/socket.h> 42 #include <sys/time.h> 43 #include <sys/sysctl.h> 44 #include <net/if.h> 45 #include <net/if_sppp.h> 46 #include <net/if_pppoe.h> 47 #include <arpa/inet.h> 48 #include <err.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <sysexits.h> 53 #include <unistd.h> 54 #ifdef SPPP_FILTER 55 #include <pcap.h> 56 #endif 57 58 __dead static void usage(void); 59 __dead static void print_error(const char *ifname, int error, const char * str); 60 static void print_vals(const char *ifname, int phase, struct spppauthcfg *sp, 61 int lcp_timeout, time_t idle_timeout, int authfailures, 62 int max_auth_failures, u_int maxalive, time_t max_noreceive, 63 u_int alive_interval, int ncp_flags); 64 static void print_dns(const char *ifname, int dns1, int dns2, int s, int tabs); 65 static void print_stats(const char *ifname, int s, int dump); 66 static const char *phase_name(int phase); 67 static const char *proto_name(int proto); 68 static const char *authflags(int flags); 69 static const char *pppoe_state_name(int state); 70 static const char *ppp_state_name(int state); 71 static void pppoectl_argument(char *arg); 72 #ifdef SPPP_FILTER 73 static void set_spppfilter(struct spppfilter *, const char *, const char *); 74 #endif 75 76 #define ISSET(x, a) ((x) & (a)) 77 #define PPPOECTL_IOCTL(_ifname, _s, _cmd, _st) do { \ 78 int __e; \ 79 memset((_st), 0, sizeof(*(_st))); \ 80 strncpy((_st)->ifname, (_ifname), \ 81 sizeof((_st)->ifname)); \ 82 __e = ioctl((_s), (_cmd), (_st)); \ 83 if (__e != 0) \ 84 print_error((_ifname), __e, #_cmd); \ 85 } while (0) 86 87 static int hz = 0; 88 89 static int set_auth, set_lcp, set_idle_to, set_auth_failure, set_dns, 90 clear_auth_failure_count, set_keepalive; 91 static u_int set_ncpflags, clr_ncpflags; 92 static int maxalive = -1; 93 static int max_noreceive = -1; 94 static int alive_intval = -1; 95 static struct spppauthcfg spr; 96 static struct sppplcpcfg lcp; 97 static struct spppncpcfg ncp; 98 static struct spppstatus status; 99 static struct spppidletimeout timeout; 100 static struct spppauthfailurestats authfailstats; 101 static struct spppauthfailuresettings authfailset; 102 static struct spppdnssettings dnssettings; 103 static struct spppkeepalivesettings keepalivesettings; 104 #ifdef SPPP_FILTER 105 static struct spppfilter spppfilter; 106 static const char *filter_dialing = NULL; 107 static const char *filter_active_in = NULL; 108 static const char *filter_active_out = NULL; 109 #endif 110 111 int 112 main(int argc, char **argv) 113 { 114 FILE *fp; 115 int s, c; 116 int errs = 0, verbose = 0, dump = 0, dns1 = 0, dns2 = 0; 117 size_t len; 118 const char *eth_if_name, *access_concentrator, *service; 119 const char *ifname, *configname; 120 char *line; 121 int mib[2]; 122 struct clockinfo clockinfo; 123 setprogname(argv[0]); 124 125 eth_if_name = NULL; 126 access_concentrator = NULL; 127 service = NULL; 128 configname = NULL; 129 while ((c = getopt(argc, argv, "vde:f:s:a:n:")) != -1) 130 switch (c) { 131 case 'v': 132 verbose++; 133 break; 134 135 case 'd': 136 dump++; 137 break; 138 139 case 'e': 140 eth_if_name = optarg; 141 break; 142 143 case 'f': 144 configname = optarg; 145 break; 146 147 case 's': 148 service = optarg; 149 break; 150 151 case 'a': 152 access_concentrator = optarg; 153 break; 154 155 case 'n': 156 if (strcmp(optarg, "1") == 0) 157 dns1 = 1; 158 else if (strcmp(optarg, "2") == 0) 159 dns2 = 1; 160 else { 161 fprintf(stderr, "bad argument \"%s\" to -n (only 1 or two allowed)\n", 162 optarg); 163 errs++; 164 } 165 break; 166 167 default: 168 errs++; 169 break; 170 } 171 argv += optind; 172 argc -= optind; 173 174 if (errs || argc < 1) 175 usage(); 176 177 ifname = argv[0]; 178 179 /* use a random AF to create the socket */ 180 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 181 err(EX_UNAVAILABLE, "ifconfig: socket"); 182 183 argc--; 184 argv++; 185 186 if (eth_if_name) { 187 struct pppoediscparms parms; 188 int e; 189 190 memset(&parms, 0, sizeof parms); 191 strncpy(parms.ifname, ifname, sizeof(parms.ifname)); 192 strncpy(parms.eth_ifname, eth_if_name, sizeof(parms.eth_ifname)); 193 if (access_concentrator) { 194 parms.ac_name = access_concentrator; 195 parms.ac_name_len = strlen(access_concentrator); 196 } 197 if (service) { 198 parms.service_name = service; 199 parms.service_name_len = strlen(service); 200 } 201 202 e = ioctl(s, PPPOESETPARMS, &parms); 203 if (e) 204 print_error(ifname, e, "PPPOESETPARMS"); 205 return 0; 206 } 207 208 if (dns1 || dns2) { 209 print_dns(ifname, dns1, dns2, s, 0); 210 } 211 212 if (dump) { 213 print_stats(ifname, s, dump); 214 return 0; 215 } 216 217 memset(&spr, 0, sizeof spr); 218 strncpy(spr.ifname, ifname, sizeof spr.ifname); 219 spr.myauth = SPPP_AUTHPROTO_NOCHG; 220 spr.hisauth = SPPP_AUTHPROTO_NOCHG; 221 memset(&lcp, 0, sizeof lcp); 222 strncpy(lcp.ifname, ifname, sizeof lcp.ifname); 223 memset(&ncp, 0, sizeof ncp); 224 strncpy(ncp.ifname, ifname, sizeof ncp.ifname); 225 memset(&status, 0, sizeof status); 226 strncpy(status.ifname, ifname, sizeof status.ifname); 227 memset(&timeout, 0, sizeof timeout); 228 strncpy(timeout.ifname, ifname, sizeof timeout.ifname); 229 memset(&authfailstats, 0, sizeof authfailstats); 230 strncpy(authfailstats.ifname, ifname, sizeof authfailstats.ifname); 231 memset(&authfailset, 0, sizeof authfailset); 232 strncpy(authfailset.ifname, ifname, sizeof authfailset.ifname); 233 memset(&dnssettings, 0, sizeof dnssettings); 234 strncpy(dnssettings.ifname, ifname, sizeof dnssettings.ifname); 235 memset(&keepalivesettings, 0, sizeof keepalivesettings); 236 strncpy(keepalivesettings.ifname, ifname, sizeof keepalivesettings.ifname); 237 #ifdef SPPP_FILTER 238 memset(&spppfilter, 0, sizeof spppfilter); 239 strlcpy(spppfilter.ifname, ifname, sizeof spppfilter.ifname); 240 #endif 241 242 mib[0] = CTL_KERN; 243 mib[1] = KERN_CLOCKRATE; 244 len = sizeof(clockinfo); 245 if(sysctl(mib, 2, &clockinfo, &len, NULL, 0) == -1) 246 { 247 fprintf(stderr, "error, cannot sysctl kern.clockrate!\n"); 248 exit(1); 249 } 250 251 hz = clockinfo.hz; 252 253 if (argc == 0 && !(dns1||dns2) && !configname) { 254 /* list only mode */ 255 256 /* first pass, get name lengths */ 257 if (ioctl(s, SPPPGETAUTHCFG, &spr) == -1) 258 err(EX_OSERR, "SPPPGETAUTHCFG"); 259 /* now allocate buffers for strings */ 260 if (spr.myname_length) 261 if ((spr.myname = malloc(spr.myname_length)) == NULL) 262 err(1, NULL); 263 if (spr.hisname_length) 264 if ((spr.hisname = malloc(spr.hisname_length)) == NULL) 265 err(1, NULL); 266 /* second pass: get names too */ 267 if (ioctl(s, SPPPGETAUTHCFG, &spr) == -1) 268 err(EX_OSERR, "SPPPGETAUTHCFG"); 269 270 if (ioctl(s, SPPPGETLCPCFG, &lcp) == -1) 271 err(EX_OSERR, "SPPPGETLCPCFG"); 272 if (ioctl(s, SPPPGETNCPCFG, &ncp) == -1) 273 err(EX_OSERR, "SPPPGETNCPCFG"); 274 if (ioctl(s, SPPPGETSTATUS, &status) == -1) 275 err(EX_OSERR, "SPPPGETSTATUS"); 276 if (ioctl(s, SPPPGETIDLETO, &timeout) == -1) 277 err(EX_OSERR, "SPPPGETIDLETO"); 278 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 279 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 280 if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1) 281 err(EX_OSERR, "SPPPGETKEEPALIVE"); 282 283 print_vals(ifname, status.phase, &spr, lcp.lcp_timeout, 284 timeout.idle_seconds, authfailstats.auth_failures, 285 authfailstats.max_failures, 286 keepalivesettings.maxalive, 287 keepalivesettings.max_noreceive, 288 keepalivesettings.alive_interval, 289 ncp.ncp_flags); 290 291 if (spr.hisname) free(spr.hisname); 292 if (spr.myname) free(spr.myname); 293 return 0; 294 } 295 296 /* first load the config file, then parse command line args */ 297 if (configname && (fp = fopen(configname, "r"))) 298 while ((line = fparseln(fp, NULL, NULL, NULL, 299 FPARSELN_UNESCALL)) != NULL) { 300 if (line[0] != '\0') 301 pppoectl_argument(line); 302 /* 303 * We do not free(line) here, because we 304 * still have references to parts of the 305 * string collected in the various ioctl 306 * argument structures (and need those). 307 * Yes, this is a memory leak. 308 * We could copy the partial strings instead, 309 * and free those later - but this is a one-shot 310 * program and memory will be freed at process 311 * exit time anyway. 312 */ 313 } 314 315 316 while (argc > 0) { 317 pppoectl_argument(argv[0]); 318 319 argv++; 320 argc--; 321 } 322 323 if (set_auth) { 324 if (ioctl(s, SPPPSETAUTHCFG, &spr) == -1) 325 err(EX_OSERR, "SPPPSETAUTHCFG"); 326 } 327 if (set_lcp) { 328 if (ioctl(s, SPPPSETLCPCFG, &lcp) == -1) 329 err(EX_OSERR, "SPPPSETLCPCFG"); 330 } 331 if (set_ncpflags != 0 || clr_ncpflags != 0) { 332 if (ioctl(s, SPPPGETNCPCFG, &ncp) == -1) 333 err(EX_OSERR, "SPPPGETNCPCFG"); 334 335 ncp.ncp_flags |= set_ncpflags; 336 ncp.ncp_flags &= ~clr_ncpflags; 337 338 if (ioctl(s, SPPPSETNCPCFG, &ncp) == -1) 339 err(EX_OSERR, "SPPPSETNCPCFG"); 340 } 341 if (set_idle_to) { 342 if (ioctl(s, SPPPSETIDLETO, &timeout) == -1) 343 err(EX_OSERR, "SPPPSETIDLETO"); 344 } 345 if (set_auth_failure) { 346 if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1) 347 err(EX_OSERR, "SPPPSETAUTHFAILURE"); 348 } 349 if (clear_auth_failure_count && !(set_auth || set_auth_failure)) { 350 /* 351 * We want to clear the auth failure count, but did not 352 * do that implicitly by setting authentication - so 353 * do a zero-effect auth setting change 354 */ 355 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 356 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 357 authfailset.max_failures = authfailstats.max_failures; 358 if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1) 359 err(EX_OSERR, "SPPPSETAUTHFAILURE"); 360 } 361 if (set_dns) { 362 if (ioctl(s, SPPPSETDNSOPTS, &dnssettings) == -1) 363 err(EX_OSERR, "SPPPSETDNSOPTS"); 364 } 365 if (set_keepalive) { 366 if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1) 367 err(EX_OSERR, "SPPPGETKEEPALIVE"); 368 if (max_noreceive >= 0) 369 keepalivesettings.max_noreceive = max_noreceive; 370 if (maxalive >= 0) 371 keepalivesettings.maxalive = maxalive; 372 if (alive_intval >= 0) 373 keepalivesettings.alive_interval = alive_intval; 374 if (ioctl(s, SPPPSETKEEPALIVE, &keepalivesettings) == -1) 375 err(EX_OSERR, "SPPPSETKEEPALIVE"); 376 } 377 378 #ifdef SPPP_FILTER 379 if (filter_dialing != NULL) { 380 const char *cmdstr = "SPPPIOCSDIALFILT"; 381 set_spppfilter(&spppfilter, filter_dialing, cmdstr); 382 if (ioctl(s, SPPPIOCSDIALFILT, &spppfilter) == -1) 383 err(EX_OSERR, "%s", cmdstr); 384 } 385 if (filter_active_in != NULL) { 386 const char *cmdstr = "SPPPIOCSIACTIVE"; 387 set_spppfilter(&spppfilter, filter_active_in, cmdstr); 388 if (ioctl(s, SPPPIOCSIACTIVE, &spppfilter) == -1) 389 err(EX_OSERR, "%s", cmdstr); 390 } 391 if (filter_active_out != NULL) { 392 const char *cmdstr = "SPPPIOCSOACTIVE"; 393 set_spppfilter(&spppfilter, filter_active_out, cmdstr); 394 if (ioctl(s, SPPPIOCSOACTIVE, &spppfilter) == -1) 395 err(EX_OSERR, "%s", cmdstr); 396 } 397 #endif 398 399 if (verbose) { 400 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 401 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 402 if (ioctl(s, SPPPGETKEEPALIVE, &keepalivesettings) == -1) 403 err(EX_OSERR, "SPPPGETKEEPALIVE"); 404 print_vals(ifname, status.phase, &spr, lcp.lcp_timeout, 405 timeout.idle_seconds, authfailstats.auth_failures, 406 authfailstats.max_failures, 407 keepalivesettings.maxalive, 408 keepalivesettings.max_noreceive, 409 keepalivesettings.alive_interval, 410 ncp.ncp_flags); 411 } 412 413 return 0; 414 } 415 416 static void 417 pppoectl_argument(char *arg) 418 { 419 size_t off; 420 const char *cp; 421 422 #define startswith(a,s) strncmp(a, s, (off = strlen(s))) == 0 423 if (startswith(arg, "authproto=")) { 424 cp = arg + off; 425 if (strcmp(cp, "pap") == 0) 426 spr.myauth = 427 spr.hisauth = SPPP_AUTHPROTO_PAP; 428 else if (strcmp(cp, "chap") == 0) 429 spr.myauth = spr.hisauth = SPPP_AUTHPROTO_CHAP; 430 else if (strcmp(cp, "none") == 0) 431 spr.myauth = spr.hisauth = SPPP_AUTHPROTO_NONE; 432 else 433 errx(EX_DATAERR, "bad auth proto: %s", cp); 434 set_auth = 1; 435 } else if (startswith(arg, "myauthproto=")) { 436 cp = arg + off; 437 if (strcmp(cp, "pap") == 0) 438 spr.myauth = SPPP_AUTHPROTO_PAP; 439 else if (strcmp(cp, "chap") == 0) 440 spr.myauth = SPPP_AUTHPROTO_CHAP; 441 else if (strcmp(cp, "none") == 0) 442 spr.myauth = SPPP_AUTHPROTO_NONE; 443 else 444 errx(EX_DATAERR, "bad auth proto: %s", cp); 445 set_auth = 1; 446 } else if (startswith(arg, "myauthname=")) { 447 spr.myname = arg + off; 448 spr.myname_length = strlen(spr.myname)+1; 449 set_auth = 1; 450 } else if (startswith(arg, "myauthsecret=") || startswith(arg, "myauthkey=")) { 451 spr.mysecret = arg + off; 452 spr.mysecret_length = strlen(spr.mysecret)+1; 453 set_auth = 1; 454 } else if (startswith(arg, "hisauthproto=")) { 455 cp = arg + off; 456 if (strcmp(cp, "pap") == 0) 457 spr.hisauth = SPPP_AUTHPROTO_PAP; 458 else if (strcmp(cp, "chap") == 0) 459 spr.hisauth = SPPP_AUTHPROTO_CHAP; 460 else if (strcmp(cp, "none") == 0) 461 spr.hisauth = SPPP_AUTHPROTO_NONE; 462 else 463 errx(EX_DATAERR, "bad auth proto: %s", cp); 464 set_auth = 1; 465 } else if (startswith(arg, "hisauthname=")) { 466 spr.hisname = arg + off; 467 spr.hisname_length = strlen(spr.hisname)+1; 468 set_auth = 1; 469 } else if (startswith(arg, "hisauthsecret=") || startswith(arg, "hisauthkey=")) { 470 spr.hissecret = arg + off; 471 spr.hissecret_length = strlen(spr.hissecret)+1; 472 set_auth = 1; 473 } else if (startswith(arg, "max-noreceive=")) { 474 max_noreceive = atoi(arg+off); 475 if (max_noreceive < 0) { 476 fprintf(stderr, 477 "max-noreceive value must be at least 0\n"); 478 max_noreceive = -1; 479 } else { 480 set_keepalive = 1; 481 } 482 } else if (startswith(arg, "max-alive-missed=")) { 483 maxalive = atoi(arg+off); 484 if (maxalive < 0) { 485 fprintf(stderr, 486 "max-alive-missed value must be at least 0\n"); 487 maxalive = -1; 488 } else { 489 set_keepalive = 1; 490 } 491 } else if (startswith(arg, "alive-interval=")) { 492 alive_intval = atoi(arg+off); 493 if (alive_intval < 0) { 494 fprintf(stderr, 495 "alive-interval value must be at least 0\n"); 496 alive_intval = -1; 497 } else { 498 set_keepalive = 1; 499 } 500 } else if (strcmp(arg, "callin") == 0) 501 spr.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT; 502 else if (strcmp(arg, "always") == 0) 503 spr.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT; 504 else if (strcmp(arg, "norechallenge") == 0) 505 spr.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE; 506 else if (strcmp(arg, "rechallenge") == 0) 507 spr.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE; 508 else if (strcmp(arg, "passiveauthproto") == 0) 509 spr.myauthflags |= SPPP_AUTHFLAG_PASSIVEAUTHPROTO; 510 #ifndef __NetBSD__ 511 else if (strcmp(arg, "enable-vj") == 0) 512 spr.defs.enable_vj = 1; 513 else if (strcmp(arg, "disable-vj") == 0) 514 spr.defs.enable_vj = 0; 515 #endif 516 else if (startswith(arg, "lcp-timeout=")) { 517 int timeout_arg = atoi(arg+off); 518 if ((timeout_arg > 20000) || (timeout_arg <= 0)) 519 errx(EX_DATAERR, "bad lcp timeout value: %s", 520 arg+off); 521 lcp.lcp_timeout = timeout_arg * hz / 1000; 522 set_lcp = 1; 523 } else if (startswith(arg, "idle-timeout=")) { 524 timeout.idle_seconds = (time_t)atol(arg+off); 525 set_idle_to = 1; 526 } else if (startswith(arg, "max-auth-failure=")) { 527 authfailset.max_failures = atoi(arg+off); 528 set_auth_failure = 1; 529 } else if (strcmp(arg, "clear-auth-failure") == 0) { 530 clear_auth_failure_count = 1; 531 } else if (startswith(arg, "query-dns=")) { 532 dnssettings.query_dns = atoi(arg+off); 533 set_dns = 1; 534 } else if (strcmp(arg, "ipcp") == 0) { 535 set_ncpflags |= SPPP_NCP_IPCP; 536 clr_ncpflags &= ~SPPP_NCP_IPCP; 537 } else if (strcmp(arg, "noipcp") == 0) { 538 set_ncpflags &= ~SPPP_NCP_IPCP; 539 clr_ncpflags |= SPPP_NCP_IPCP; 540 } else if (strcmp(arg, "ipv6cp") == 0) { 541 set_ncpflags |= SPPP_NCP_IPV6CP; 542 clr_ncpflags &= ~SPPP_NCP_IPV6CP; 543 } else if (strcmp(arg, "noipv6cp") == 0) { 544 set_ncpflags &= ~SPPP_NCP_IPV6CP; 545 clr_ncpflags |= SPPP_NCP_IPV6CP; 546 #ifdef SPPP_FILTER 547 } else if (startswith(arg, "filter-dialing=")) { 548 filter_dialing = arg + off; 549 } else if (startswith(arg, "filter-active-in=")) { 550 filter_active_in = arg + off; 551 } else if (startswith(arg, "filter-active-out=")) { 552 filter_active_out = arg + off; 553 #endif 554 } else 555 errx(EX_DATAERR, "bad parameter: \"%s\"", arg); 556 } 557 558 static void 559 usage(void) 560 { 561 const char * prog = getprogname(); 562 fprintf(stderr, 563 "usage:\n" 564 " %s [-f config] ifname [...]\n" 565 " %s [-v] ifname [{my|his}auth{proto|name|secret}=...] \\\n" 566 " [callin] [always] [{no}rechallenge]\n" 567 " [query-dns=3] [{no}ipcp] [{no}ipv6cp]\n" 568 " to set authentication names, passwords\n" 569 " and (optional) parameters\n" 570 " %s [-v] ifname lcp-timeout=ms|idle-timeout=s|\n" 571 " max-noreceive=s|max-alive-missed=cnt|\n" 572 " max-auth-failure=count|clear-auth-failure\n" 573 #ifdef SPPP_FILTER 574 " filter-dialing=...|\n" 575 " filter-active-in=...|filter-active-out=...\n" 576 #endif 577 " to set general parameters\n" 578 " or\n" 579 " %s -e ethernet-ifname ifname\n" 580 " to connect an ethernet interface for PPPoE\n" 581 " %s [-a access-concentrator-name] [-s service-name] ifname\n" 582 " to specify (optional) data for PPPoE sessions\n" 583 " %s -d ifname\n" 584 " to dump the current PPPoE session state\n" 585 " %s -n (1|2) ifname\n" 586 " to print DNS addresses retrieved via query-dns\n" 587 , prog, prog, prog, prog, prog, prog, prog); 588 exit(EX_USAGE); 589 } 590 591 static void 592 print_vals(const char *ifname, int phase, struct spppauthcfg *sp, int lcp_timeout, 593 time_t idle_timeout, int authfailures, int max_auth_failures, 594 u_int maxalive_cnt, time_t max_noreceive_time, u_int alive_interval, 595 int ncp_flags) 596 { 597 #ifndef __NetBSD__ 598 time_t send, recv; 599 #endif 600 601 printf("%s:\tphase=%s\n", ifname, phase_name(phase)); 602 if (sp->myauth) { 603 printf("\tmyauthproto=%s myauthname=\"%s\"\n", 604 proto_name(sp->myauth), 605 sp->myname); 606 } 607 if (sp->hisauth) { 608 printf("\thisauthproto=%s hisauthname=\"%s\"%s\n", 609 proto_name(sp->hisauth), 610 sp->hisname, 611 authflags(sp->hisauthflags)); 612 } 613 #ifndef __NetBSD__ 614 if (sp->defs.pp_phase > PHASE_DEAD) { 615 send = time(NULL) - sp->defs.pp_last_sent; 616 recv = time(NULL) - sp->defs.pp_last_recv; 617 printf("\tidle_time=%ld\n", (send<recv)? send : recv); 618 } 619 #endif 620 621 printf("\tlcp timeout: %.3f s\n", 622 (double)lcp_timeout / hz); 623 624 if (idle_timeout != 0) 625 printf("\tidle timeout = %lu s\n", (unsigned long)idle_timeout); 626 else 627 printf("\tidle timeout = disabled\n"); 628 629 if (authfailures != 0) 630 printf("\tauthentication failures = %d\n", authfailures); 631 printf("\tmax-auth-failure = %d\n", max_auth_failures); 632 633 printf("\tmax-noreceive = %ld seconds\n", (long)max_noreceive_time); 634 printf("\tmax-alive-missed = %u unanswered echo requests\n", maxalive_cnt); 635 printf("\talive-interval = %u\n", alive_interval); 636 637 #ifndef __NetBSD__ 638 printf("\tenable_vj: %s\n", 639 sp->defs.enable_vj ? "on" : "off"); 640 #endif 641 642 printf("\tipcp: %s\n", 643 ncp_flags & SPPP_NCP_IPCP ? "enable" : "disable"); 644 printf("\tipv6cp: %s\n", 645 ncp_flags & SPPP_NCP_IPV6CP ? "enable" : "disable"); 646 } 647 648 static void 649 print_dns(const char *ifname, int dns1, int dns2, int s, int tabs) 650 { 651 int i; 652 struct spppdnsaddrs addrs; 653 654 if (!dns1 && !dns2) 655 return; 656 657 PPPOECTL_IOCTL(ifname, s, SPPPGETDNSADDRS, &addrs); 658 if (dns1) { 659 for (i = 0; i < tabs; i++) 660 printf("\t"); 661 if (tabs > 0) 662 printf("primary dns address "); 663 printf("%d.%d.%d.%d\n", 664 (addrs.dns[0] >> 24) & 0xff, 665 (addrs.dns[0] >> 16) & 0xff, 666 (addrs.dns[0] >> 8) & 0xff, 667 addrs.dns[0] & 0xff); 668 } 669 if (dns2) { 670 for (i = 0; i < tabs; i++) 671 printf("\t"); 672 if (tabs > 0) 673 printf("secondary dns address "); 674 printf("%d.%d.%d.%d\n", 675 (addrs.dns[1] >> 24) & 0xff, 676 (addrs.dns[1] >> 16) & 0xff, 677 (addrs.dns[1] >> 8) & 0xff, 678 addrs.dns[1] & 0xff); 679 } 680 } 681 682 static void 683 print_stats(const char *ifname, int s, int dump) 684 { 685 struct pppoeconnectionstate state; 686 struct sppplcpstatus lcpst; 687 struct spppipcpstatus ipcpst; 688 struct spppipv6cpstatus ipv6cpst; 689 struct in_addr addr; 690 691 PPPOECTL_IOCTL(ifname, s, PPPOEGETSESSION, &state); 692 693 /* dump PPPoE session state */ 694 printf("%s:\t%s %s\n", ifname, 695 dump > 1 ? "PPPoE state:" : "state =", 696 pppoe_state_name(state.state)); 697 printf("\tSession ID: 0x%x\n", state.session_id); 698 printf("\tPADI retries: %d\n", state.padi_retry_no); 699 printf("\tPADR retries: %d\n", state.padr_retry_no); 700 701 if (dump > 1) { 702 PPPOECTL_IOCTL(ifname, s, SPPPGETLCPSTATUS, &lcpst); 703 PPPOECTL_IOCTL(ifname, s, SPPPGETIPCPSTATUS, &ipcpst); 704 PPPOECTL_IOCTL(ifname, s, SPPPGETIPV6CPSTATUS, &ipv6cpst); 705 706 printf("\tLCP state: %s\n", 707 ppp_state_name(lcpst.state)); 708 printf("\tIPCP state: %s\n", 709 ppp_state_name(ipcpst.state)); 710 printf("\tIPv6CP state: %s\n", 711 ppp_state_name(ipv6cpst.state)); 712 713 if (lcpst.state == SPPP_STATE_OPENED) { 714 printf("\tLCP negotiated options:\n"); 715 printf("\t\tmru %lu\n", lcpst.mru); 716 printf("\t\tmagic number 0x%lx\n", 717 lcpst.magic); 718 } 719 720 if (ipcpst.state == SPPP_STATE_OPENED) { 721 addr.s_addr = ipcpst.myaddr; 722 723 printf("\tIPCP negotiated options:\n"); 724 printf("\t\taddress %s\n", inet_ntoa(addr)); 725 print_dns(ifname, 726 ISSET(ipcpst.opts, SPPP_IPCP_OPT_PRIMDNS), 727 ISSET(ipcpst.opts, SPPP_IPCP_OPT_SECDNS), 728 s, 2); 729 } 730 731 if (ipv6cpst.state == SPPP_STATE_OPENED) { 732 printf("\tIPv6CP negotiated options:\n"); 733 if (ISSET(ipv6cpst.opts, SPPP_IPV6CP_OPT_COMPRESSION)) 734 printf("\t\tcompression\n"); 735 if (ISSET(ipv6cpst.opts, SPPP_IPV6CP_OPT_IFID)) { 736 printf("\t\tifid: " 737 "my_ifid=0x%02x%02x%02x%02x%02x%02x%02x%02x, " 738 "his_ifid=0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 739 ipv6cpst.my_ifid[0], ipv6cpst.my_ifid[1], 740 ipv6cpst.my_ifid[2], ipv6cpst.my_ifid[3], 741 ipv6cpst.my_ifid[4], ipv6cpst.my_ifid[5], 742 ipv6cpst.my_ifid[6], ipv6cpst.my_ifid[7], 743 ipv6cpst.his_ifid[0], ipv6cpst.his_ifid[1], 744 ipv6cpst.his_ifid[2], ipv6cpst.his_ifid[3], 745 ipv6cpst.his_ifid[4], ipv6cpst.his_ifid[5], 746 ipv6cpst.his_ifid[6], ipv6cpst.his_ifid[7]); 747 } 748 } 749 } 750 } 751 752 static const char * 753 phase_name(int phase) 754 { 755 switch (phase) { 756 case SPPP_PHASE_DEAD: return "dead"; 757 case SPPP_PHASE_ESTABLISH: return "establish"; 758 case SPPP_PHASE_TERMINATE: return "terminate"; 759 case SPPP_PHASE_AUTHENTICATE: return "authenticate"; 760 case SPPP_PHASE_NETWORK: return "network"; 761 } 762 return "illegal"; 763 } 764 765 static const char * 766 proto_name(int proto) 767 { 768 static char buf[12]; 769 switch (proto) { 770 case SPPP_AUTHPROTO_PAP: return "pap"; 771 case SPPP_AUTHPROTO_CHAP: return "chap"; 772 case SPPP_AUTHPROTO_NONE: return "none"; 773 } 774 snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto); 775 return buf; 776 } 777 778 static const char * 779 authflags(int flags) 780 { 781 static char buf[32]; 782 buf[0] = '\0'; 783 if (flags & SPPP_AUTHFLAG_NOCALLOUT) 784 strlcat(buf, " callin", sizeof(buf)); 785 if (flags & SPPP_AUTHFLAG_NORECHALLENGE) 786 strlcat(buf, " norechallenge", sizeof(buf)); 787 return buf; 788 } 789 790 static const char * 791 pppoe_state_name(int state) 792 { 793 794 switch(state) { 795 case PPPOE_STATE_INITIAL: 796 return "initial"; 797 case PPPOE_STATE_PADI_SENT: 798 return "PADI sent"; 799 case PPPOE_STATE_PADR_SENT: 800 return "PADR sent"; 801 case PPPOE_STATE_SESSION: 802 return "session"; 803 case PPPOE_STATE_CLOSING: 804 return "closing"; 805 } 806 807 return "unknown"; 808 } 809 static const char * 810 ppp_state_name(int state) 811 { 812 813 switch (state) { 814 case SPPP_STATE_INITIAL: return "initial"; 815 case SPPP_STATE_STARTING: return "starting"; 816 case SPPP_STATE_CLOSED: return "closed"; 817 case SPPP_STATE_STOPPED: return "stopped"; 818 case SPPP_STATE_CLOSING: return "closing"; 819 case SPPP_STATE_STOPPING: return "stopping"; 820 case SPPP_STATE_REQ_SENT: return "req-sent"; 821 case SPPP_STATE_ACK_RCVD: return "ack-rcvd"; 822 case SPPP_STATE_ACK_SENT: return "ack-sent"; 823 case SPPP_STATE_OPENED: return "opened"; 824 } 825 826 return "unknown"; 827 } 828 829 static void 830 print_error(const char *ifname, int error, const char * str) 831 { 832 if (error == -1) 833 fprintf(stderr, "%s: interface not found\n", ifname); 834 else 835 fprintf(stderr, "%s: %s: %s\n", ifname, str, strerror(error)); 836 exit(EX_DATAERR); 837 } 838 839 #ifdef SPPP_FILTER 840 static void 841 set_spppfilter(struct spppfilter *sf, const char *pcap_str, 842 const char *cmdstr) 843 { 844 845 if (strcmp(pcap_str, "none") == 0) { 846 /* filter matches no packets */ 847 static const struct bpf_insn null_insns[] = { 848 BPF_STMT(BPF_RET+BPF_K, (u_int)0) 849 }; 850 const struct bpf_program null_bf = { 851 .bf_len = __arraycount(null_insns), 852 .bf_insns = __UNCONST(null_insns), 853 }; 854 sf->bf = null_bf; 855 } else if (strcmp(pcap_str, "all") == 0) { 856 sf->bf.bf_len = 0; 857 sf->bf.bf_insns = NULL; 858 } else { 859 pcap_t *pcap; 860 /* 861 * bpf_filter() is called before PPP encapsulation in 862 * sppp_output and after PPP decapsulation in sppp_input. 863 * It therefore sees raw IP packets rather than PPP frames, 864 * so use DLT_RAW instead of DLT_PPP_ETHER. 865 */ 866 pcap = pcap_open_dead(DLT_RAW, 65535); 867 if (pcap == NULL) 868 err(EX_OSERR, "%s: pcap_open_dead failed", cmdstr); 869 if (pcap_compile(pcap, &sf->bf, pcap_str, 1, 0)) 870 errx(EX_OSERR, "%s: filter compile error: %s", 871 cmdstr, pcap_geterr(pcap)); 872 873 pcap_close(pcap); 874 } 875 } 876 #endif 877