1 /* $NetBSD: pppoectl.c,v 1.12 2003/06/23 11:53:39 agc 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.12 2003/06/23 11:53:39 agc Exp $"); 35 #endif 36 37 38 #include <sys/param.h> 39 #include <sys/callout.h> 40 #include <sys/ioctl.h> 41 #include <sys/mbuf.h> 42 #include <sys/socket.h> 43 #include <sys/time.h> 44 #include <sys/sysctl.h> 45 #include <net/if.h> 46 #include <net/if_sppp.h> 47 #include <net/if_pppoe.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 55 static void usage(void); 56 static void print_error(const char *ifname, int error, const char * str); 57 static void print_vals(const char *ifname, int phase, struct spppauthcfg *sp, 58 int lcp_timeout, time_t idle_timeout, int authfailures, 59 int max_auth_failures); 60 const char *phase_name(int phase); 61 const char *proto_name(int proto); 62 const char *authflags(int flags); 63 static void pppoectl_argument(char *arg); 64 65 int hz = 0; 66 67 int set_auth, set_lcp, set_idle_to, set_auth_failure, set_dns, 68 clear_auth_failure_count; 69 struct spppauthcfg spr; 70 struct sppplcpcfg lcp; 71 struct spppstatus status; 72 struct spppidletimeout timeout; 73 struct spppauthfailurestats authfailstats; 74 struct spppauthfailuresettings authfailset; 75 struct spppdnssettings dnssettings; 76 77 int 78 main(int argc, char **argv) 79 { 80 FILE *fp; 81 int s, c; 82 int errs = 0, verbose = 0, dump = 0, dns1 = 0, dns2 = 0; 83 size_t len; 84 const char *eth_if_name, *access_concentrator, *service; 85 const char *ifname, *configname; 86 char *line; 87 int mib[2]; 88 struct clockinfo clockinfo; 89 setprogname(argv[0]); 90 91 eth_if_name = NULL; 92 access_concentrator = NULL; 93 service = NULL; 94 configname = NULL; 95 while ((c = getopt(argc, argv, "vde:f:s:a:n:")) != -1) 96 switch (c) { 97 case 'v': 98 verbose++; 99 break; 100 101 case 'd': 102 dump++; 103 break; 104 105 case 'e': 106 eth_if_name = optarg; 107 break; 108 109 case 'f': 110 configname = optarg; 111 break; 112 113 case 's': 114 service = optarg; 115 break; 116 117 case 'a': 118 access_concentrator = optarg; 119 break; 120 121 case 'n': 122 if (strcmp(optarg, "1") == 0) 123 dns1 = 1; 124 else if (strcmp(optarg, "2") == 0) 125 dns2 = 1; 126 else { 127 fprintf(stderr, "bad argument \"%s\" to -n (only 1 or two allowed)\n", 128 optarg); 129 errs++; 130 } 131 break; 132 133 default: 134 errs++; 135 break; 136 } 137 argv += optind; 138 argc -= optind; 139 140 if (errs || argc < 1) 141 usage(); 142 143 ifname = argv[0]; 144 145 /* use a random AF to create the socket */ 146 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 147 err(EX_UNAVAILABLE, "ifconfig: socket"); 148 149 argc--; 150 argv++; 151 152 if (eth_if_name) { 153 struct pppoediscparms parms; 154 int e; 155 156 memset(&parms, 0, sizeof parms); 157 strncpy(parms.ifname, ifname, sizeof(parms.ifname)); 158 strncpy(parms.eth_ifname, eth_if_name, sizeof(parms.eth_ifname)); 159 if (access_concentrator) { 160 parms.ac_name = (char*)access_concentrator; 161 parms.ac_name_len = strlen(access_concentrator); 162 } 163 if (service) { 164 parms.service_name = (char*)service; 165 parms.service_name_len = strlen(service); 166 } 167 168 e = ioctl(s, PPPOESETPARMS, &parms); 169 if (e) 170 print_error(ifname, e, "PPPOESETPARMS"); 171 return 0; 172 } 173 174 if (dns1 || dns2) { 175 /* print DNS addresses */ 176 int e; 177 struct spppdnsaddrs addrs; 178 memset(&addrs, 0, sizeof addrs); 179 strncpy(addrs.ifname, ifname, sizeof addrs.ifname); 180 e = ioctl(s, SPPPGETDNSADDRS, &addrs); 181 if (e) 182 print_error(ifname, e, "SPPPGETDNSADDRS"); 183 if (dns1) 184 printf("%d.%d.%d.%d\n", 185 (addrs.dns[0] >> 24) & 0xff, 186 (addrs.dns[0] >> 16) & 0xff, 187 (addrs.dns[0] >> 8) & 0xff, 188 addrs.dns[0] & 0xff); 189 if (dns2) 190 printf("%d.%d.%d.%d\n", 191 (addrs.dns[1] >> 24) & 0xff, 192 (addrs.dns[1] >> 16) & 0xff, 193 (addrs.dns[1] >> 8) & 0xff, 194 addrs.dns[1] & 0xff); 195 } 196 197 if (dump) { 198 /* dump PPPoE session state */ 199 struct pppoeconnectionstate state; 200 int e; 201 202 memset(&state, 0, sizeof state); 203 strncpy(state.ifname, ifname, sizeof state.ifname); 204 e = ioctl(s, PPPOEGETSESSION, &state); 205 if (e) 206 print_error(ifname, e, "PPPOEGETSESSION"); 207 208 printf("%s:\tstate = ", ifname); 209 switch(state.state) { 210 case PPPOE_STATE_INITIAL: 211 printf("initial\n"); break; 212 case PPPOE_STATE_PADI_SENT: 213 printf("PADI sent\n"); break; 214 case PPPOE_STATE_PADR_SENT: 215 printf("PADR sent\n"); break; 216 case PPPOE_STATE_SESSION: 217 printf("session\n"); break; 218 case PPPOE_STATE_CLOSING: 219 printf("closing\n"); break; 220 } 221 printf("\tSession ID: 0x%x\n", state.session_id); 222 printf("\tPADI retries: %d\n", state.padi_retry_no); 223 printf("\tPADR retries: %d\n", state.padr_retry_no); 224 225 return 0; 226 } 227 228 229 memset(&spr, 0, sizeof spr); 230 strncpy(spr.ifname, ifname, sizeof spr.ifname); 231 memset(&lcp, 0, sizeof lcp); 232 strncpy(lcp.ifname, ifname, sizeof lcp.ifname); 233 memset(&status, 0, sizeof status); 234 strncpy(status.ifname, ifname, sizeof status.ifname); 235 memset(&timeout, 0, sizeof timeout); 236 strncpy(timeout.ifname, ifname, sizeof timeout.ifname); 237 memset(&authfailstats, 0, sizeof &authfailstats); 238 strncpy(authfailstats.ifname, ifname, sizeof authfailstats.ifname); 239 memset(&authfailset, 0, sizeof authfailset); 240 strncpy(authfailset.ifname, ifname, sizeof authfailset.ifname); 241 memset(&dnssettings, 0, sizeof dnssettings); 242 strncpy(dnssettings.ifname, ifname, sizeof dnssettings.ifname); 243 244 mib[0] = CTL_KERN; 245 mib[1] = KERN_CLOCKRATE; 246 len = sizeof(clockinfo); 247 if(sysctl(mib, 2, &clockinfo, &len, NULL, 0) == -1) 248 { 249 fprintf(stderr, "error, cannot sysctl kern.clockrate!\n"); 250 exit(1); 251 } 252 253 hz = clockinfo.hz; 254 255 if (argc == 0 && !(dns1||dns2) && !configname) { 256 /* list only mode */ 257 258 /* first pass, get name lenghts */ 259 if (ioctl(s, SPPPGETAUTHCFG, &spr) == -1) 260 err(EX_OSERR, "SPPPGETAUTHCFG"); 261 /* now allocate buffers for strings */ 262 if (spr.myname_length) 263 spr.myname = malloc(spr.myname_length); 264 if (spr.hisname_length) 265 spr.hisname = malloc(spr.hisname_length); 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, SPPPGETSTATUS, &status) == -1) 273 err(EX_OSERR, "SPPPGETSTATUS"); 274 if (ioctl(s, SPPPGETIDLETO, &timeout) == -1) 275 err(EX_OSERR, "SPPPGETIDLETO"); 276 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 277 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 278 279 print_vals(ifname, status.phase, &spr, lcp.lcp_timeout, timeout.idle_seconds, authfailstats.auth_failures, authfailstats.max_failures); 280 281 if (spr.hisname) free(spr.hisname); 282 if (spr.myname) free(spr.myname); 283 return 0; 284 } 285 286 /* first load the config file, then parse command line args */ 287 if (configname && (fp = fopen(configname, "r"))) 288 while ((line = fparseln(fp, NULL, NULL, NULL, 0))) 289 pppoectl_argument(line); 290 291 while (argc > 0) { 292 pppoectl_argument(argv[0]); 293 294 argv++; 295 argc--; 296 } 297 298 if (set_auth) { 299 if (ioctl(s, SPPPSETAUTHCFG, &spr) == -1) 300 err(EX_OSERR, "SPPPSETAUTHCFG"); 301 } 302 if (set_lcp) { 303 if (ioctl(s, SPPPSETLCPCFG, &lcp) == -1) 304 err(EX_OSERR, "SPPPSETLCPCFG"); 305 } 306 if (set_idle_to) { 307 if (ioctl(s, SPPPSETIDLETO, &timeout) == -1) 308 err(EX_OSERR, "SPPPSETIDLETO"); 309 } 310 if (set_auth_failure) { 311 if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1) 312 err(EX_OSERR, "SPPPSETAUTHFAILURE"); 313 } 314 if (clear_auth_failure_count && !(set_auth || set_auth_failure)) { 315 /* 316 * We want to clear the auth failure count, but did not 317 * do that implicitly by setting authentication - so 318 * do a zero-effect auth setting change 319 */ 320 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 321 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 322 authfailset.max_failures = authfailstats.max_failures; 323 if (ioctl(s, SPPPSETAUTHFAILURE, &authfailset) == -1) 324 err(EX_OSERR, "SPPPSETAUTHFAILURE"); 325 } 326 if (set_dns) { 327 if (ioctl(s, SPPPSETDNSOPTS, &dnssettings) == -1) 328 err(EX_OSERR, "SPPPSETDNSOPTS"); 329 } 330 331 if (verbose) { 332 if (ioctl(s, SPPPGETAUTHFAILURES, &authfailstats) == -1) 333 err(EX_OSERR, "SPPPGETAUTHFAILURES"); 334 print_vals(ifname, status.phase, &spr, lcp.lcp_timeout, timeout.idle_seconds, authfailstats.auth_failures, authfailstats.max_failures); 335 } 336 337 return 0; 338 } 339 340 static void 341 pppoectl_argument(char *arg) 342 { 343 size_t off; 344 const char *cp; 345 346 #define startswith(a,s) strncmp(a, s, (off = strlen(s))) == 0 347 if (startswith(arg, "authproto=")) { 348 cp = arg + off; 349 if (strcmp(cp, "pap") == 0) 350 spr.myauth = 351 spr.hisauth = SPPP_AUTHPROTO_PAP; 352 else if (strcmp(cp, "chap") == 0) 353 spr.myauth = spr.hisauth = SPPP_AUTHPROTO_CHAP; 354 else if (strcmp(cp, "none") == 0) 355 spr.myauth = spr.hisauth = SPPP_AUTHPROTO_NONE; 356 else 357 errx(EX_DATAERR, "bad auth proto: %s", cp); 358 set_auth = 1; 359 } else if (startswith(arg, "myauthproto=")) { 360 cp = arg + off; 361 if (strcmp(cp, "pap") == 0) 362 spr.myauth = SPPP_AUTHPROTO_PAP; 363 else if (strcmp(cp, "chap") == 0) 364 spr.myauth = SPPP_AUTHPROTO_CHAP; 365 else if (strcmp(cp, "none") == 0) 366 spr.myauth = SPPP_AUTHPROTO_NONE; 367 else 368 errx(EX_DATAERR, "bad auth proto: %s", cp); 369 set_auth = 1; 370 } else if (startswith(arg, "myauthname=")) { 371 spr.myname = arg + off; 372 spr.myname_length = strlen(spr.myname)+1; 373 set_auth = 1; 374 } else if (startswith(arg, "myauthsecret=") || startswith(arg, "myauthkey=")) { 375 spr.mysecret = arg + off; 376 spr.mysecret_length = strlen(spr.mysecret)+1; 377 set_auth = 1; 378 } else if (startswith(arg, "hisauthproto=")) { 379 cp = arg + off; 380 if (strcmp(cp, "pap") == 0) 381 spr.hisauth = SPPP_AUTHPROTO_PAP; 382 else if (strcmp(cp, "chap") == 0) 383 spr.hisauth = SPPP_AUTHPROTO_CHAP; 384 else if (strcmp(cp, "none") == 0) 385 spr.hisauth = SPPP_AUTHPROTO_NONE; 386 else 387 errx(EX_DATAERR, "bad auth proto: %s", cp); 388 set_auth = 1; 389 } else if (startswith(arg, "hisauthname=")) { 390 spr.hisname = arg + off; 391 spr.hisname_length = strlen(spr.hisname)+1; 392 set_auth = 1; 393 } else if (startswith(arg, "hisauthsecret=") || startswith(arg, "hisauthkey=")) { 394 spr.hissecret = arg + off; 395 spr.hissecret_length = strlen(spr.hissecret)+1; 396 set_auth = 1; 397 } else if (strcmp(arg, "callin") == 0) 398 spr.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT; 399 else if (strcmp(arg, "always") == 0) 400 spr.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT; 401 else if (strcmp(arg, "norechallenge") == 0) 402 spr.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE; 403 else if (strcmp(arg, "rechallenge") == 0) 404 spr.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE; 405 #ifndef __NetBSD__ 406 else if (strcmp(arg, "enable-vj") == 0) 407 spr.defs.enable_vj = 1; 408 else if (strcmp(arg, "disable-vj") == 0) 409 spr.defs.enable_vj = 0; 410 #endif 411 else if (startswith(arg, "lcp-timeout=")) { 412 int timeout_arg = atoi(arg+off); 413 if ((timeout_arg > 20000) || (timeout_arg <= 0)) 414 errx(EX_DATAERR, "bad lcp timeout value: %s", 415 arg+off); 416 lcp.lcp_timeout = timeout_arg * hz / 1000; 417 set_lcp = 1; 418 } else if (startswith(arg, "idle-timeout=")) { 419 timeout.idle_seconds = (time_t)atol(arg+off); 420 set_idle_to = 1; 421 } else if (startswith(arg, "max-auth-failure=")) { 422 authfailset.max_failures = atoi(arg+off); 423 set_auth_failure = 1; 424 } else if (strcmp(arg, "clear-auth-failure") == 0) { 425 clear_auth_failure_count = 1; 426 } else if (startswith(arg, "query-dns=")) { 427 dnssettings.query_dns = atoi(arg+off); 428 set_dns = 1; 429 } else 430 errx(EX_DATAERR, "bad parameter: \"%s\"", arg); 431 } 432 433 static void 434 usage(void) 435 { 436 const char * prog = getprogname(); 437 fprintf(stderr, 438 "usage:\n" 439 " %s [-f config] ifname [...]\n" 440 " %s [-v] ifname [{my|his}auth{proto|name|secret}=...] \\\n" 441 " [callin] [always] [{no}rechallenge]\n" 442 " [query-dns=3]\n" 443 " to set authentication names, passwords\n" 444 " and (optional) paramaters\n" 445 " %s [-v] ifname lcp-timeout=ms|idle-timeout=s|\n" 446 " max-auth-failure=count|clear-auth-failure\n" 447 " to set general parameters\n" 448 " or\n" 449 " %s -e ethernet-ifname ifname\n" 450 " to connect an ethernet interface for PPPoE\n" 451 " %s [-a access-concentrator-name] [-s service-name] ifname\n" 452 " to specify (optional) data for PPPoE sessions\n" 453 " %s -d ifname\n" 454 " to dump the current PPPoE session state\n" 455 " %s -n (1|2) ifname\n" 456 " to print DNS addresses retrieved via query-dns\n" 457 , prog, prog, prog, prog, prog, prog, prog); 458 exit(EX_USAGE); 459 } 460 461 static void 462 print_vals(const char *ifname, int phase, struct spppauthcfg *sp, int lcp_timeout, 463 time_t idle_timeout, int authfailures, int max_auth_failures) 464 { 465 #ifndef __NetBSD__ 466 time_t send, recv; 467 #endif 468 469 printf("%s:\tphase=%s\n", ifname, phase_name(phase)); 470 if (sp->myauth) { 471 printf("\tmyauthproto=%s myauthname=\"%s\"\n", 472 proto_name(sp->myauth), 473 sp->myname); 474 } 475 if (sp->hisauth) { 476 printf("\thisauthproto=%s hisauthname=\"%s\"%s\n", 477 proto_name(sp->hisauth), 478 sp->hisname, 479 authflags(sp->hisauthflags)); 480 } 481 #ifndef __NetBSD__ 482 if (sp->defs.pp_phase > PHASE_DEAD) { 483 send = time(NULL) - sp->defs.pp_last_sent; 484 recv = time(NULL) - sp->defs.pp_last_recv; 485 printf("\tidle_time=%ld\n", (send<recv)? send : recv); 486 } 487 #endif 488 489 printf("\tlcp timeout: %.3f s\n", 490 (double)lcp_timeout / hz); 491 492 if (idle_timeout != 0) 493 printf("\tidle timeout = %lu s\n", (unsigned long)idle_timeout); 494 else 495 printf("\tidle timeout = disabled\n"); 496 497 if (authfailures != 0) 498 printf("\tauthentication failures = %d\n", authfailures); 499 printf("\tmax-auth-failure = %d\n", max_auth_failures); 500 501 #ifndef __NetBSD__ 502 printf("\tenable_vj: %s\n", 503 sp->defs.enable_vj ? "on" : "off"); 504 #endif 505 } 506 507 const char * 508 phase_name(int phase) 509 { 510 switch (phase) { 511 case SPPP_PHASE_DEAD: return "dead"; 512 case SPPP_PHASE_ESTABLISH: return "establish"; 513 case SPPP_PHASE_TERMINATE: return "terminate"; 514 case SPPP_PHASE_AUTHENTICATE: return "authenticate"; 515 case SPPP_PHASE_NETWORK: return "network"; 516 } 517 return "illegal"; 518 } 519 520 const char * 521 proto_name(int proto) 522 { 523 static char buf[12]; 524 switch (proto) { 525 case SPPP_AUTHPROTO_PAP: return "pap"; 526 case SPPP_AUTHPROTO_CHAP: return "chap"; 527 case SPPP_AUTHPROTO_NONE: return "none"; 528 } 529 sprintf(buf, "0x%x", (unsigned)proto); 530 return buf; 531 } 532 533 const char * 534 authflags(int flags) 535 { 536 static char buf[32]; 537 buf[0] = '\0'; 538 if (flags & SPPP_AUTHFLAG_NOCALLOUT) 539 strcat(buf, " callin"); 540 if (flags & SPPP_AUTHFLAG_NORECHALLENGE) 541 strcat(buf, " norechallenge"); 542 return buf; 543 } 544 545 static void 546 print_error(const char *ifname, int error, const char * str) 547 { 548 if (error == -1) 549 fprintf(stderr, "%s: interface not found\n", ifname); 550 else 551 fprintf(stderr, "%s: %s: %s\n", ifname, str, strerror(error)); 552 exit(EX_DATAERR); 553 } 554 555 556