1 /*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 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 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <netinet/in_systm.h> 33 #include <netinet/in.h> 34 #include <netinet/ip.h> 35 #include <arpa/inet.h> 36 #include <sys/socket.h> 37 #include <net/route.h> 38 #include <netdb.h> 39 #include <sys/un.h> 40 41 #include <ctype.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <paths.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sys/wait.h> 49 #include <termios.h> 50 #include <unistd.h> 51 52 #ifndef NONAT 53 #ifdef LOCALNAT 54 #include "alias.h" 55 #else 56 #include <alias.h> 57 #endif 58 #endif 59 60 #include "layer.h" 61 #include "defs.h" 62 #include "command.h" 63 #include "mbuf.h" 64 #include "log.h" 65 #include "timer.h" 66 #include "fsm.h" 67 #include "iplist.h" 68 #include "throughput.h" 69 #include "slcompress.h" 70 #include "lqr.h" 71 #include "hdlc.h" 72 #include "lcp.h" 73 #include "ncpaddr.h" 74 #include "ip.h" 75 #include "ipcp.h" 76 #ifndef NONAT 77 #include "nat_cmd.h" 78 #endif 79 #include "systems.h" 80 #include "filter.h" 81 #include "descriptor.h" 82 #include "main.h" 83 #include "route.h" 84 #include "ccp.h" 85 #include "auth.h" 86 #include "async.h" 87 #include "link.h" 88 #include "physical.h" 89 #include "mp.h" 90 #ifndef NORADIUS 91 #include "radius.h" 92 #endif 93 #include "ipv6cp.h" 94 #include "ncp.h" 95 #include "bundle.h" 96 #include "server.h" 97 #include "prompt.h" 98 #include "chat.h" 99 #include "chap.h" 100 #include "cbcp.h" 101 #include "datalink.h" 102 #include "iface.h" 103 #include "id.h" 104 #include "probe.h" 105 106 /* ``set'' values */ 107 #define VAR_AUTHKEY 0 108 #define VAR_DIAL 1 109 #define VAR_LOGIN 2 110 #define VAR_AUTHNAME 3 111 #define VAR_AUTOLOAD 4 112 #define VAR_WINSIZE 5 113 #define VAR_DEVICE 6 114 #define VAR_ACCMAP 7 115 #define VAR_MRRU 8 116 #define VAR_MRU 9 117 #define VAR_MTU 10 118 #define VAR_OPENMODE 11 119 #define VAR_PHONE 12 120 #define VAR_HANGUP 13 121 #define VAR_IDLETIMEOUT 14 122 #define VAR_LQRPERIOD 15 123 #define VAR_LCPRETRY 16 124 #define VAR_CHAPRETRY 17 125 #define VAR_PAPRETRY 18 126 #define VAR_CCPRETRY 19 127 #define VAR_IPCPRETRY 20 128 #define VAR_DNS 21 129 #define VAR_NBNS 22 130 #define VAR_MODE 23 131 #define VAR_CALLBACK 24 132 #define VAR_CBCP 25 133 #define VAR_CHOKED 26 134 #define VAR_SENDPIPE 27 135 #define VAR_RECVPIPE 28 136 #define VAR_RADIUS 29 137 #define VAR_CD 30 138 #define VAR_PARITY 31 139 #define VAR_CRTSCTS 32 140 #define VAR_URGENTPORTS 33 141 #define VAR_LOGOUT 34 142 #define VAR_IFQUEUE 35 143 #define VAR_MPPE 36 144 145 /* ``accept|deny|disable|enable'' masks */ 146 #define NEG_HISMASK (1) 147 #define NEG_MYMASK (2) 148 149 /* ``accept|deny|disable|enable'' values */ 150 #define NEG_ACFCOMP 40 151 #define NEG_CHAP05 41 152 #define NEG_CHAP80 42 153 #define NEG_CHAP80LM 43 154 #define NEG_DEFLATE 44 155 #define NEG_DNS 45 156 #define NEG_ENDDISC 46 157 #define NEG_LQR 47 158 #define NEG_PAP 48 159 #define NEG_PPPDDEFLATE 49 160 #define NEG_PRED1 50 161 #define NEG_PROTOCOMP 51 162 #define NEG_SHORTSEQ 52 163 #define NEG_VJCOMP 53 164 #define NEG_MPPE 54 165 #define NEG_CHAP81 55 166 167 const char Version[] = "3.0.0"; 168 169 static int ShowCommand(struct cmdargs const *); 170 static int TerminalCommand(struct cmdargs const *); 171 static int QuitCommand(struct cmdargs const *); 172 static int OpenCommand(struct cmdargs const *); 173 static int CloseCommand(struct cmdargs const *); 174 static int DownCommand(struct cmdargs const *); 175 static int SetCommand(struct cmdargs const *); 176 static int LinkCommand(struct cmdargs const *); 177 static int AddCommand(struct cmdargs const *); 178 static int DeleteCommand(struct cmdargs const *); 179 static int NegotiateCommand(struct cmdargs const *); 180 static int ClearCommand(struct cmdargs const *); 181 static int RunListCommand(struct cmdargs const *); 182 static int IfaceAddCommand(struct cmdargs const *); 183 static int IfaceDeleteCommand(struct cmdargs const *); 184 static int IfaceClearCommand(struct cmdargs const *); 185 static int SetProcTitle(struct cmdargs const *); 186 #ifndef NONAT 187 static int NatEnable(struct cmdargs const *); 188 static int NatOption(struct cmdargs const *); 189 #endif 190 191 static const char * 192 showcx(struct cmdtab const *cmd) 193 { 194 if (cmd->lauth & LOCAL_CX) 195 return "(c)"; 196 else if (cmd->lauth & LOCAL_CX_OPT) 197 return "(o)"; 198 199 return ""; 200 } 201 202 static int 203 HelpCommand(struct cmdargs const *arg) 204 { 205 struct cmdtab const *cmd; 206 int n, cmax, dmax, cols, cxlen; 207 const char *cx; 208 209 if (!arg->prompt) { 210 log_Printf(LogWARN, "help: Cannot help without a prompt\n"); 211 return 0; 212 } 213 214 if (arg->argc > arg->argn) { 215 for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) 216 if ((cmd->lauth & arg->prompt->auth) && 217 ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || 218 (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { 219 prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); 220 return 0; 221 } 222 return -1; 223 } 224 225 cmax = dmax = 0; 226 for (cmd = arg->cmdtab; cmd->func; cmd++) 227 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 228 if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) 229 cmax = n; 230 if ((n = strlen(cmd->helpmes)) > dmax) 231 dmax = n; 232 } 233 234 cols = 80 / (dmax + cmax + 3); 235 n = 0; 236 prompt_Printf(arg->prompt, "(o) = Optional context," 237 " (c) = Context required\n"); 238 for (cmd = arg->cmdtab; cmd->func; cmd++) 239 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 240 cx = showcx(cmd); 241 cxlen = cmax - strlen(cmd->name); 242 if (n % cols != 0) 243 prompt_Printf(arg->prompt, " "); 244 prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s", 245 cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); 246 if (++n % cols == 0) 247 prompt_Printf(arg->prompt, "\n"); 248 } 249 if (n % cols != 0) 250 prompt_Printf(arg->prompt, "\n"); 251 252 return 0; 253 } 254 255 static int 256 IdentCommand(struct cmdargs const *arg) 257 { 258 int f, max, n, pos; 259 260 *arg->cx->physical->link.lcp.cfg.ident = '\0'; 261 max = sizeof arg->cx->physical->link.lcp.cfg.ident; 262 263 for (pos = 0, f = arg->argn; f < arg->argc && pos < max; f++) { 264 n = snprintf(arg->cx->physical->link.lcp.cfg.ident + pos, max - pos, 265 "%s%s", f == arg->argn ? "" : " ", arg->argv[f]); 266 if (n < 0) { 267 arg->cx->physical->link.lcp.cfg.ident[pos] = '\0'; 268 break; 269 } 270 if ((pos += n) >= max) 271 break; 272 } 273 274 return 0; 275 } 276 277 static int 278 SendIdentification(struct cmdargs const *arg) 279 { 280 if (arg->cx->state < DATALINK_LCP) { 281 log_Printf(LogWARN, "sendident: link has not reached LCP\n"); 282 return 2; 283 } 284 return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1; 285 } 286 287 static int 288 CloneCommand(struct cmdargs const *arg) 289 { 290 char namelist[LINE_LEN]; 291 char *name; 292 int f; 293 294 if (arg->argc == arg->argn) 295 return -1; 296 297 namelist[sizeof namelist - 1] = '\0'; 298 for (f = arg->argn; f < arg->argc; f++) { 299 strncpy(namelist, arg->argv[f], sizeof namelist - 1); 300 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 301 bundle_DatalinkClone(arg->bundle, arg->cx, name); 302 } 303 304 return 0; 305 } 306 307 static int 308 RemoveCommand(struct cmdargs const *arg) 309 { 310 if (arg->argc != arg->argn) 311 return -1; 312 313 if (arg->cx->state != DATALINK_CLOSED) { 314 log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); 315 return 2; 316 } 317 318 bundle_DatalinkRemove(arg->bundle, arg->cx); 319 return 0; 320 } 321 322 static int 323 RenameCommand(struct cmdargs const *arg) 324 { 325 if (arg->argc != arg->argn + 1) 326 return -1; 327 328 if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) 329 return 0; 330 331 log_Printf(LogWARN, "%s -> %s: target name already exists\n", 332 arg->cx->name, arg->argv[arg->argn]); 333 return 1; 334 } 335 336 int 337 LoadCommand(struct cmdargs const *arg) 338 { 339 const char *err; 340 int n, mode; 341 342 mode = arg->bundle->phys_type.all; 343 344 if (arg->argn < arg->argc) { 345 for (n = arg->argn; n < arg->argc; n++) 346 if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) { 347 log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err); 348 return 1; 349 } 350 351 for (n = arg->argn; n < arg->argc; n++) { 352 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 353 system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx); 354 } 355 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 356 } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) { 357 log_Printf(LogWARN, "default: %s\n", err); 358 return 1; 359 } else { 360 bundle_SetLabel(arg->bundle, "default"); 361 system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx); 362 bundle_SetLabel(arg->bundle, "default"); 363 } 364 365 return 0; 366 } 367 368 int 369 SaveCommand(struct cmdargs const *arg) 370 { 371 log_Printf(LogWARN, "save command is not implemented (yet).\n"); 372 return 1; 373 } 374 375 static int 376 DialCommand(struct cmdargs const *arg) 377 { 378 int res; 379 380 if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) 381 || (!arg->cx && 382 (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { 383 log_Printf(LogWARN, "Manual dial is only available for auto and" 384 " interactive links\n"); 385 return 1; 386 } 387 388 if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) 389 return res; 390 391 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 392 393 return 0; 394 } 395 396 #define isinword(ch) (isalnum(ch) || (ch) == '_') 397 398 static char * 399 strstrword(char *big, const char *little) 400 { 401 /* Get the first occurance of the word ``little'' in ``big'' */ 402 char *pos; 403 int len; 404 405 pos = big; 406 len = strlen(little); 407 408 while ((pos = strstr(pos, little)) != NULL) 409 if ((pos != big && isinword(pos[-1])) || isinword(pos[len])) 410 pos++; 411 else if (pos != big && pos[-1] == '\\') 412 memmove(pos - 1, pos, strlen(pos) + 1); 413 else 414 break; 415 416 return pos; 417 } 418 419 static char * 420 subst(char *tgt, const char *oldstr, const char *newstr) 421 { 422 /* tgt is a malloc()d area... realloc() as necessary */ 423 char *word, *ntgt; 424 int ltgt, loldstr, lnewstr, pos; 425 426 if ((word = strstrword(tgt, oldstr)) == NULL) 427 return tgt; 428 429 ltgt = strlen(tgt) + 1; 430 loldstr = strlen(oldstr); 431 lnewstr = strlen(newstr); 432 do { 433 pos = word - tgt; 434 if (loldstr > lnewstr) 435 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 436 if (loldstr != lnewstr) { 437 ntgt = realloc(tgt, ltgt += lnewstr - loldstr); 438 if (ntgt == NULL) 439 break; /* Oh wonderful ! */ 440 word = ntgt + pos; 441 tgt = ntgt; 442 } 443 if (lnewstr > loldstr) 444 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 445 bcopy(newstr, word, lnewstr); 446 } while ((word = strstrword(word, oldstr))); 447 448 return tgt; 449 } 450 451 void 452 command_Expand(char **nargv, int argc, char const *const *oargv, 453 struct bundle *bundle, int inc0, pid_t pid) 454 { 455 int arg; 456 char pidstr[12]; 457 458 if (inc0) 459 arg = 0; /* Start at arg 0 */ 460 else { 461 nargv[0] = strdup(oargv[0]); 462 arg = 1; 463 } 464 snprintf(pidstr, sizeof pidstr, "%d", (int)pid); 465 for (; arg < argc; arg++) { 466 nargv[arg] = strdup(oargv[arg]); 467 nargv[arg] = subst(nargv[arg], "HISADDR", 468 inet_ntoa(bundle->ncp.ipcp.peer_ip)); 469 #ifndef NOINET6 470 nargv[arg] = subst(nargv[arg], "HISADDR6", 471 ncpaddr_ntoa(&bundle->ncp.ipv6cp.hisaddr)); 472 #endif 473 nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); 474 nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name); 475 nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip)); 476 #ifndef NOINET6 477 nargv[arg] = subst(nargv[arg], "MYADDR6", 478 ncpaddr_ntoa(&bundle->ncp.ipv6cp.myaddr)); 479 #endif 480 nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); 481 nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", 482 mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, 483 bundle->ncp.mp.peer.enddisc.address, 484 bundle->ncp.mp.peer.enddisc.len)); 485 nargv[arg] = subst(nargv[arg], "ENDDISC", 486 mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, 487 bundle->ncp.mp.cfg.enddisc.address, 488 bundle->ncp.mp.cfg.enddisc.len)); 489 nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr); 490 nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); 491 nargv[arg] = subst(nargv[arg], "DNS0", 492 inet_ntoa(bundle->ncp.ipcp.ns.dns[0])); 493 nargv[arg] = subst(nargv[arg], "DNS1", 494 inet_ntoa(bundle->ncp.ipcp.ns.dns[1])); 495 nargv[arg] = subst(nargv[arg], "VERSION", Version); 496 nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__); 497 } 498 nargv[arg] = NULL; 499 } 500 501 static int 502 ShellCommand(struct cmdargs const *arg, int bg) 503 { 504 const char *shell; 505 pid_t shpid, pid; 506 507 #ifdef SHELL_ONLY_INTERACTIVELY 508 /* we're only allowed to shell when we run ppp interactively */ 509 if (arg->prompt && arg->prompt->owner) { 510 log_Printf(LogWARN, "Can't start a shell from a network connection\n"); 511 return 1; 512 } 513 #endif 514 515 if (arg->argc == arg->argn) { 516 if (!arg->prompt) { 517 log_Printf(LogWARN, "Can't start an interactive shell from" 518 " a config file\n"); 519 return 1; 520 } else if (arg->prompt->owner) { 521 log_Printf(LogWARN, "Can't start an interactive shell from" 522 " a socket connection\n"); 523 return 1; 524 } else if (bg) { 525 log_Printf(LogWARN, "Can only start an interactive shell in" 526 " the foreground mode\n"); 527 return 1; 528 } 529 } 530 531 pid = getpid(); 532 if ((shpid = fork()) == 0) { 533 int i, fd; 534 535 if ((shell = getenv("SHELL")) == 0) 536 shell = _PATH_BSHELL; 537 538 timer_TermService(); 539 540 if (arg->prompt) 541 fd = arg->prompt->fd_out; 542 else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 543 log_Printf(LogALERT, "Failed to open %s: %s\n", 544 _PATH_DEVNULL, strerror(errno)); 545 exit(1); 546 } 547 dup2(fd, STDIN_FILENO); 548 dup2(fd, STDOUT_FILENO); 549 dup2(fd, STDERR_FILENO); 550 for (i = getdtablesize(); i > STDERR_FILENO; i--) 551 fcntl(i, F_SETFD, 1); 552 553 #ifndef NOSUID 554 setuid(ID0realuid()); 555 #endif 556 if (arg->argc > arg->argn) { 557 /* substitute pseudo args */ 558 char *argv[MAXARGS]; 559 int argc = arg->argc - arg->argn; 560 561 if (argc >= sizeof argv / sizeof argv[0]) { 562 argc = sizeof argv / sizeof argv[0] - 1; 563 log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); 564 } 565 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid); 566 if (bg) { 567 pid_t p; 568 569 p = getpid(); 570 if (daemon(1, 1) == -1) { 571 log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno)); 572 exit(1); 573 } 574 } else if (arg->prompt) 575 printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); 576 execvp(argv[0], argv); 577 } else { 578 if (arg->prompt) 579 printf("ppp: Pausing until %s finishes\n", shell); 580 prompt_TtyOldMode(arg->prompt); 581 execl(shell, shell, (char *)NULL); 582 } 583 584 log_Printf(LogWARN, "exec() of %s failed: %s\n", 585 arg->argc > arg->argn ? arg->argv[arg->argn] : shell, 586 strerror(errno)); 587 _exit(255); 588 } 589 590 if (shpid == (pid_t) - 1) 591 log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); 592 else { 593 int status; 594 waitpid(shpid, &status, 0); 595 } 596 597 if (arg->prompt && !arg->prompt->owner) 598 prompt_TtyCommandMode(arg->prompt); 599 600 return 0; 601 } 602 603 static int 604 BgShellCommand(struct cmdargs const *arg) 605 { 606 if (arg->argc == arg->argn) 607 return -1; 608 return ShellCommand(arg, 1); 609 } 610 611 static int 612 FgShellCommand(struct cmdargs const *arg) 613 { 614 return ShellCommand(arg, 0); 615 } 616 617 static int 618 ResolvCommand(struct cmdargs const *arg) 619 { 620 if (arg->argc == arg->argn + 1) { 621 if (!strcasecmp(arg->argv[arg->argn], "reload")) 622 ipcp_LoadDNS(&arg->bundle->ncp.ipcp); 623 else if (!strcasecmp(arg->argv[arg->argn], "restore")) 624 ipcp_RestoreDNS(&arg->bundle->ncp.ipcp); 625 else if (!strcasecmp(arg->argv[arg->argn], "rewrite")) 626 ipcp_WriteDNS(&arg->bundle->ncp.ipcp); 627 else if (!strcasecmp(arg->argv[arg->argn], "readonly")) 628 arg->bundle->ncp.ipcp.ns.writable = 0; 629 else if (!strcasecmp(arg->argv[arg->argn], "writable")) 630 arg->bundle->ncp.ipcp.ns.writable = 1; 631 else 632 return -1; 633 634 return 0; 635 } 636 637 return -1; 638 } 639 640 #ifndef NONAT 641 static struct cmdtab const NatCommands[] = 642 { 643 {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH, 644 "static address translation", "nat addr [addr_local addr_alias]"}, 645 {"deny_incoming", NULL, NatOption, LOCAL_AUTH, 646 "stop incoming connections", "nat deny_incoming yes|no", 647 (const void *) PKT_ALIAS_DENY_INCOMING}, 648 {"enable", NULL, NatEnable, LOCAL_AUTH, 649 "enable NAT", "nat enable yes|no"}, 650 {"log", NULL, NatOption, LOCAL_AUTH, 651 "log NAT link creation", "nat log yes|no", 652 (const void *) PKT_ALIAS_LOG}, 653 {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection", 654 "nat port proto localaddr:port[-port] aliasport[-aliasport]"}, 655 {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection", 656 "nat proto proto localIP [publicIP [remoteIP]]"}, 657 {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH, 658 "proxy control", "nat proxy server host[:port] ..."}, 659 #ifndef NO_FW_PUNCH 660 {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH, 661 "firewall control", "nat punch_fw [base count]"}, 662 #endif 663 {"same_ports", NULL, NatOption, LOCAL_AUTH, 664 "try to leave port numbers unchanged", "nat same_ports yes|no", 665 (const void *) PKT_ALIAS_SAME_PORTS}, 666 {"target", NULL, nat_SetTarget, LOCAL_AUTH, 667 "Default address for incoming connections", "nat target addr" }, 668 {"unregistered_only", NULL, NatOption, LOCAL_AUTH, 669 "translate unregistered (private) IP address space only", 670 "nat unregistered_only yes|no", 671 (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, 672 {"use_sockets", NULL, NatOption, LOCAL_AUTH, 673 "allocate host sockets", "nat use_sockets yes|no", 674 (const void *) PKT_ALIAS_USE_SOCKETS}, 675 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 676 "Display this message", "nat help|? [command]", NatCommands}, 677 {NULL, NULL, NULL}, 678 }; 679 #endif 680 681 static struct cmdtab const AllowCommands[] = { 682 {"modes", "mode", AllowModes, LOCAL_AUTH, 683 "Only allow certain ppp modes", "allow modes mode..."}, 684 {"users", "user", AllowUsers, LOCAL_AUTH, 685 "Only allow ppp access to certain users", "allow users logname..."}, 686 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 687 "Display this message", "allow help|? [command]", AllowCommands}, 688 {NULL, NULL, NULL}, 689 }; 690 691 static struct cmdtab const IfaceCommands[] = 692 { 693 {"add", NULL, IfaceAddCommand, LOCAL_AUTH, 694 "Add iface address", "iface add addr[/bits| mask] peer", NULL}, 695 {NULL, "add!", IfaceAddCommand, LOCAL_AUTH, 696 "Add or change an iface address", "iface add! addr[/bits| mask] peer", 697 (void *)1}, 698 {"clear", NULL, IfaceClearCommand, LOCAL_AUTH, 699 "Clear iface address(es)", "iface clear [INET | INET6]"}, 700 {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH, 701 "Delete iface address", "iface delete addr", NULL}, 702 {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH, 703 "Delete iface address", "iface delete addr", (void *)1}, 704 {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH, 705 "Delete iface address", "iface delete addr", (void *)1}, 706 {"show", NULL, iface_Show, LOCAL_AUTH, 707 "Show iface address(es)", "iface show"}, 708 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 709 "Display this message", "nat help|? [command]", IfaceCommands}, 710 {NULL, NULL, NULL}, 711 }; 712 713 static struct cmdtab const Commands[] = { 714 {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 715 "accept option request", "accept option .."}, 716 {"add", NULL, AddCommand, LOCAL_AUTH, 717 "add route", "add dest mask gateway", NULL}, 718 {NULL, "add!", AddCommand, LOCAL_AUTH, 719 "add or change route", "add! dest mask gateway", (void *)1}, 720 {"allow", "auth", RunListCommand, LOCAL_AUTH, 721 "Allow ppp access", "allow users|modes ....", AllowCommands}, 722 {"bg", "!bg", BgShellCommand, LOCAL_AUTH, 723 "Run a background command", "[!]bg command"}, 724 {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, 725 "Clear throughput statistics", 726 "clear ipcp|ipv6cp|physical [current|overall|peak]..."}, 727 {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, 728 "Clone a link", "clone newname..."}, 729 {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, 730 "Close an FSM", "close [lcp|ccp]"}, 731 {"delete", NULL, DeleteCommand, LOCAL_AUTH, 732 "delete route", "delete dest", NULL}, 733 {NULL, "delete!", DeleteCommand, LOCAL_AUTH, 734 "delete a route if it exists", "delete! dest", (void *)1}, 735 {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 736 "Deny option request", "deny option .."}, 737 {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, 738 "Dial and login", "dial|call [system ...]", NULL}, 739 {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 740 "Disable option", "disable option .."}, 741 {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, 742 "Generate a down event", "down [ccp|lcp]"}, 743 {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 744 "Enable option", "enable option .."}, 745 {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX, 746 "Set the link identity", "ident text..."}, 747 {"iface", "interface", RunListCommand, LOCAL_AUTH, 748 "interface control", "iface option ...", IfaceCommands}, 749 {"link", "datalink", LinkCommand, LOCAL_AUTH, 750 "Link specific commands", "link name command ..."}, 751 {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, 752 "Load settings", "load [system ...]"}, 753 #ifndef NONAT 754 {"nat", "alias", RunListCommand, LOCAL_AUTH, 755 "NAT control", "nat option yes|no", NatCommands}, 756 #endif 757 {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, 758 "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, 759 {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, 760 "Password for manipulation", "passwd LocalPassword"}, 761 {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 762 "Quit PPP program", "quit|bye [all]"}, 763 {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, 764 "Remove a link", "remove"}, 765 {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, 766 "Rename a link", "rename name"}, 767 {"resolv", NULL, ResolvCommand, LOCAL_AUTH, 768 "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"}, 769 {"save", NULL, SaveCommand, LOCAL_AUTH, 770 "Save settings", "save"}, 771 {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX, 772 "Transmit the link identity", "sendident"}, 773 {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, 774 "Set parameters", "set[up] var value"}, 775 {"shell", "!", FgShellCommand, LOCAL_AUTH, 776 "Run a subshell", "shell|! [sh command]"}, 777 {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, 778 "Show status and stats", "show var"}, 779 {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, 780 "Enter terminal mode", "term"}, 781 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 782 "Display this message", "help|? [command]", Commands}, 783 {NULL, NULL, NULL}, 784 }; 785 786 static int 787 ShowEscape(struct cmdargs const *arg) 788 { 789 if (arg->cx->physical->async.cfg.EscMap[32]) { 790 int code, bit; 791 const char *sep = ""; 792 793 for (code = 0; code < 32; code++) 794 if (arg->cx->physical->async.cfg.EscMap[code]) 795 for (bit = 0; bit < 8; bit++) 796 if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { 797 prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); 798 sep = ", "; 799 } 800 prompt_Printf(arg->prompt, "\n"); 801 } 802 return 0; 803 } 804 805 static int 806 ShowTimerList(struct cmdargs const *arg) 807 { 808 timer_Show(0, arg->prompt); 809 return 0; 810 } 811 812 static int 813 ShowStopped(struct cmdargs const *arg) 814 { 815 prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); 816 if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) 817 prompt_Printf(arg->prompt, "Disabled"); 818 else 819 prompt_Printf(arg->prompt, "%ld secs", 820 arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); 821 822 prompt_Printf(arg->prompt, ", CCP: "); 823 if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) 824 prompt_Printf(arg->prompt, "Disabled"); 825 else 826 prompt_Printf(arg->prompt, "%ld secs", 827 arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); 828 829 prompt_Printf(arg->prompt, "\n"); 830 831 return 0; 832 } 833 834 static int 835 ShowVersion(struct cmdargs const *arg) 836 { 837 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__); 838 return 0; 839 } 840 841 static int 842 ShowProtocolStats(struct cmdargs const *arg) 843 { 844 struct link *l = command_ChooseLink(arg); 845 846 prompt_Printf(arg->prompt, "%s:\n", l->name); 847 link_ReportProtocolStatus(l, arg->prompt); 848 return 0; 849 } 850 851 static struct cmdtab const ShowCommands[] = { 852 {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, 853 "bundle details", "show bundle"}, 854 {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, 855 "CCP status", "show cpp"}, 856 {"compress", NULL, sl_Show, LOCAL_AUTH, 857 "VJ compression stats", "show compress"}, 858 {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, 859 "escape characters", "show escape"}, 860 {"filter", NULL, filter_Show, LOCAL_AUTH, 861 "packet filters", "show filter [in|out|dial|alive]"}, 862 {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, 863 "HDLC errors", "show hdlc"}, 864 {"iface", "interface", iface_Show, LOCAL_AUTH, 865 "Interface status", "show iface"}, 866 {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, 867 "IPCP status", "show ipcp"}, 868 #ifndef NOINET6 869 {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH, 870 "IPV6CP status", "show ipv6cp"}, 871 #endif 872 {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT, 873 "Protocol layers", "show layers"}, 874 {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, 875 "LCP status", "show lcp"}, 876 {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, 877 "(high-level) link info", "show link"}, 878 {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, 879 "available link names", "show links"}, 880 {"log", NULL, log_ShowLevel, LOCAL_AUTH, 881 "log levels", "show log"}, 882 {"mem", NULL, mbuf_Show, LOCAL_AUTH, 883 "mbuf allocations", "show mem"}, 884 {"ncp", NULL, ncp_Show, LOCAL_AUTH, 885 "NCP status", "show ncp"}, 886 {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX, 887 "(low-level) link info", "show physical"}, 888 {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, 889 "multilink setup", "show mp"}, 890 {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, 891 "protocol summary", "show proto"}, 892 {"route", NULL, route_Show, LOCAL_AUTH, 893 "routing table", "show route"}, 894 {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, 895 "STOPPED timeout", "show stopped"}, 896 {"timers", NULL, ShowTimerList, LOCAL_AUTH, 897 "alarm timers", "show timers"}, 898 {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, 899 "version string", "show version"}, 900 {"who", NULL, log_ShowWho, LOCAL_AUTH, 901 "client list", "show who"}, 902 {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, 903 "Display this message", "show help|? [command]", ShowCommands}, 904 {NULL, NULL, NULL}, 905 }; 906 907 static struct cmdtab const * 908 FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) 909 { 910 int nmatch; 911 int len; 912 struct cmdtab const *found; 913 914 found = NULL; 915 len = strlen(str); 916 nmatch = 0; 917 while (cmds->func) { 918 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { 919 if (cmds->name[len] == '\0') { 920 *pmatch = 1; 921 return cmds; 922 } 923 nmatch++; 924 found = cmds; 925 } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { 926 if (cmds->alias[len] == '\0') { 927 *pmatch = 1; 928 return cmds; 929 } 930 nmatch++; 931 found = cmds; 932 } 933 cmds++; 934 } 935 *pmatch = nmatch; 936 return found; 937 } 938 939 static const char * 940 mkPrefix(int argc, char const *const *argv, char *tgt, int sz) 941 { 942 int f, tlen, len; 943 944 tlen = 0; 945 for (f = 0; f < argc && tlen < sz - 2; f++) { 946 if (f) 947 tgt[tlen++] = ' '; 948 len = strlen(argv[f]); 949 if (len > sz - tlen - 1) 950 len = sz - tlen - 1; 951 strncpy(tgt+tlen, argv[f], len); 952 tlen += len; 953 } 954 tgt[tlen] = '\0'; 955 return tgt; 956 } 957 958 static int 959 FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, 960 char const *const *argv, struct prompt *prompt, struct datalink *cx) 961 { 962 struct cmdtab const *cmd; 963 int val = 1; 964 int nmatch; 965 struct cmdargs arg; 966 char prefix[100]; 967 968 cmd = FindCommand(cmds, argv[argn], &nmatch); 969 if (nmatch > 1) 970 log_Printf(LogWARN, "%s: Ambiguous command\n", 971 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 972 else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { 973 if ((cmd->lauth & LOCAL_CX) && !cx) 974 /* We've got no context, but we require it */ 975 cx = bundle2datalink(bundle, NULL); 976 977 if ((cmd->lauth & LOCAL_CX) && !cx) 978 log_Printf(LogWARN, "%s: No context (use the `link' command)\n", 979 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 980 else { 981 if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 982 log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", 983 mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); 984 cx = NULL; 985 } 986 arg.cmdtab = cmds; 987 arg.cmd = cmd; 988 arg.argc = argc; 989 arg.argn = argn+1; 990 arg.argv = argv; 991 arg.bundle = bundle; 992 arg.cx = cx; 993 arg.prompt = prompt; 994 val = (*cmd->func) (&arg); 995 } 996 } else 997 log_Printf(LogWARN, "%s: Invalid command\n", 998 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 999 1000 if (val == -1) 1001 log_Printf(LogWARN, "Usage: %s\n", cmd->syntax); 1002 else if (val) 1003 log_Printf(LogWARN, "%s: Failed %d\n", 1004 mkPrefix(argn+1, argv, prefix, sizeof prefix), val); 1005 1006 return val; 1007 } 1008 1009 int 1010 command_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset) 1011 { 1012 char buff2[LINE_LEN-offset]; 1013 1014 InterpretArg(buff, buff2); 1015 strncpy(buff, buff2, LINE_LEN - offset - 1); 1016 buff[LINE_LEN - offset - 1] = '\0'; 1017 1018 return command_Interpret(buff, nb, argv); 1019 } 1020 1021 int 1022 command_Interpret(char *buff, int nb, char *argv[MAXARGS]) 1023 { 1024 char *cp; 1025 1026 if (nb > 0) { 1027 cp = buff + strcspn(buff, "\r\n"); 1028 if (cp) 1029 *cp = '\0'; 1030 return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE); 1031 } 1032 return 0; 1033 } 1034 1035 static int 1036 arghidden(int argc, char const *const *argv, int n) 1037 { 1038 /* Is arg n of the given command to be hidden from the log ? */ 1039 1040 /* set authkey xxxxx */ 1041 /* set key xxxxx */ 1042 if (n == 2 && !strncasecmp(argv[0], "se", 2) && 1043 (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) 1044 return 1; 1045 1046 /* passwd xxxxx */ 1047 if (n == 1 && !strncasecmp(argv[0], "p", 1)) 1048 return 1; 1049 1050 /* set server port xxxxx .... */ 1051 if (n == 3 && !strncasecmp(argv[0], "se", 2) && 1052 !strncasecmp(argv[1], "se", 2)) 1053 return 1; 1054 1055 return 0; 1056 } 1057 1058 void 1059 command_Run(struct bundle *bundle, int argc, char const *const *argv, 1060 struct prompt *prompt, const char *label, struct datalink *cx) 1061 { 1062 if (argc > 0) { 1063 if (log_IsKept(LogCOMMAND)) { 1064 char buf[LINE_LEN]; 1065 int f, n; 1066 1067 if (label) { 1068 strncpy(buf, label, sizeof buf - 3); 1069 buf[sizeof buf - 3] = '\0'; 1070 strcat(buf, ": "); 1071 n = strlen(buf); 1072 } else { 1073 *buf = '\0'; 1074 n = 0; 1075 } 1076 buf[sizeof buf - 1] = '\0'; /* In case we run out of room in buf */ 1077 1078 for (f = 0; f < argc; f++) { 1079 if (n < sizeof buf - 1 && f) 1080 buf[n++] = ' '; 1081 if (arghidden(argc, argv, f)) 1082 strncpy(buf+n, "********", sizeof buf - n - 1); 1083 else 1084 strncpy(buf+n, argv[f], sizeof buf - n - 1); 1085 n += strlen(buf+n); 1086 } 1087 log_Printf(LogCOMMAND, "%s\n", buf); 1088 } 1089 FindExec(bundle, Commands, argc, 0, argv, prompt, cx); 1090 } 1091 } 1092 1093 int 1094 command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, 1095 const char *label) 1096 { 1097 int argc; 1098 char *argv[MAXARGS]; 1099 1100 if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0) 1101 return 0; 1102 1103 command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); 1104 return 1; 1105 } 1106 1107 static int 1108 ShowCommand(struct cmdargs const *arg) 1109 { 1110 if (!arg->prompt) 1111 log_Printf(LogWARN, "show: Cannot show without a prompt\n"); 1112 else if (arg->argc > arg->argn) 1113 FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, 1114 arg->prompt, arg->cx); 1115 else 1116 prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); 1117 1118 return 0; 1119 } 1120 1121 static int 1122 TerminalCommand(struct cmdargs const *arg) 1123 { 1124 if (!arg->prompt) { 1125 log_Printf(LogWARN, "term: Need a prompt\n"); 1126 return 1; 1127 } 1128 1129 if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { 1130 prompt_Printf(arg->prompt, "LCP state is [%s]\n", 1131 State2Nam(arg->cx->physical->link.lcp.fsm.state)); 1132 return 1; 1133 } 1134 1135 datalink_Up(arg->cx, 0, 0); 1136 prompt_TtyTermMode(arg->prompt, arg->cx); 1137 return 0; 1138 } 1139 1140 static int 1141 QuitCommand(struct cmdargs const *arg) 1142 { 1143 if (!arg->prompt || prompt_IsController(arg->prompt) || 1144 (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && 1145 (arg->prompt->auth & LOCAL_AUTH))) 1146 Cleanup(EX_NORMAL); 1147 if (arg->prompt) 1148 prompt_Destroy(arg->prompt, 1); 1149 1150 return 0; 1151 } 1152 1153 static int 1154 OpenCommand(struct cmdargs const *arg) 1155 { 1156 if (arg->argc == arg->argn) 1157 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 1158 else if (arg->argc == arg->argn + 1) { 1159 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1160 struct datalink *cx = arg->cx ? 1161 arg->cx : bundle2datalink(arg->bundle, NULL); 1162 if (cx) { 1163 if (cx->physical->link.lcp.fsm.state == ST_OPENED) 1164 fsm_Reopen(&cx->physical->link.lcp.fsm); 1165 else 1166 bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); 1167 } else 1168 log_Printf(LogWARN, "open lcp: You must specify a link\n"); 1169 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1170 struct fsm *fp; 1171 1172 fp = &command_ChooseLink(arg)->ccp.fsm; 1173 if (fp->link->lcp.fsm.state != ST_OPENED) 1174 log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); 1175 else if (fp->state == ST_OPENED) 1176 fsm_Reopen(fp); 1177 else { 1178 fp->open_mode = 0; /* Not passive any more */ 1179 if (fp->state == ST_STOPPED) { 1180 fsm_Down(fp); 1181 fsm_Up(fp); 1182 } else { 1183 fsm_Up(fp); 1184 fsm_Open(fp); 1185 } 1186 } 1187 } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { 1188 if (arg->cx) 1189 log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); 1190 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 1191 fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); 1192 else 1193 bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); 1194 } else 1195 return -1; 1196 } else 1197 return -1; 1198 1199 return 0; 1200 } 1201 1202 static int 1203 CloseCommand(struct cmdargs const *arg) 1204 { 1205 if (arg->argc == arg->argn) 1206 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); 1207 else if (arg->argc == arg->argn + 1) { 1208 if (!strcasecmp(arg->argv[arg->argn], "lcp")) 1209 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); 1210 else if (!strcasecmp(arg->argv[arg->argn], "ccp") || 1211 !strcasecmp(arg->argv[arg->argn], "ccp!")) { 1212 struct fsm *fp; 1213 1214 fp = &command_ChooseLink(arg)->ccp.fsm; 1215 if (fp->state == ST_OPENED) { 1216 fsm_Close(fp); 1217 if (arg->argv[arg->argn][3] == '!') 1218 fp->open_mode = 0; /* Stay ST_CLOSED */ 1219 else 1220 fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ 1221 } 1222 } else 1223 return -1; 1224 } else 1225 return -1; 1226 1227 return 0; 1228 } 1229 1230 static int 1231 DownCommand(struct cmdargs const *arg) 1232 { 1233 if (arg->argc == arg->argn) { 1234 if (arg->cx) 1235 datalink_Down(arg->cx, CLOSE_STAYDOWN); 1236 else 1237 bundle_Down(arg->bundle, CLOSE_STAYDOWN); 1238 } else if (arg->argc == arg->argn + 1) { 1239 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1240 if (arg->cx) 1241 datalink_Down(arg->cx, CLOSE_LCP); 1242 else 1243 bundle_Down(arg->bundle, CLOSE_LCP); 1244 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1245 struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : 1246 &arg->bundle->ncp.mp.link.ccp.fsm; 1247 fsm2initial(fp); 1248 } else 1249 return -1; 1250 } else 1251 return -1; 1252 1253 return 0; 1254 } 1255 1256 static int 1257 SetModemSpeed(struct cmdargs const *arg) 1258 { 1259 long speed; 1260 char *end; 1261 1262 if (arg->argc > arg->argn && *arg->argv[arg->argn]) { 1263 if (arg->argc > arg->argn+1) { 1264 log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n"); 1265 return -1; 1266 } 1267 if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { 1268 physical_SetSync(arg->cx->physical); 1269 return 0; 1270 } 1271 end = NULL; 1272 speed = strtol(arg->argv[arg->argn], &end, 10); 1273 if (*end) { 1274 log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", 1275 arg->argv[arg->argn]); 1276 return -1; 1277 } 1278 if (physical_SetSpeed(arg->cx->physical, speed)) 1279 return 0; 1280 log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); 1281 } else 1282 log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); 1283 1284 return -1; 1285 } 1286 1287 static int 1288 SetStoppedTimeout(struct cmdargs const *arg) 1289 { 1290 struct link *l = &arg->cx->physical->link; 1291 1292 l->lcp.fsm.StoppedTimer.load = 0; 1293 l->ccp.fsm.StoppedTimer.load = 0; 1294 if (arg->argc <= arg->argn+2) { 1295 if (arg->argc > arg->argn) { 1296 l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; 1297 if (arg->argc > arg->argn+1) 1298 l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; 1299 } 1300 return 0; 1301 } 1302 return -1; 1303 } 1304 1305 static int 1306 SetServer(struct cmdargs const *arg) 1307 { 1308 int res = -1; 1309 1310 if (arg->argc > arg->argn && arg->argc < arg->argn+4) { 1311 const char *port, *passwd, *mask; 1312 int mlen; 1313 1314 /* What's what ? */ 1315 port = arg->argv[arg->argn]; 1316 if (arg->argc == arg->argn + 2) { 1317 passwd = arg->argv[arg->argn+1]; 1318 mask = NULL; 1319 } else if (arg->argc == arg->argn + 3) { 1320 passwd = arg->argv[arg->argn+1]; 1321 mask = arg->argv[arg->argn+2]; 1322 mlen = strlen(mask); 1323 if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen || 1324 (mlen == 4 && *mask != '0')) { 1325 log_Printf(LogWARN, "%s %s: %s: Invalid mask\n", 1326 arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask); 1327 return -1; 1328 } 1329 } else if (arg->argc != arg->argn + 1) 1330 return -1; 1331 else if (strcasecmp(port, "none") == 0) { 1332 if (server_Clear(arg->bundle)) 1333 log_Printf(LogPHASE, "Disabled server socket\n"); 1334 return 0; 1335 } else if (strcasecmp(port, "open") == 0) { 1336 switch (server_Reopen(arg->bundle)) { 1337 case SERVER_OK: 1338 return 0; 1339 case SERVER_FAILED: 1340 log_Printf(LogWARN, "Failed to reopen server port\n"); 1341 return 1; 1342 case SERVER_UNSET: 1343 log_Printf(LogWARN, "Cannot reopen unset server socket\n"); 1344 return 1; 1345 default: 1346 break; 1347 } 1348 return -1; 1349 } else if (strcasecmp(port, "closed") == 0) { 1350 if (server_Close(arg->bundle)) 1351 log_Printf(LogPHASE, "Closed server socket\n"); 1352 else 1353 log_Printf(LogWARN, "Server socket not open\n"); 1354 1355 return 0; 1356 } else 1357 return -1; 1358 1359 strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1); 1360 server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0'; 1361 1362 if (*port == '/') { 1363 mode_t imask; 1364 char *ptr, name[LINE_LEN + 12]; 1365 1366 if (mask == NULL) 1367 imask = (mode_t)-1; 1368 else for (imask = mlen = 0; mask[mlen]; mlen++) 1369 imask = (imask * 8) + mask[mlen] - '0'; 1370 1371 ptr = strstr(port, "%d"); 1372 if (ptr) { 1373 snprintf(name, sizeof name, "%.*s%d%s", 1374 (int)(ptr - port), port, arg->bundle->unit, ptr + 2); 1375 port = name; 1376 } 1377 res = server_LocalOpen(arg->bundle, port, imask); 1378 } else { 1379 int iport, add = 0; 1380 1381 if (mask != NULL) 1382 return -1; 1383 1384 if (*port == '+') { 1385 port++; 1386 add = 1; 1387 } 1388 if (strspn(port, "0123456789") != strlen(port)) { 1389 struct servent *s; 1390 1391 if ((s = getservbyname(port, "tcp")) == NULL) { 1392 iport = 0; 1393 log_Printf(LogWARN, "%s: Invalid port or service\n", port); 1394 } else 1395 iport = ntohs(s->s_port); 1396 } else 1397 iport = atoi(port); 1398 1399 if (iport) { 1400 if (add) 1401 iport += arg->bundle->unit; 1402 res = server_TcpOpen(arg->bundle, iport); 1403 } else 1404 res = -1; 1405 } 1406 } 1407 1408 return res; 1409 } 1410 1411 static int 1412 SetEscape(struct cmdargs const *arg) 1413 { 1414 int code; 1415 int argc = arg->argc - arg->argn; 1416 char const *const *argv = arg->argv + arg->argn; 1417 1418 for (code = 0; code < 33; code++) 1419 arg->cx->physical->async.cfg.EscMap[code] = 0; 1420 1421 while (argc-- > 0) { 1422 sscanf(*argv++, "%x", &code); 1423 code &= 0xff; 1424 arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); 1425 arg->cx->physical->async.cfg.EscMap[32] = 1; 1426 } 1427 return 0; 1428 } 1429 1430 static int 1431 SetInterfaceAddr(struct cmdargs const *arg) 1432 { 1433 struct ncp *ncp = &arg->bundle->ncp; 1434 struct ncpaddr ncpaddr; 1435 const char *hisaddr; 1436 1437 if (arg->argc > arg->argn + 4) 1438 return -1; 1439 1440 hisaddr = NULL; 1441 memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range); 1442 memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range); 1443 ncp->ipcp.cfg.HaveTriggerAddress = 0; 1444 ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY; 1445 iplist_reset(&ncp->ipcp.cfg.peer_list); 1446 1447 if (arg->argc > arg->argn) { 1448 if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn])) 1449 return 1; 1450 if (arg->argc > arg->argn+1) { 1451 hisaddr = arg->argv[arg->argn+1]; 1452 if (arg->argc > arg->argn+2) { 1453 ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask = 1454 GetIpAddr(arg->argv[arg->argn+2]); 1455 if (arg->argc > arg->argn+3) { 1456 ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); 1457 ncp->ipcp.cfg.HaveTriggerAddress = 1; 1458 } 1459 } 1460 } 1461 } 1462 1463 /* 0.0.0.0 means any address (0 bits) */ 1464 ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip); 1465 ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr); 1466 if (ncp->ipcp.my_ip.s_addr == INADDR_ANY) 1467 ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0); 1468 bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL); 1469 1470 if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, 1471 arg->bundle->phys_type.all & PHYS_AUTO)) 1472 return 4; 1473 1474 return 0; 1475 } 1476 1477 static int 1478 SetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq, 1479 u_int *maxtrm, int def) 1480 { 1481 if (argc == 0) { 1482 *timeout = DEF_FSMRETRY; 1483 *maxreq = def; 1484 if (maxtrm != NULL) 1485 *maxtrm = def; 1486 } else { 1487 long l = atol(argv[0]); 1488 1489 if (l < MIN_FSMRETRY) { 1490 log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n", 1491 l, MIN_FSMRETRY); 1492 return 1; 1493 } else 1494 *timeout = l; 1495 1496 if (argc > 1) { 1497 l = atol(argv[1]); 1498 if (l < 1) { 1499 log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l); 1500 l = 1; 1501 } 1502 *maxreq = l; 1503 1504 if (argc > 2 && maxtrm != NULL) { 1505 l = atol(argv[2]); 1506 if (l < 1) { 1507 log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l); 1508 l = 1; 1509 } 1510 *maxtrm = l; 1511 } 1512 } 1513 } 1514 1515 return 0; 1516 } 1517 1518 static int 1519 SetVariable(struct cmdargs const *arg) 1520 { 1521 long long_val, param = (long)arg->cmd->args; 1522 int mode, dummyint, f, first, res; 1523 u_short *change; 1524 const char *argp; 1525 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 1526 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 1527 struct in_addr *ipaddr; 1528 struct ncpaddr ncpaddr[2]; 1529 1530 if (arg->argc > arg->argn) 1531 argp = arg->argv[arg->argn]; 1532 else 1533 argp = ""; 1534 1535 res = 0; 1536 1537 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 1538 log_Printf(LogWARN, "set %s: No context (use the `link' command)\n", 1539 arg->cmd->name); 1540 return 1; 1541 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 1542 log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", 1543 arg->cmd->name, cx->name); 1544 cx = NULL; 1545 } 1546 1547 switch (param) { 1548 case VAR_AUTHKEY: 1549 strncpy(arg->bundle->cfg.auth.key, argp, 1550 sizeof arg->bundle->cfg.auth.key - 1); 1551 arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; 1552 break; 1553 1554 case VAR_AUTHNAME: 1555 switch (bundle_Phase(arg->bundle)) { 1556 default: 1557 log_Printf(LogWARN, "Altering authname while at phase %s\n", 1558 bundle_PhaseName(arg->bundle)); 1559 /* drop through */ 1560 case PHASE_DEAD: 1561 case PHASE_ESTABLISH: 1562 strncpy(arg->bundle->cfg.auth.name, argp, 1563 sizeof arg->bundle->cfg.auth.name - 1); 1564 arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0'; 1565 break; 1566 } 1567 break; 1568 1569 case VAR_AUTOLOAD: 1570 if (arg->argc == arg->argn + 3) { 1571 int v1, v2, v3; 1572 char *end; 1573 1574 v1 = strtol(arg->argv[arg->argn], &end, 0); 1575 if (v1 < 0 || *end) { 1576 log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n", 1577 arg->argv[arg->argn]); 1578 res = 1; 1579 break; 1580 } 1581 1582 v2 = strtol(arg->argv[arg->argn + 1], &end, 0); 1583 if (v2 < 0 || *end) { 1584 log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n", 1585 arg->argv[arg->argn + 1]); 1586 res = 1; 1587 break; 1588 } 1589 if (v2 < v1) { 1590 v3 = v1; 1591 v1 = v2; 1592 v2 = v3; 1593 } 1594 1595 v3 = strtol(arg->argv[arg->argn + 2], &end, 0); 1596 if (v3 <= 0 || *end) { 1597 log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n", 1598 arg->argv[arg->argn + 2]); 1599 res = 1; 1600 break; 1601 } 1602 1603 arg->bundle->ncp.mp.cfg.autoload.min = v1; 1604 arg->bundle->ncp.mp.cfg.autoload.max = v2; 1605 arg->bundle->ncp.mp.cfg.autoload.period = v3; 1606 mp_RestartAutoloadTimer(&arg->bundle->ncp.mp); 1607 } else { 1608 log_Printf(LogWARN, "Set autoload requires three arguments\n"); 1609 res = 1; 1610 } 1611 break; 1612 1613 case VAR_DIAL: 1614 strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); 1615 cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; 1616 break; 1617 1618 case VAR_LOGIN: 1619 strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); 1620 cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; 1621 break; 1622 1623 case VAR_WINSIZE: 1624 if (arg->argc > arg->argn) { 1625 l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); 1626 if (l->ccp.cfg.deflate.out.winsize < 8 || 1627 l->ccp.cfg.deflate.out.winsize > 15) { 1628 log_Printf(LogWARN, "%d: Invalid outgoing window size\n", 1629 l->ccp.cfg.deflate.out.winsize); 1630 l->ccp.cfg.deflate.out.winsize = 15; 1631 } 1632 if (arg->argc > arg->argn+1) { 1633 l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); 1634 if (l->ccp.cfg.deflate.in.winsize < 8 || 1635 l->ccp.cfg.deflate.in.winsize > 15) { 1636 log_Printf(LogWARN, "%d: Invalid incoming window size\n", 1637 l->ccp.cfg.deflate.in.winsize); 1638 l->ccp.cfg.deflate.in.winsize = 15; 1639 } 1640 } else 1641 l->ccp.cfg.deflate.in.winsize = 0; 1642 } else { 1643 log_Printf(LogWARN, "No window size specified\n"); 1644 res = 1; 1645 } 1646 break; 1647 1648 #ifdef HAVE_DES 1649 case VAR_MPPE: 1650 if (arg->argc > arg->argn + 2) { 1651 res = -1; 1652 break; 1653 } 1654 1655 if (arg->argc == arg->argn) { 1656 l->ccp.cfg.mppe.keybits = 0; 1657 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1658 l->ccp.cfg.mppe.required = 0; 1659 break; 1660 } 1661 1662 if (!strcmp(argp, "*")) 1663 long_val = 0; 1664 else { 1665 long_val = atol(argp); 1666 if (long_val != 40 && long_val != 56 && long_val != 128) { 1667 log_Printf(LogWARN, "%s: Invalid bits value\n", argp); 1668 res = -1; 1669 break; 1670 } 1671 } 1672 1673 if (arg->argc == arg->argn + 2) { 1674 if (!strcmp(arg->argv[arg->argn + 1], "*")) 1675 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1676 else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless")) 1677 l->ccp.cfg.mppe.state = MPPE_STATELESS; 1678 else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful")) 1679 l->ccp.cfg.mppe.state = MPPE_STATEFUL; 1680 else { 1681 log_Printf(LogWARN, "%s: Invalid state value\n", 1682 arg->argv[arg->argn + 1]); 1683 res = -1; 1684 break; 1685 } 1686 } else 1687 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1688 l->ccp.cfg.mppe.keybits = long_val; 1689 l->ccp.cfg.mppe.required = 1; 1690 break; 1691 #endif 1692 1693 case VAR_DEVICE: 1694 physical_SetDeviceList(cx->physical, arg->argc - arg->argn, 1695 arg->argv + arg->argn); 1696 break; 1697 1698 case VAR_ACCMAP: 1699 if (arg->argc > arg->argn) { 1700 u_long ulong_val; 1701 sscanf(argp, "%lx", &ulong_val); 1702 cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; 1703 } else { 1704 log_Printf(LogWARN, "No accmap specified\n"); 1705 res = 1; 1706 } 1707 break; 1708 1709 case VAR_MODE: 1710 mode = Nam2mode(argp); 1711 if (mode == PHYS_NONE || mode == PHYS_ALL) { 1712 log_Printf(LogWARN, "%s: Invalid mode\n", argp); 1713 res = -1; 1714 break; 1715 } 1716 bundle_SetMode(arg->bundle, cx, mode); 1717 break; 1718 1719 case VAR_MRRU: 1720 switch (bundle_Phase(arg->bundle)) { 1721 case PHASE_DEAD: 1722 break; 1723 case PHASE_ESTABLISH: 1724 /* Make sure none of our links are DATALINK_LCP or greater */ 1725 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 1726 log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n"); 1727 res = 1; 1728 break; 1729 } 1730 break; 1731 default: 1732 log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n"); 1733 res = 1; 1734 break; 1735 } 1736 if (res != 0) 1737 break; 1738 long_val = atol(argp); 1739 if (long_val && long_val < MIN_MRU) { 1740 log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); 1741 res = 1; 1742 break; 1743 } else if (long_val > MAX_MRU) { 1744 log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); 1745 res = 1; 1746 break; 1747 } else 1748 arg->bundle->ncp.mp.cfg.mrru = long_val; 1749 break; 1750 1751 case VAR_MRU: 1752 long_val = 0; /* silence gcc */ 1753 change = NULL; /* silence gcc */ 1754 switch(arg->argc - arg->argn) { 1755 case 1: 1756 if (argp[strspn(argp, "0123456789")] != '\0') { 1757 res = -1; 1758 break; 1759 } 1760 /*FALLTHRU*/ 1761 case 0: 1762 long_val = atol(argp); 1763 change = &l->lcp.cfg.mru; 1764 if (long_val > l->lcp.cfg.max_mru) { 1765 log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val, 1766 l->lcp.cfg.max_mru); 1767 res = 1; 1768 break; 1769 } 1770 break; 1771 case 2: 1772 if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) { 1773 res = -1; 1774 break; 1775 } 1776 long_val = atol(arg->argv[arg->argn + 1]); 1777 change = &l->lcp.cfg.max_mru; 1778 if (long_val > MAX_MRU) { 1779 log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val, 1780 MAX_MRU); 1781 res = 1; 1782 break; 1783 } 1784 break; 1785 default: 1786 res = -1; 1787 break; 1788 } 1789 if (res != 0) 1790 break; 1791 1792 if (long_val == 0) 1793 *change = 0; 1794 else if (long_val < MIN_MRU) { 1795 log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); 1796 res = 1; 1797 break; 1798 } else if (long_val > MAX_MRU) { 1799 log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); 1800 res = 1; 1801 break; 1802 } else 1803 *change = long_val; 1804 if (l->lcp.cfg.mru > *change) 1805 l->lcp.cfg.mru = *change; 1806 break; 1807 1808 case VAR_MTU: 1809 long_val = 0; /* silence gcc */ 1810 change = NULL; /* silence gcc */ 1811 switch(arg->argc - arg->argn) { 1812 case 1: 1813 if (argp[strspn(argp, "0123456789")] != '\0') { 1814 res = -1; 1815 break; 1816 } 1817 /*FALLTHRU*/ 1818 case 0: 1819 long_val = atol(argp); 1820 change = &l->lcp.cfg.mtu; 1821 if (long_val > l->lcp.cfg.max_mtu) { 1822 log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val, 1823 l->lcp.cfg.max_mtu); 1824 res = 1; 1825 break; 1826 } 1827 break; 1828 case 2: 1829 if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) { 1830 res = -1; 1831 break; 1832 } 1833 long_val = atol(arg->argv[arg->argn + 1]); 1834 change = &l->lcp.cfg.max_mtu; 1835 if (long_val > MAX_MTU) { 1836 log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val, 1837 MAX_MTU); 1838 res = 1; 1839 break; 1840 } 1841 break; 1842 default: 1843 res = -1; 1844 break; 1845 } 1846 1847 if (res != 0) 1848 break; 1849 1850 if (long_val && long_val < MIN_MTU) { 1851 log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); 1852 res = 1; 1853 break; 1854 } else if (long_val > MAX_MTU) { 1855 log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); 1856 res = 1; 1857 break; 1858 } else 1859 *change = long_val; 1860 if (l->lcp.cfg.mtu > *change) 1861 l->lcp.cfg.mtu = *change; 1862 break; 1863 1864 case VAR_OPENMODE: 1865 if (strcasecmp(argp, "active") == 0) 1866 cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? 1867 atoi(arg->argv[arg->argn+1]) : 1; 1868 else if (strcasecmp(argp, "passive") == 0) 1869 cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; 1870 else { 1871 log_Printf(LogWARN, "%s: Invalid openmode\n", argp); 1872 res = 1; 1873 } 1874 break; 1875 1876 case VAR_PHONE: 1877 strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); 1878 cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; 1879 cx->phone.alt = cx->phone.next = NULL; 1880 break; 1881 1882 case VAR_HANGUP: 1883 strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); 1884 cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; 1885 break; 1886 1887 case VAR_IFQUEUE: 1888 long_val = atol(argp); 1889 arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val; 1890 break; 1891 1892 case VAR_LOGOUT: 1893 strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1); 1894 cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0'; 1895 break; 1896 1897 case VAR_IDLETIMEOUT: 1898 if (arg->argc > arg->argn+2) { 1899 log_Printf(LogWARN, "Too many idle timeout values\n"); 1900 res = 1; 1901 } else if (arg->argc == arg->argn) { 1902 log_Printf(LogWARN, "Too few idle timeout values\n"); 1903 res = 1; 1904 } else { 1905 int timeout, min; 1906 1907 timeout = atoi(argp); 1908 min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1; 1909 bundle_SetIdleTimer(arg->bundle, timeout, min); 1910 } 1911 break; 1912 1913 case VAR_LQRPERIOD: 1914 long_val = atol(argp); 1915 if (long_val < MIN_LQRPERIOD) { 1916 log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", 1917 long_val, MIN_LQRPERIOD); 1918 res = 1; 1919 } else 1920 l->lcp.cfg.lqrperiod = long_val; 1921 break; 1922 1923 case VAR_LCPRETRY: 1924 res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1925 &cx->physical->link.lcp.cfg.fsm.timeout, 1926 &cx->physical->link.lcp.cfg.fsm.maxreq, 1927 &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1928 break; 1929 1930 case VAR_CHAPRETRY: 1931 res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1932 &cx->chap.auth.cfg.fsm.timeout, 1933 &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES); 1934 break; 1935 1936 case VAR_PAPRETRY: 1937 res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1938 &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq, 1939 NULL, DEF_FSMAUTHTRIES); 1940 break; 1941 1942 case VAR_CCPRETRY: 1943 res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1944 &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq, 1945 &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1946 break; 1947 1948 case VAR_IPCPRETRY: 1949 res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1950 &arg->bundle->ncp.ipcp.cfg.fsm.timeout, 1951 &arg->bundle->ncp.ipcp.cfg.fsm.maxreq, 1952 &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1953 break; 1954 1955 case VAR_NBNS: 1956 case VAR_DNS: 1957 if (param == VAR_DNS) { 1958 ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns; 1959 ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE; 1960 } else { 1961 ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns; 1962 ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY; 1963 } 1964 1965 if (arg->argc > arg->argn) { 1966 ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]); 1967 if (!ncpaddr_getip4(ncpaddr, ipaddr)) 1968 return -1; 1969 if (arg->argc > arg->argn+1) { 1970 ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]); 1971 if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1)) 1972 return -1; 1973 } 1974 1975 if (ipaddr[0].s_addr == INADDR_ANY) { 1976 ipaddr[0] = ipaddr[1]; 1977 ipaddr[1].s_addr = INADDR_ANY; 1978 } 1979 if (ipaddr[0].s_addr == INADDR_NONE) { 1980 ipaddr[0] = ipaddr[1]; 1981 ipaddr[1].s_addr = INADDR_NONE; 1982 } 1983 } 1984 break; 1985 1986 case VAR_CALLBACK: 1987 cx->cfg.callback.opmask = 0; 1988 for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { 1989 if (!strcasecmp(arg->argv[dummyint], "auth")) 1990 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); 1991 else if (!strcasecmp(arg->argv[dummyint], "cbcp")) 1992 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); 1993 else if (!strcasecmp(arg->argv[dummyint], "e.164")) { 1994 if (dummyint == arg->argc - 1) 1995 log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); 1996 else { 1997 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); 1998 strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], 1999 sizeof cx->cfg.callback.msg - 1); 2000 cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; 2001 } 2002 } else if (!strcasecmp(arg->argv[dummyint], "none")) 2003 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); 2004 else { 2005 res = -1; 2006 break; 2007 } 2008 } 2009 if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) 2010 cx->cfg.callback.opmask = 0; 2011 break; 2012 2013 case VAR_CBCP: 2014 cx->cfg.cbcp.delay = 0; 2015 *cx->cfg.cbcp.phone = '\0'; 2016 cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; 2017 if (arg->argc > arg->argn) { 2018 strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], 2019 sizeof cx->cfg.cbcp.phone - 1); 2020 cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; 2021 if (arg->argc > arg->argn + 1) { 2022 cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); 2023 if (arg->argc > arg->argn + 2) { 2024 long_val = atol(arg->argv[arg->argn + 2]); 2025 if (long_val < MIN_FSMRETRY) 2026 log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", 2027 long_val, MIN_FSMRETRY); 2028 else 2029 cx->cfg.cbcp.fsmretry = long_val; 2030 } 2031 } 2032 } 2033 break; 2034 2035 case VAR_CHOKED: 2036 arg->bundle->cfg.choked.timeout = atoi(argp); 2037 if (arg->bundle->cfg.choked.timeout <= 0) 2038 arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; 2039 break; 2040 2041 case VAR_SENDPIPE: 2042 long_val = atol(argp); 2043 arg->bundle->ncp.cfg.sendpipe = long_val; 2044 break; 2045 2046 case VAR_RECVPIPE: 2047 long_val = atol(argp); 2048 arg->bundle->ncp.cfg.recvpipe = long_val; 2049 break; 2050 2051 #ifndef NORADIUS 2052 case VAR_RADIUS: 2053 if (!*argp) 2054 *arg->bundle->radius.cfg.file = '\0'; 2055 else if (access(argp, R_OK)) { 2056 log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno)); 2057 res = 1; 2058 break; 2059 } else { 2060 strncpy(arg->bundle->radius.cfg.file, argp, 2061 sizeof arg->bundle->radius.cfg.file - 1); 2062 arg->bundle->radius.cfg.file 2063 [sizeof arg->bundle->radius.cfg.file - 1] = '\0'; 2064 } 2065 break; 2066 #endif 2067 2068 case VAR_CD: 2069 if (*argp) { 2070 if (strcasecmp(argp, "off")) { 2071 long_val = atol(argp); 2072 if (long_val < 0) 2073 long_val = 0; 2074 cx->physical->cfg.cd.delay = long_val; 2075 cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ? 2076 CD_REQUIRED : CD_VARIABLE; 2077 } else 2078 cx->physical->cfg.cd.necessity = CD_NOTREQUIRED; 2079 } else { 2080 cx->physical->cfg.cd.delay = 0; 2081 cx->physical->cfg.cd.necessity = CD_DEFAULT; 2082 } 2083 break; 2084 2085 case VAR_PARITY: 2086 if (arg->argc == arg->argn + 1) 2087 res = physical_SetParity(arg->cx->physical, argp); 2088 else { 2089 log_Printf(LogWARN, "Parity value must be odd, even or none\n"); 2090 res = 1; 2091 } 2092 break; 2093 2094 case VAR_CRTSCTS: 2095 if (strcasecmp(argp, "on") == 0) 2096 physical_SetRtsCts(arg->cx->physical, 1); 2097 else if (strcasecmp(argp, "off") == 0) 2098 physical_SetRtsCts(arg->cx->physical, 0); 2099 else { 2100 log_Printf(LogWARN, "RTS/CTS value must be on or off\n"); 2101 res = 1; 2102 } 2103 break; 2104 2105 case VAR_URGENTPORTS: 2106 if (arg->argn == arg->argc) { 2107 ncp_SetUrgentTOS(&arg->bundle->ncp); 2108 ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); 2109 ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); 2110 } else if (!strcasecmp(arg->argv[arg->argn], "udp")) { 2111 ncp_SetUrgentTOS(&arg->bundle->ncp); 2112 if (arg->argn == arg->argc - 1) 2113 ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); 2114 else for (f = arg->argn + 1; f < arg->argc; f++) 2115 if (*arg->argv[f] == '+') 2116 ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); 2117 else if (*arg->argv[f] == '-') 2118 ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); 2119 else { 2120 if (f == arg->argn) 2121 ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); 2122 ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f])); 2123 } 2124 } else if (arg->argn == arg->argc - 1 && 2125 !strcasecmp(arg->argv[arg->argn], "none")) { 2126 ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); 2127 ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); 2128 ncp_ClearUrgentTOS(&arg->bundle->ncp); 2129 } else { 2130 ncp_SetUrgentTOS(&arg->bundle->ncp); 2131 first = arg->argn; 2132 if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc) 2133 ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); 2134 2135 for (f = first; f < arg->argc; f++) 2136 if (*arg->argv[f] == '+') 2137 ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); 2138 else if (*arg->argv[f] == '-') 2139 ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); 2140 else { 2141 if (f == first) 2142 ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); 2143 ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f])); 2144 } 2145 } 2146 break; 2147 } 2148 2149 return res; 2150 } 2151 2152 static struct cmdtab const SetCommands[] = { 2153 {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2154 "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, 2155 {"authkey", "key", SetVariable, LOCAL_AUTH, 2156 "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, 2157 {"authname", NULL, SetVariable, LOCAL_AUTH, 2158 "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, 2159 {"autoload", NULL, SetVariable, LOCAL_AUTH, 2160 "auto link [de]activation", "set autoload maxtime maxload mintime minload", 2161 (const void *)VAR_AUTOLOAD}, 2162 {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX, 2163 "datalink bandwidth", "set bandwidth value"}, 2164 {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2165 "callback control", "set callback [none|auth|cbcp|" 2166 "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, 2167 {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2168 "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", 2169 (const void *)VAR_CBCP}, 2170 {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2171 "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY}, 2172 {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement", 2173 "set cd value[!]", (const void *)VAR_CD}, 2174 {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX, 2175 "CHAP retries", "set chapretry value [attempts]", 2176 (const void *)VAR_CHAPRETRY}, 2177 {"choked", NULL, SetVariable, LOCAL_AUTH, 2178 "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, 2179 {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX, 2180 "Use hardware flow control", "set ctsrts [on|off]", 2181 (const char *)VAR_CRTSCTS}, 2182 {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2183 "deflate window sizes", "set deflate out-winsize in-winsize", 2184 (const void *) VAR_WINSIZE}, 2185 #ifdef HAVE_DES 2186 {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2187 "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]", 2188 (const void *) VAR_MPPE}, 2189 #endif 2190 {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, 2191 "physical device name", "set device|line device-name[,device-name]", 2192 (const void *) VAR_DEVICE}, 2193 {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2194 "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, 2195 {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", 2196 "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, 2197 {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, 2198 "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, 2199 {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, 2200 "escape characters", "set escape hex-digit ..."}, 2201 {"filter", NULL, filter_Set, LOCAL_AUTH, 2202 "packet filters", "set filter alive|dial|in|out rule-no permit|deny " 2203 "[src_addr[/width]] [dst_addr[/width]] [proto " 2204 "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, 2205 {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2206 "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, 2207 {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", 2208 "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, 2209 {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue", 2210 "set ifqueue packets", (const void *)VAR_IFQUEUE}, 2211 {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries", 2212 "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY}, 2213 {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries", 2214 "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY}, 2215 {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", 2216 "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|" 2217 "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."}, 2218 {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2219 "login script", "set login chat-script", (const void *) VAR_LOGIN}, 2220 {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2221 "logout script", "set logout chat-script", (const void *) VAR_LOGOUT}, 2222 {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2223 "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, 2224 {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", 2225 "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, 2226 {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", 2227 "set mrru value", (const void *)VAR_MRRU}, 2228 {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2229 "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU}, 2230 {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2231 "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU}, 2232 {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", 2233 "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, 2234 {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", 2235 "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, 2236 {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries", 2237 "set papretry value [attempts]", (const void *)VAR_PAPRETRY}, 2238 {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity", 2239 "set parity [odd|even|none]", (const void *)VAR_PARITY}, 2240 {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", 2241 "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, 2242 {"proctitle", "title", SetProcTitle, LOCAL_AUTH, 2243 "Process title", "set proctitle [value]"}, 2244 #ifndef NORADIUS 2245 {"radius", NULL, SetVariable, LOCAL_AUTH, 2246 "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS}, 2247 #endif 2248 {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, 2249 "Reconnect timeout", "set reconnect value ntries"}, 2250 {"recvpipe", NULL, SetVariable, LOCAL_AUTH, 2251 "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE}, 2252 {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, 2253 "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"}, 2254 {"sendpipe", NULL, SetVariable, LOCAL_AUTH, 2255 "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE}, 2256 {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port", 2257 "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"}, 2258 {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, 2259 "physical speed", "set speed value|sync"}, 2260 {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, 2261 "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, 2262 {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", 2263 "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, 2264 {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports", 2265 "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS}, 2266 {"vj", NULL, ipcp_vjset, LOCAL_AUTH, 2267 "vj values", "set vj slots|slotcomp [value]"}, 2268 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2269 "Display this message", "set help|? [command]", SetCommands}, 2270 {NULL, NULL, NULL}, 2271 }; 2272 2273 static int 2274 SetCommand(struct cmdargs const *arg) 2275 { 2276 if (arg->argc > arg->argn) 2277 FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, 2278 arg->prompt, arg->cx); 2279 else if (arg->prompt) 2280 prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for" 2281 " syntax help.\n"); 2282 else 2283 log_Printf(LogWARN, "set command must have arguments\n"); 2284 2285 return 0; 2286 } 2287 2288 static int 2289 AddCommand(struct cmdargs const *arg) 2290 { 2291 struct ncpaddr gw; 2292 struct ncprange dest; 2293 struct in_addr host; 2294 int dest_default, gw_arg, addrs; 2295 2296 if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) 2297 return -1; 2298 2299 addrs = 0; 2300 dest_default = 0; 2301 if (arg->argc == arg->argn + 2) { 2302 if (!strcasecmp(arg->argv[arg->argn], "default")) 2303 dest_default = 1; 2304 else { 2305 if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn])) 2306 return -1; 2307 if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) 2308 addrs = ROUTE_DSTMYADDR; 2309 else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7)) 2310 addrs = ROUTE_DSTMYADDR6; 2311 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) 2312 addrs = ROUTE_DSTHISADDR; 2313 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8)) 2314 addrs = ROUTE_DSTHISADDR6; 2315 else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4)) 2316 addrs = ROUTE_DSTDNS0; 2317 else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4)) 2318 addrs = ROUTE_DSTDNS1; 2319 } 2320 gw_arg = 1; 2321 } else { 2322 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2323 addrs = ROUTE_DSTMYADDR; 2324 host = arg->bundle->ncp.ipcp.my_ip; 2325 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2326 addrs = ROUTE_DSTHISADDR; 2327 host = arg->bundle->ncp.ipcp.peer_ip; 2328 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2329 addrs = ROUTE_DSTDNS0; 2330 host = arg->bundle->ncp.ipcp.ns.dns[0]; 2331 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2332 addrs = ROUTE_DSTDNS1; 2333 host = arg->bundle->ncp.ipcp.ns.dns[1]; 2334 } else { 2335 host = GetIpAddr(arg->argv[arg->argn]); 2336 if (host.s_addr == INADDR_NONE) { 2337 log_Printf(LogWARN, "%s: Invalid destination address\n", 2338 arg->argv[arg->argn]); 2339 return -1; 2340 } 2341 } 2342 ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1])); 2343 gw_arg = 2; 2344 } 2345 2346 if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) { 2347 ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip); 2348 addrs |= ROUTE_GWHISADDR; 2349 #ifndef NOINET6 2350 } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) { 2351 ncpaddr_copy(&gw, &arg->bundle->ncp.ipv6cp.hisaddr); 2352 addrs |= ROUTE_GWHISADDR6; 2353 #endif 2354 } else { 2355 if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) { 2356 log_Printf(LogWARN, "%s: Invalid gateway address\n", 2357 arg->argv[arg->argn + gw_arg]); 2358 return -1; 2359 } 2360 } 2361 2362 if (dest_default) 2363 ncprange_setdefault(&dest, ncpaddr_family(&gw)); 2364 2365 if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0, 2366 ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0) 2367 && addrs != ROUTE_STATIC) 2368 route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw); 2369 2370 return 0; 2371 } 2372 2373 static int 2374 DeleteCommand(struct cmdargs const *arg) 2375 { 2376 struct ncprange dest; 2377 int addrs; 2378 2379 if (arg->argc == arg->argn+1) { 2380 if(strcasecmp(arg->argv[arg->argn], "all") == 0) { 2381 route_IfDelete(arg->bundle, 0); 2382 route_DeleteAll(&arg->bundle->ncp.route); 2383 } else { 2384 addrs = 0; 2385 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2386 ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip); 2387 addrs = ROUTE_DSTMYADDR; 2388 #ifndef NOINET6 2389 } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) { 2390 ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr); 2391 addrs = ROUTE_DSTMYADDR6; 2392 #endif 2393 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2394 ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip); 2395 addrs = ROUTE_DSTHISADDR; 2396 #ifndef NOINET6 2397 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) { 2398 ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr); 2399 addrs = ROUTE_DSTHISADDR6; 2400 #endif 2401 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2402 ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]); 2403 addrs = ROUTE_DSTDNS0; 2404 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2405 ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]); 2406 addrs = ROUTE_DSTDNS1; 2407 } else { 2408 ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]); 2409 addrs = ROUTE_STATIC; 2410 } 2411 rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0); 2412 route_Delete(&arg->bundle->ncp.route, addrs, &dest); 2413 } 2414 } else 2415 return -1; 2416 2417 return 0; 2418 } 2419 2420 #ifndef NONAT 2421 static int 2422 NatEnable(struct cmdargs const *arg) 2423 { 2424 if (arg->argc == arg->argn+1) { 2425 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2426 if (!arg->bundle->NatEnabled) { 2427 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 2428 PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip); 2429 arg->bundle->NatEnabled = 1; 2430 } 2431 return 0; 2432 } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { 2433 arg->bundle->NatEnabled = 0; 2434 arg->bundle->cfg.opt &= ~OPT_IFACEALIAS; 2435 /* Don't iface_Clear() - there may be manually configured addresses */ 2436 return 0; 2437 } 2438 } 2439 2440 return -1; 2441 } 2442 2443 2444 static int 2445 NatOption(struct cmdargs const *arg) 2446 { 2447 long param = (long)arg->cmd->args; 2448 2449 if (arg->argc == arg->argn+1) { 2450 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2451 if (arg->bundle->NatEnabled) { 2452 PacketAliasSetMode(param, param); 2453 return 0; 2454 } 2455 log_Printf(LogWARN, "nat not enabled\n"); 2456 } else if (strcmp(arg->argv[arg->argn], "no") == 0) { 2457 if (arg->bundle->NatEnabled) { 2458 PacketAliasSetMode(0, param); 2459 return 0; 2460 } 2461 log_Printf(LogWARN, "nat not enabled\n"); 2462 } 2463 } 2464 return -1; 2465 } 2466 #endif /* #ifndef NONAT */ 2467 2468 static int 2469 LinkCommand(struct cmdargs const *arg) 2470 { 2471 if (arg->argc > arg->argn+1) { 2472 char namelist[LINE_LEN]; 2473 struct datalink *cx; 2474 char *name; 2475 int result = 0; 2476 2477 if (!strcmp(arg->argv[arg->argn], "*")) { 2478 struct datalink *dl; 2479 2480 cx = arg->bundle->links; 2481 while (cx) { 2482 /* Watch it, the command could be a ``remove'' */ 2483 dl = cx->next; 2484 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2485 arg->prompt, cx); 2486 for (cx = arg->bundle->links; cx; cx = cx->next) 2487 if (cx == dl) 2488 break; /* Pointer's still valid ! */ 2489 } 2490 } else { 2491 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2492 namelist[sizeof namelist - 1] = '\0'; 2493 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 2494 if (!bundle2datalink(arg->bundle, name)) { 2495 log_Printf(LogWARN, "link: %s: Invalid link name\n", name); 2496 return 1; 2497 } 2498 2499 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2500 namelist[sizeof namelist - 1] = '\0'; 2501 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { 2502 cx = bundle2datalink(arg->bundle, name); 2503 if (cx) 2504 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2505 arg->prompt, cx); 2506 else { 2507 log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); 2508 result++; 2509 } 2510 } 2511 } 2512 return result; 2513 } 2514 2515 log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax); 2516 return 2; 2517 } 2518 2519 struct link * 2520 command_ChooseLink(struct cmdargs const *arg) 2521 { 2522 if (arg->cx) 2523 return &arg->cx->physical->link; 2524 else if (!arg->bundle->ncp.mp.cfg.mrru) { 2525 struct datalink *dl = bundle2datalink(arg->bundle, NULL); 2526 if (dl) 2527 return &dl->physical->link; 2528 } 2529 return &arg->bundle->ncp.mp.link; 2530 } 2531 2532 static const char * 2533 ident_cmd(const char *cmd, unsigned *keep, unsigned *add) 2534 { 2535 const char *result; 2536 2537 switch (*cmd) { 2538 case 'A': 2539 case 'a': 2540 result = "accept"; 2541 *keep = NEG_MYMASK; 2542 *add = NEG_ACCEPTED; 2543 break; 2544 case 'D': 2545 case 'd': 2546 switch (cmd[1]) { 2547 case 'E': 2548 case 'e': 2549 result = "deny"; 2550 *keep = NEG_MYMASK; 2551 *add = 0; 2552 break; 2553 case 'I': 2554 case 'i': 2555 result = "disable"; 2556 *keep = NEG_HISMASK; 2557 *add = 0; 2558 break; 2559 default: 2560 return NULL; 2561 } 2562 break; 2563 case 'E': 2564 case 'e': 2565 result = "enable"; 2566 *keep = NEG_HISMASK; 2567 *add = NEG_ENABLED; 2568 break; 2569 default: 2570 return NULL; 2571 } 2572 2573 return result; 2574 } 2575 2576 static int 2577 OptSet(struct cmdargs const *arg) 2578 { 2579 int bit = (int)(long)arg->cmd->args; 2580 unsigned keep; /* Keep these bits */ 2581 unsigned add; /* Add these bits */ 2582 2583 if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL) 2584 return 1; 2585 2586 #ifndef NOINET6 2587 if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) { 2588 log_Printf(LogWARN, "IPv6 is not available on this machine\n"); 2589 return 1; 2590 } 2591 #endif 2592 2593 if (add) 2594 arg->bundle->cfg.opt |= bit; 2595 else 2596 arg->bundle->cfg.opt &= ~bit; 2597 2598 return 0; 2599 } 2600 2601 static int 2602 IfaceAliasOptSet(struct cmdargs const *arg) 2603 { 2604 unsigned save = arg->bundle->cfg.opt; 2605 int result = OptSet(arg); 2606 2607 if (result == 0) 2608 if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) { 2609 arg->bundle->cfg.opt = save; 2610 log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n"); 2611 result = 2; 2612 } 2613 2614 return result; 2615 } 2616 2617 static int 2618 NegotiateSet(struct cmdargs const *arg) 2619 { 2620 long param = (long)arg->cmd->args; 2621 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 2622 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 2623 const char *cmd; 2624 unsigned keep; /* Keep these bits */ 2625 unsigned add; /* Add these bits */ 2626 2627 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2628 return 1; 2629 2630 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 2631 log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", 2632 cmd, arg->cmd->name); 2633 return 2; 2634 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 2635 log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", 2636 cmd, arg->cmd->name, cx->name); 2637 cx = NULL; 2638 } 2639 2640 switch (param) { 2641 case NEG_ACFCOMP: 2642 cx->physical->link.lcp.cfg.acfcomp &= keep; 2643 cx->physical->link.lcp.cfg.acfcomp |= add; 2644 break; 2645 case NEG_CHAP05: 2646 cx->physical->link.lcp.cfg.chap05 &= keep; 2647 cx->physical->link.lcp.cfg.chap05 |= add; 2648 break; 2649 #ifdef HAVE_DES 2650 case NEG_CHAP80: 2651 cx->physical->link.lcp.cfg.chap80nt &= keep; 2652 cx->physical->link.lcp.cfg.chap80nt |= add; 2653 break; 2654 case NEG_CHAP80LM: 2655 cx->physical->link.lcp.cfg.chap80lm &= keep; 2656 cx->physical->link.lcp.cfg.chap80lm |= add; 2657 break; 2658 case NEG_CHAP81: 2659 cx->physical->link.lcp.cfg.chap81 &= keep; 2660 cx->physical->link.lcp.cfg.chap81 |= add; 2661 break; 2662 case NEG_MPPE: 2663 l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep; 2664 l->ccp.cfg.neg[CCP_NEG_MPPE] |= add; 2665 break; 2666 #endif 2667 case NEG_DEFLATE: 2668 l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; 2669 l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; 2670 break; 2671 case NEG_DNS: 2672 arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; 2673 arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; 2674 break; 2675 case NEG_ENDDISC: 2676 arg->bundle->ncp.mp.cfg.negenddisc &= keep; 2677 arg->bundle->ncp.mp.cfg.negenddisc |= add; 2678 break; 2679 case NEG_LQR: 2680 cx->physical->link.lcp.cfg.lqr &= keep; 2681 cx->physical->link.lcp.cfg.lqr |= add; 2682 break; 2683 case NEG_PAP: 2684 cx->physical->link.lcp.cfg.pap &= keep; 2685 cx->physical->link.lcp.cfg.pap |= add; 2686 break; 2687 case NEG_PPPDDEFLATE: 2688 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; 2689 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; 2690 break; 2691 case NEG_PRED1: 2692 l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; 2693 l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; 2694 break; 2695 case NEG_PROTOCOMP: 2696 cx->physical->link.lcp.cfg.protocomp &= keep; 2697 cx->physical->link.lcp.cfg.protocomp |= add; 2698 break; 2699 case NEG_SHORTSEQ: 2700 switch (bundle_Phase(arg->bundle)) { 2701 case PHASE_DEAD: 2702 break; 2703 case PHASE_ESTABLISH: 2704 /* Make sure none of our links are DATALINK_LCP or greater */ 2705 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 2706 log_Printf(LogWARN, "shortseq: Only changable before" 2707 " LCP negotiations\n"); 2708 return 1; 2709 } 2710 break; 2711 default: 2712 log_Printf(LogWARN, "shortseq: Only changable at phase" 2713 " DEAD/ESTABLISH\n"); 2714 return 1; 2715 } 2716 arg->bundle->ncp.mp.cfg.shortseq &= keep; 2717 arg->bundle->ncp.mp.cfg.shortseq |= add; 2718 break; 2719 case NEG_VJCOMP: 2720 arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; 2721 arg->bundle->ncp.ipcp.cfg.vj.neg |= add; 2722 break; 2723 } 2724 2725 return 0; 2726 } 2727 2728 static struct cmdtab const NegotiateCommands[] = { 2729 {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH, 2730 "filter on PPPoUDP payloads", "disable|enable", 2731 (const void *)OPT_FILTERDECAP}, 2732 {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", 2733 "disable|enable", (const void *)OPT_IDCHECK}, 2734 {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH, 2735 "retain interface addresses", "disable|enable", 2736 (const void *)OPT_IFACEALIAS}, 2737 #ifndef NOINET6 2738 {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol", 2739 "disable|enable", (const void *)OPT_IPCP}, 2740 {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol", 2741 "disable|enable", (const void *)OPT_IPV6CP}, 2742 #endif 2743 {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader", 2744 "disable|enable", (const void *)OPT_KEEPSESSION}, 2745 {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", 2746 "disable|enable", (const void *)OPT_LOOPBACK}, 2747 {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", 2748 "disable|enable", (const void *)OPT_PASSWDAUTH}, 2749 {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry", 2750 "disable|enable", (const void *)OPT_PROXY}, 2751 {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts", 2752 "disable|enable", (const void *)OPT_PROXYALL}, 2753 {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", 2754 "disable|enable", (const void *)OPT_SROUTES}, 2755 {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options", 2756 "disable|enable", (const void *)OPT_TCPMSSFIXUP}, 2757 {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", 2758 "disable|enable", (const void *)OPT_THROUGHPUT}, 2759 {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", 2760 "disable|enable", (const void *)OPT_UTMP}, 2761 2762 #ifndef NOINET6 2763 #define OPT_MAX 13 /* accept/deny allowed below and not above */ 2764 #else 2765 #define OPT_MAX 11 2766 #endif 2767 2768 {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2769 "Address & Control field compression", "accept|deny|disable|enable", 2770 (const void *)NEG_ACFCOMP}, 2771 {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2772 "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", 2773 (const void *)NEG_CHAP05}, 2774 #ifdef HAVE_DES 2775 {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2776 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2777 (const void *)NEG_CHAP80}, 2778 {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2779 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2780 (const void *)NEG_CHAP80LM}, 2781 {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2782 "Microsoft CHAP v2", "accept|deny|disable|enable", 2783 (const void *)NEG_CHAP81}, 2784 {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2785 "MPPE encryption", "accept|deny|disable|enable", 2786 (const void *)NEG_MPPE}, 2787 #endif 2788 {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2789 "Deflate compression", "accept|deny|disable|enable", 2790 (const void *)NEG_DEFLATE}, 2791 {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2792 "Deflate (type 24) compression", "accept|deny|disable|enable", 2793 (const void *)NEG_PPPDDEFLATE}, 2794 {"dns", NULL, NegotiateSet, LOCAL_AUTH, 2795 "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, 2796 {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation", 2797 "accept|deny|disable|enable", (const void *)NEG_ENDDISC}, 2798 {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2799 "Link Quality Reports", "accept|deny|disable|enable", 2800 (const void *)NEG_LQR}, 2801 {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2802 "Password Authentication protocol", "accept|deny|disable|enable", 2803 (const void *)NEG_PAP}, 2804 {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2805 "Predictor 1 compression", "accept|deny|disable|enable", 2806 (const void *)NEG_PRED1}, 2807 {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2808 "Protocol field compression", "accept|deny|disable|enable", 2809 (const void *)NEG_PROTOCOMP}, 2810 {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, 2811 "MP Short Sequence Numbers", "accept|deny|disable|enable", 2812 (const void *)NEG_SHORTSEQ}, 2813 {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, 2814 "Van Jacobson header compression", "accept|deny|disable|enable", 2815 (const void *)NEG_VJCOMP}, 2816 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2817 "Display this message", "accept|deny|disable|enable help|? [value]", 2818 NegotiateCommands}, 2819 {NULL, NULL, NULL}, 2820 }; 2821 2822 static int 2823 NegotiateCommand(struct cmdargs const *arg) 2824 { 2825 if (arg->argc > arg->argn) { 2826 char const *argv[3]; 2827 unsigned keep, add; 2828 int n; 2829 2830 if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) 2831 return -1; 2832 argv[2] = NULL; 2833 2834 for (n = arg->argn; n < arg->argc; n++) { 2835 argv[1] = arg->argv[n]; 2836 FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? 2837 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); 2838 } 2839 } else if (arg->prompt) 2840 prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", 2841 arg->argv[arg->argn-1]); 2842 else 2843 log_Printf(LogWARN, "%s command must have arguments\n", 2844 arg->argv[arg->argn] ); 2845 2846 return 0; 2847 } 2848 2849 const char * 2850 command_ShowNegval(unsigned val) 2851 { 2852 switch (val&3) { 2853 case 1: return "disabled & accepted"; 2854 case 2: return "enabled & denied"; 2855 case 3: return "enabled & accepted"; 2856 } 2857 return "disabled & denied"; 2858 } 2859 2860 static int 2861 ClearCommand(struct cmdargs const *arg) 2862 { 2863 struct pppThroughput *t; 2864 struct datalink *cx; 2865 int i, clear_type; 2866 2867 if (arg->argc < arg->argn + 1) 2868 return -1; 2869 2870 if (strcasecmp(arg->argv[arg->argn], "physical") == 0) { 2871 cx = arg->cx; 2872 if (!cx) 2873 cx = bundle2datalink(arg->bundle, NULL); 2874 if (!cx) { 2875 log_Printf(LogWARN, "A link must be specified for ``clear physical''\n"); 2876 return 1; 2877 } 2878 t = &cx->physical->link.stats.total; 2879 } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) 2880 t = &arg->bundle->ncp.ipcp.throughput; 2881 #ifndef NOINET6 2882 else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0) 2883 t = &arg->bundle->ncp.ipv6cp.throughput; 2884 #endif 2885 else 2886 return -1; 2887 2888 if (arg->argc > arg->argn + 1) { 2889 clear_type = 0; 2890 for (i = arg->argn + 1; i < arg->argc; i++) 2891 if (strcasecmp(arg->argv[i], "overall") == 0) 2892 clear_type |= THROUGHPUT_OVERALL; 2893 else if (strcasecmp(arg->argv[i], "current") == 0) 2894 clear_type |= THROUGHPUT_CURRENT; 2895 else if (strcasecmp(arg->argv[i], "peak") == 0) 2896 clear_type |= THROUGHPUT_PEAK; 2897 else 2898 return -1; 2899 } else 2900 clear_type = THROUGHPUT_ALL; 2901 2902 throughput_clear(t, clear_type, arg->prompt); 2903 return 0; 2904 } 2905 2906 static int 2907 RunListCommand(struct cmdargs const *arg) 2908 { 2909 const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???"; 2910 2911 #ifndef NONAT 2912 if (arg->cmd->args == NatCommands && 2913 tolower(*arg->argv[arg->argn - 1]) == 'a') { 2914 if (arg->prompt) 2915 prompt_Printf(arg->prompt, "The alias command is deprecated\n"); 2916 else 2917 log_Printf(LogWARN, "The alias command is deprecated\n"); 2918 } 2919 #endif 2920 2921 if (arg->argc > arg->argn) 2922 FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv, 2923 arg->prompt, arg->cx); 2924 else if (arg->prompt) 2925 prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help" 2926 " <option>' for syntax help.\n", cmd, cmd); 2927 else 2928 log_Printf(LogWARN, "%s command must have arguments\n", cmd); 2929 2930 return 0; 2931 } 2932 2933 static int 2934 IfaceAddCommand(struct cmdargs const *arg) 2935 { 2936 struct ncpaddr peer, addr; 2937 struct ncprange ifa; 2938 struct in_addr mask; 2939 int n, how; 2940 2941 if (arg->argc == arg->argn + 1) { 2942 if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn])) 2943 return -1; 2944 ncpaddr_init(&peer); 2945 } else { 2946 if (arg->argc == arg->argn + 2) { 2947 if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn])) 2948 return -1; 2949 n = 1; 2950 } else if (arg->argc == arg->argn + 3) { 2951 if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn])) 2952 return -1; 2953 if (ncpaddr_family(&addr) != AF_INET) 2954 return -1; 2955 ncprange_sethost(&ifa, &addr); 2956 if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1])) 2957 return -1; 2958 if (!ncpaddr_getip4(&addr, &mask)) 2959 return -1; 2960 if (!ncprange_setip4mask(&ifa, mask)) 2961 return -1; 2962 n = 2; 2963 } else 2964 return -1; 2965 2966 if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n])) 2967 return -1; 2968 2969 if (ncprange_family(&ifa) != ncpaddr_family(&peer)) { 2970 log_Printf(LogWARN, "IfaceAddCommand: src and dst address families" 2971 " differ\n"); 2972 return -1; 2973 } 2974 } 2975 2976 how = IFACE_ADD_LAST; 2977 if (arg->cmd->args) 2978 how |= IFACE_FORCE_ADD; 2979 2980 return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how); 2981 } 2982 2983 static int 2984 IfaceDeleteCommand(struct cmdargs const *arg) 2985 { 2986 struct ncpaddr ifa; 2987 struct in_addr ifa4; 2988 int ok; 2989 2990 if (arg->argc != arg->argn + 1) 2991 return -1; 2992 2993 if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn])) 2994 return -1; 2995 2996 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED && 2997 ncpaddr_getip4(&ifa, &ifa4) && 2998 arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) { 2999 log_Printf(LogWARN, "%s: Cannot remove active interface address\n", 3000 ncpaddr_ntoa(&ifa)); 3001 return 1; 3002 } 3003 3004 ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa); 3005 if (!ok) { 3006 if (arg->cmd->args) 3007 ok = 1; 3008 else if (arg->prompt) 3009 prompt_Printf(arg->prompt, "%s: No such interface address\n", 3010 ncpaddr_ntoa(&ifa)); 3011 else 3012 log_Printf(LogWARN, "%s: No such interface address\n", 3013 ncpaddr_ntoa(&ifa)); 3014 } 3015 3016 return !ok; 3017 } 3018 3019 static int 3020 IfaceClearCommand(struct cmdargs const *arg) 3021 { 3022 int family, how; 3023 3024 family = 0; 3025 if (arg->argc == arg->argn + 1) { 3026 if (strcasecmp(arg->argv[arg->argn], "inet") == 0) 3027 family = AF_INET; 3028 #ifndef NOINET6 3029 else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0) 3030 family = AF_INET6; 3031 #endif 3032 else 3033 return -1; 3034 } else if (arg->argc != arg->argn) 3035 return -1; 3036 3037 how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED || 3038 arg->bundle->phys_type.all & PHYS_AUTO ? 3039 IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL; 3040 iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how); 3041 3042 return 0; 3043 } 3044 3045 static int 3046 SetProcTitle(struct cmdargs const *arg) 3047 { 3048 static char title[LINE_LEN]; 3049 char *argv[MAXARGS], *ptr; 3050 int len, remaining, f, argc = arg->argc - arg->argn; 3051 3052 if (arg->argc == arg->argn) { 3053 SetTitle(NULL); 3054 return 0; 3055 } 3056 3057 if (argc >= sizeof argv / sizeof argv[0]) { 3058 argc = sizeof argv / sizeof argv[0] - 1; 3059 log_Printf(LogWARN, "Truncating proc title to %d args\n", argc); 3060 } 3061 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid()); 3062 3063 ptr = title; 3064 remaining = sizeof title - 1; 3065 for (f = 0; f < argc && remaining; f++) { 3066 if (f) { 3067 *ptr++ = ' '; 3068 remaining--; 3069 } 3070 len = strlen(argv[f]); 3071 if (len > remaining) 3072 len = remaining; 3073 memcpy(ptr, argv[f], len); 3074 remaining -= len; 3075 ptr += len; 3076 } 3077 *ptr = '\0'; 3078 3079 SetTitle(title); 3080 3081 return 0; 3082 } 3083