diff options
-rw-r--r-- | usr.sbin/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ppp/Makefile | 24 | ||||
-rw-r--r-- | usr.sbin/ppp/Makefile.inc | 1 | ||||
-rw-r--r-- | usr.sbin/ppp/alias_cmd.h | 9 | ||||
-rw-r--r-- | usr.sbin/ppp/async.h | 32 | ||||
-rw-r--r-- | usr.sbin/ppp/auth.c | 213 | ||||
-rw-r--r-- | usr.sbin/ppp/ccp.c | 432 | ||||
-rw-r--r-- | usr.sbin/ppp/ccp.h | 92 | ||||
-rw-r--r-- | usr.sbin/ppp/chat.c | 678 | ||||
-rw-r--r-- | usr.sbin/ppp/chat.h | 29 | ||||
-rw-r--r-- | usr.sbin/ppp/command.c | 1687 | ||||
-rw-r--r-- | usr.sbin/ppp/command.h | 62 | ||||
-rw-r--r-- | usr.sbin/ppp/deflate.c | 618 | ||||
-rw-r--r-- | usr.sbin/ppp/filter.c | 499 | ||||
-rw-r--r-- | usr.sbin/ppp/fsm.c | 820 | ||||
-rw-r--r-- | usr.sbin/ppp/hdlc.h | 66 | ||||
-rw-r--r-- | usr.sbin/ppp/ipcp.c | 710 | ||||
-rw-r--r-- | usr.sbin/ppp/ipcp.h | 83 | ||||
-rw-r--r-- | usr.sbin/ppp/lcp.c | 834 | ||||
-rw-r--r-- | usr.sbin/ppp/lcp.h | 82 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/HISTORY | 129 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/Makefile | 20 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias.c | 1154 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias.h | 173 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_cuseeme.c | 120 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_db.c | 2239 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_ftp.c | 227 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_irc.c | 316 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_local.h | 107 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_nbt.c | 576 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_old.c | 77 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/alias_util.c | 137 | ||||
-rw-r--r-- | usr.sbin/ppp/libalias/libalias.3 | 768 | ||||
-rw-r--r-- | usr.sbin/ppp/log.c | 246 | ||||
-rw-r--r-- | usr.sbin/ppp/lqr.c | 281 | ||||
-rw-r--r-- | usr.sbin/ppp/lqr.h | 64 | ||||
-rw-r--r-- | usr.sbin/ppp/main.c | 1103 | ||||
-rw-r--r-- | usr.sbin/ppp/mbuf.c | 175 | ||||
-rw-r--r-- | usr.sbin/ppp/modem.c | 937 | ||||
-rw-r--r-- | usr.sbin/ppp/os.c | 400 | ||||
-rw-r--r-- | usr.sbin/ppp/os.h | 32 | ||||
-rw-r--r-- | usr.sbin/ppp/pap.c | 216 | ||||
-rw-r--r-- | usr.sbin/ppp/pathnames.h | 43 | ||||
-rw-r--r-- | usr.sbin/ppp/phase.c | 105 | ||||
-rw-r--r-- | usr.sbin/ppp/phase.h | 31 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/Makefile | 63 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/README.alias (renamed from usr.sbin/ppp/README.alias) | 46 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/README.changes | 73 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/README.devel (renamed from usr.sbin/ppp/README.devel) | 15 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/alias_cmd.c | 211 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/alias_cmd.h | 11 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/arp.c (renamed from usr.sbin/ppp/arp.c) | 137 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/arp.h (renamed from usr.sbin/ppp/main.h) | 14 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/async.c (renamed from usr.sbin/ppp/async.c) | 125 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/async.h | 52 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/auth.c | 279 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/auth.h (renamed from usr.sbin/ppp/auth.h) | 34 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/bundle.c | 1746 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/bundle.h | 183 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/cbcp.c | 691 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/cbcp.h | 65 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ccp.c | 611 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ccp.h | 128 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap.c (renamed from usr.sbin/ppp/chap.c) | 210 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap.h (renamed from usr.sbin/ppp/chap.h) | 18 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap_ms.c (renamed from usr.sbin/ppp/chap_ms.c) | 12 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap_ms.h (renamed from usr.sbin/ppp/chap_ms.h) | 4 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chat.c | 797 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chat.h | 82 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/command.c | 2254 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/command.h | 63 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/datalink.c | 1271 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/datalink.h | 145 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/deflate.c | 593 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/deflate.h (renamed from usr.sbin/ppp/deflate.h) | 2 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/defs.c (renamed from usr.sbin/ppp/defs.c) | 121 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/defs.h (renamed from usr.sbin/ppp/defs.h) | 72 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/descriptor.h (renamed from usr.sbin/ppp/loadalias.h) | 40 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/filter.c | 533 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/filter.h (renamed from usr.sbin/ppp/filter.h) | 37 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/fsm.c | 1014 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/fsm.h (renamed from usr.sbin/ppp/fsm.h) | 95 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/hdlc.c (renamed from usr.sbin/ppp/hdlc.c) | 505 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/hdlc.h | 115 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/id.c (renamed from usr.sbin/ppp/id.c) | 103 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/id.h (renamed from usr.sbin/ppp/id.h) | 9 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ip.c (renamed from usr.sbin/ppp/ip.c) | 398 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ip.h (renamed from usr.sbin/ppp/ip.h) | 21 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ipcp.c | 1122 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ipcp.h | 115 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/iplist.c (renamed from usr.sbin/ppp/iplist.c) | 16 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/iplist.h (renamed from usr.sbin/ppp/iplist.h) | 24 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lcp.c | 1063 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lcp.h | 136 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lcpproto.h (renamed from usr.sbin/ppp/lcpproto.h) | 6 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/link.c | 210 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/link.h | 69 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/log.c | 467 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/log.h (renamed from usr.sbin/ppp/log.h) | 72 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lqr.c | 320 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lqr.h | 59 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/main.c | 555 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/main.h (renamed from usr.sbin/ppp/arp.h) | 6 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/mbuf.c | 211 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/mbuf.h (renamed from usr.sbin/ppp/mbuf.h) | 50 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/modem.c | 1097 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/modem.h (renamed from usr.sbin/ppp/modem.h) | 40 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/mp.c | 1021 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/mp.h | 136 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/pap.c | 202 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/pap.h (renamed from usr.sbin/ppp/pap.h) | 10 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/physical.c | 239 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/physical.h | 103 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ppp.8 (renamed from usr.sbin/ppp/ppp.8) | 2218 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/pred.c (renamed from usr.sbin/ppp/pred.c) | 205 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/pred.h (renamed from usr.sbin/ppp/pred.h) | 2 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/probe.c | 53 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/probe.h (renamed from usr.sbin/ppp/server.h) | 12 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/prompt.c | 551 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/prompt.h | 91 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/route.c (renamed from usr.sbin/ppp/route.c) | 414 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/route.h | 53 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/server.c | 285 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/server.h | 49 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/sig.c (renamed from usr.sbin/ppp/sig.c) | 10 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/sig.h (renamed from usr.sbin/ppp/sig.h) | 6 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/slcompress.c (renamed from usr.sbin/ppp/slcompress.c) | 134 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/slcompress.h (renamed from usr.sbin/ppp/slcompress.h) | 37 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/systems.c (renamed from usr.sbin/ppp/systems.c) | 260 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/systems.h (renamed from usr.sbin/ppp/systems.h) | 12 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/throughput.c (renamed from usr.sbin/ppp/throughput.c) | 116 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/throughput.h (renamed from usr.sbin/ppp/throughput.h) | 15 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/timer.c (renamed from usr.sbin/ppp/timer.c) | 184 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/timer.h (renamed from usr.sbin/ppp/timer.h) | 21 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/tun.c (renamed from usr.sbin/ppp/tun.c) | 43 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/tun.h (renamed from usr.sbin/ppp/tun.h) | 6 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/vjcomp.c (renamed from usr.sbin/ppp/vjcomp.c) | 83 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/vjcomp.h (renamed from usr.sbin/ppp/vjcomp.h) | 12 | ||||
-rw-r--r-- | usr.sbin/ppp/pppctl/Makefile | 16 | ||||
-rw-r--r-- | usr.sbin/ppp/pppctl/pppctl.8 (renamed from usr.sbin/pppctl/pppctl.8) | 4 | ||||
-rw-r--r-- | usr.sbin/ppp/pppctl/pppctl.c (renamed from usr.sbin/pppctl/pppctl.c) | 2 | ||||
-rw-r--r-- | usr.sbin/ppp/route.h | 29 | ||||
-rw-r--r-- | usr.sbin/ppp/server.c | 169 | ||||
-rw-r--r-- | usr.sbin/ppp/vars.c | 192 | ||||
-rw-r--r-- | usr.sbin/ppp/vars.h | 205 | ||||
-rw-r--r-- | usr.sbin/pppctl/Makefile | 10 |
146 files changed, 28894 insertions, 13603 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index e18c249624f..caf4a2a9c8e 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.36 1998/08/18 03:43:20 deraadt Exp $ +# $OpenBSD: Makefile,v 1.37 1998/08/31 00:20:07 brian Exp $ # not yet done: catman @@ -9,7 +9,7 @@ SUBDIR= ac accton adduser amd arp bootpd bootpgw bootpef bootptest \ edquota gspa httpd inetd iostat \ ipftest ipmon ipsend kgmon \ kvm_mkdb lpr map-mbone mrinfo mopd mrouted mtrace mtree named \ - netgroup_mkdb pkg_install portmap ppp pppctl pppd pstat pwd_mkdb \ + netgroup_mkdb pkg_install portmap ppp pppd pstat pwd_mkdb \ quot quotaon rarpd rbootd rdconfig rdate repquota rmt \ rpc.bootparamd rpc.lockd rpc.pcnfsd rwhod \ sa sendmail sliplogin slstats spray sysctl \ diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile index c79275ffe77..c3176629818 100644 --- a/usr.sbin/ppp/Makefile +++ b/usr.sbin/ppp/Makefile @@ -1,17 +1,11 @@ -# $Id: Makefile,v 1.9 1998/06/07 17:09:43 brian Exp $ +# $OpenBSD: Makefile,v 1.10 1998/08/31 00:20:08 brian Exp $ -PROG= ppp -SRCS= arp.c async.c auth.c ccp.c chap.c chap_ms.c chat.c \ - command.c deflate.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c \ - iplist.c lcp.c log.c lqr.c main.c mbuf.c modem.c os.c \ - pap.c phase.c pred.c route.c server.c sig.c slcompress.c systems.c \ - throughput.c timer.c tun.c vars.c vjcomp.c -CFLAGS+=-Wall -Wmissing-prototypes -DHAVE_DES -DNOALIAS -LDADD+= -lutil -ldes -lz -DPADD+= ${LIBUTIL} ${LIBDES} ${LIBZ} -MAN= ppp.8 -BINMODE=4554 -BINOWN= root -BINGRP= network +.include <bsd.own.mk> -.include <bsd.prog.mk> +.if !make(install) +SUBDIR= libalias +.endif + +SUBDIR+= ppp pppctl + +.include <bsd.subdir.mk> diff --git a/usr.sbin/ppp/Makefile.inc b/usr.sbin/ppp/Makefile.inc new file mode 100644 index 00000000000..1890d51e766 --- /dev/null +++ b/usr.sbin/ppp/Makefile.inc @@ -0,0 +1 @@ +BINDIR?= /usr/sbin diff --git a/usr.sbin/ppp/alias_cmd.h b/usr.sbin/ppp/alias_cmd.h deleted file mode 100644 index 1e9e0513d35..00000000000 --- a/usr.sbin/ppp/alias_cmd.h +++ /dev/null @@ -1,9 +0,0 @@ -/*- - * The code in this file was written by Eivind Eklund <perhaps@yes.no>, - * who places it in the public domain without restriction. - * - * $Id: alias_cmd.h,v 1.3 1997/12/24 10:28:15 brian Exp $ - */ - -extern int AliasRedirectPort(struct cmdargs const *); -extern int AliasRedirectAddr(struct cmdargs const *); diff --git a/usr.sbin/ppp/async.h b/usr.sbin/ppp/async.h deleted file mode 100644 index 0804131f1c1..00000000000 --- a/usr.sbin/ppp/async.h +++ /dev/null @@ -1,32 +0,0 @@ -/*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: async.h,v 1.2 1997/12/21 14:27:00 brian Exp $ - */ - -extern void AsyncInit(void); -extern void SetLinkParams(struct lcpstate *); -extern void AsyncOutput(int, struct mbuf *, int); -extern void AsyncInput(u_char *, int); diff --git a/usr.sbin/ppp/auth.c b/usr.sbin/ppp/auth.c deleted file mode 100644 index ef327941a82..00000000000 --- a/usr.sbin/ppp/auth.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * PPP Secret Key Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: auth.c,v 1.5 1998/03/13 01:25:50 brian Exp $ - * - * TODO: - * o Implement check against with registered IP addresses. - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "ipcp.h" -#include "loadalias.h" -#include "vars.h" -#include "auth.h" -#include "chat.h" -#include "systems.h" - -void -LocalAuthInit() -{ - if (!(mode&MODE_DAEMON)) - /* We're allowed in interactive mode */ - VarLocalAuth = LOCAL_AUTH; - else if (VarHaveLocalAuthKey) - VarLocalAuth = *VarLocalAuthKey == '\0' ? LOCAL_AUTH : LOCAL_NO_AUTH; - else - switch (LocalAuthValidate(SECRETFILE, VarShortHost, "")) { - case NOT_FOUND: - VarLocalAuth = LOCAL_DENY; - break; - case VALID: - VarLocalAuth = LOCAL_AUTH; - break; - case INVALID: - VarLocalAuth = LOCAL_NO_AUTH; - break; - } -} - -LOCAL_AUTH_VALID -LocalAuthValidate(const char *fname, const char *system, const char *key) -{ - FILE *fp; - int n; - char *vector[3]; - char buff[LINE_LEN]; - LOCAL_AUTH_VALID rc; - - rc = NOT_FOUND; /* No system entry */ - fp = OpenSecret(fname); - if (fp == NULL) - return (rc); - while (fgets(buff, sizeof buff, fp)) { - if (buff[0] == '#') - continue; - buff[strlen(buff) - 1] = 0; - memset(vector, '\0', sizeof vector); - n = MakeArgs(buff, vector, VECSIZE(vector)); - if (n < 1) - continue; - if (strcmp(vector[0], system) == 0) { - if ((vector[1] == (char *) NULL && (key == NULL || *key == '\0')) || - (vector[1] != (char *) NULL && strcmp(vector[1], key) == 0)) { - rc = VALID; /* Valid */ - } else { - rc = INVALID; /* Invalid */ - } - break; - } - } - CloseSecret(fp); - return (rc); -} - -int -AuthValidate(const char *fname, const char *system, const char *key) -{ - FILE *fp; - int n; - char *vector[5]; - char buff[LINE_LEN]; - char passwd[100]; - - fp = OpenSecret(fname); - if (fp == NULL) - return (0); - while (fgets(buff, sizeof buff, fp)) { - if (buff[0] == '#') - continue; - buff[strlen(buff) - 1] = 0; - memset(vector, '\0', sizeof vector); - n = MakeArgs(buff, vector, VECSIZE(vector)); - if (n < 2) - continue; - if (strcmp(vector[0], system) == 0) { - ExpandString(vector[1], passwd, sizeof passwd, 0); - if (strcmp(passwd, key) == 0) { - CloseSecret(fp); - if (n > 2 && !UseHisaddr(vector[2], 1)) - return (0); - IpcpInit(); - if (n > 3) - SetLabel(vector[3]); - return (1); /* Valid */ - } - } - } - CloseSecret(fp); - return (0); /* Invalid */ -} - -char * -AuthGetSecret(const char *fname, const char *system, int len, int setaddr) -{ - FILE *fp; - int n; - char *vector[5]; - char buff[LINE_LEN]; - static char passwd[100]; - - fp = OpenSecret(fname); - if (fp == NULL) - return (NULL); - while (fgets(buff, sizeof buff, fp)) { - if (buff[0] == '#') - continue; - buff[strlen(buff) - 1] = 0; - memset(vector, '\0', sizeof vector); - n = MakeArgs(buff, vector, VECSIZE(vector)); - if (n < 2) - continue; - if (strlen(vector[0]) == len && strncmp(vector[0], system, len) == 0) { - ExpandString(vector[1], passwd, sizeof passwd, 0); - if (setaddr) { - memset(&DefHisAddress, '\0', sizeof DefHisAddress); - } - if (n > 2 && setaddr) { - if (UseHisaddr(vector[2], 1)) - IpcpInit(); - else - return NULL; - } - if (n > 3) - SetLabel(vector[3]); - return (passwd); - } - } - CloseSecret(fp); - return (NULL); /* Invalid */ -} - -static void -AuthTimeout(void *vauthp) -{ - struct pppTimer *tp; - struct authinfo *authp = (struct authinfo *)vauthp; - - tp = &authp->authtimer; - StopTimer(tp); - if (--authp->retry > 0) { - StartTimer(tp); - (authp->ChallengeFunc) (++authp->id); - } -} - -void -StartAuthChallenge(struct authinfo *authp) -{ - struct pppTimer *tp; - - tp = &authp->authtimer; - StopTimer(tp); - tp->func = AuthTimeout; - tp->load = VarRetryTimeout * SECTICKS; - tp->state = TIMER_STOPPED; - tp->arg = (void *) authp; - StartTimer(tp); - authp->retry = 3; - authp->id = 1; - (authp->ChallengeFunc) (authp->id); -} - -void -StopAuthTimer(struct authinfo *authp) -{ - StopTimer(&authp->authtimer); -} diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c deleted file mode 100644 index 36736f68ee8..00000000000 --- a/usr.sbin/ppp/ccp.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * PPP Compression Control Protocol (CCP) Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: ccp.c,v 1.11 1998/02/18 19:31:42 brian Exp $ - * - * TODO: - * o Support other compression protocols - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <string.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "lcpproto.h" -#include "lcp.h" -#include "ccp.h" -#include "phase.h" -#include "loadalias.h" -#include "vars.h" -#include "pred.h" -#include "deflate.h" - -struct ccpstate CcpInfo = { -1, -1, -1, -1 }; - -static void CcpSendConfigReq(struct fsm *); -static void CcpSendTerminateReq(struct fsm *); -static void CcpSendTerminateAck(struct fsm *); -static void CcpDecodeConfig(u_char *, int, int); -static void CcpLayerStart(struct fsm *); -static void CcpLayerFinish(struct fsm *); -static void CcpLayerUp(struct fsm *); -static void CcpLayerDown(struct fsm *); -static void CcpInitRestartCounter(struct fsm *); - -struct fsm CcpFsm = { - "CCP", - PROTO_CCP, - CCP_MAXCODE, - 0, - ST_INITIAL, - 0, 0, 0, - {0, 0, 0, NULL, NULL, NULL}, /* FSM timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Open timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */ - LogCCP, - - CcpLayerUp, - CcpLayerDown, - CcpLayerStart, - CcpLayerFinish, - CcpInitRestartCounter, - CcpSendConfigReq, - CcpSendTerminateReq, - CcpSendTerminateAck, - CcpDecodeConfig, -}; - -static char const *cftypes[] = { - /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ - "OUI", /* 0: OUI */ - "PRED1", /* 1: Predictor type 1 */ - "PRED2", /* 2: Predictor type 2 */ - "PUDDLE", /* 3: Puddle Jumber */ - "???", "???", "???", "???", "???", "???", - "???", "???", "???", "???", "???", "???", - "HWPPC", /* 16: Hewlett-Packard PPC */ - "STAC", /* 17: Stac Electronics LZS (rfc1974) */ - "MSPPC", /* 18: Microsoft PPC */ - "GAND", /* 19: Gandalf FZA (rfc1993) */ - "V42BIS", /* 20: ARG->DATA.42bis compression */ - "BSD", /* 21: BSD LZW Compress */ - "???", - "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ - "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ - /* 24: Deflate (according to pppd-2.3.1) */ - "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ - "DEFLATE", /* 26: Deflate (rfc1979) */ -}; - -#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) - -static const char * -protoname(int proto) -{ - if (proto < 0 || proto > NCFTYPES) - return "none"; - return cftypes[proto]; -} - -/* We support these algorithms, and Req them in the given order */ -static const struct ccp_algorithm *algorithm[] = { - &DeflateAlgorithm, - &Pred1Algorithm, - &PppdDeflateAlgorithm -}; - -static int in_algorithm = -1; -static int out_algorithm = -1; -#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) - -int -ReportCcpStatus(struct cmdargs const *arg) -{ - if (VarTerm) { - fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]); - fprintf(VarTerm, "My protocol = %s, His protocol = %s\n", - protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto)); - fprintf(VarTerm, "Output: %ld --> %ld, Input: %ld --> %ld\n", - CcpInfo.uncompout, CcpInfo.compout, - CcpInfo.compin, CcpInfo.uncompin); - } - return 0; -} - -static void -ccpstateInit(void) -{ - if (CcpInfo.in_init) - (*algorithm[in_algorithm]->i.Term)(); - if (CcpInfo.out_init) - (*algorithm[out_algorithm]->o.Term)(); - in_algorithm = -1; - out_algorithm = -1; - memset(&CcpInfo, '\0', sizeof CcpInfo); - CcpInfo.his_proto = CcpInfo.my_proto = -1; - CcpInfo.reset_sent = CcpInfo.last_reset = -1; -} - -void -CcpInit() -{ - FsmInit(&CcpFsm); - ccpstateInit(); - CcpFsm.maxconfig = 10; -} - -static void -CcpInitRestartCounter(struct fsm *fp) -{ - fp->FsmTimer.load = VarRetryTimeout * SECTICKS; - fp->restart = 5; -} - -static void -CcpSendConfigReq(struct fsm *fp) -{ - u_char *cp; - int f; - - LogPrintf(LogCCP, "CcpSendConfigReq\n"); - cp = ReqBuff; - CcpInfo.my_proto = -1; - out_algorithm = -1; - for (f = 0; f < NALGORITHMS; f++) - if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) { - struct lcp_opt o; - - (*algorithm[f]->o.Get)(&o); - cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id], - (*algorithm[f]->Disp)(&o)); - CcpInfo.my_proto = o.id; - out_algorithm = f; - } - FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); -} - -void -CcpSendResetReq(struct fsm *fp) -{ - LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid); - CcpInfo.reset_sent = fp->reqid; - CcpInfo.last_reset = -1; - FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); -} - -static void -CcpSendTerminateReq(struct fsm *fp) -{ - /* XXX: No code yet */ -} - -static void -CcpSendTerminateAck(struct fsm *fp) -{ - LogPrintf(LogCCP, "CcpSendTerminateAck\n"); - FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); -} - -void -CcpRecvResetReq(struct fsm *fp) -{ - if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) - (*algorithm[out_algorithm]->o.Reset)(); -} - -static void -CcpLayerStart(struct fsm *fp) -{ - LogPrintf(LogCCP, "CcpLayerStart.\n"); -} - -static void -CcpLayerFinish(struct fsm *fp) -{ - LogPrintf(LogCCP, "CcpLayerFinish.\n"); - ccpstateInit(); -} - -static void -CcpLayerDown(struct fsm *fp) -{ - LogPrintf(LogCCP, "CcpLayerDown.\n"); - ccpstateInit(); -} - -/* - * Called when CCP has reached the OPEN state - */ -static void -CcpLayerUp(struct fsm *fp) -{ - LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state); - LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", - protoname(CcpInfo.my_proto), CcpInfo.my_proto, - protoname(CcpInfo.his_proto), CcpInfo.his_proto); - if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) { - (*algorithm[in_algorithm]->i.Init)(); - CcpInfo.in_init = 1; - } - if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) { - (*algorithm[out_algorithm]->o.Init)(); - CcpInfo.out_init = 1; - } -} - -void -CcpUp() -{ - FsmUp(&CcpFsm); - LogPrintf(LogCCP, "CCP Up event!!\n"); -} - -void -CcpOpen() -{ - int f; - - for (f = 0; f < NALGORITHMS; f++) - if (Enabled(algorithm[f]->Conf)) { - CcpFsm.open_mode = 0; - FsmOpen(&CcpFsm); - break; - } - - if (f == NALGORITHMS) - for (f = 0; f < NALGORITHMS; f++) - if (Acceptable(algorithm[f]->Conf)) { - CcpFsm.open_mode = OPEN_PASSIVE; - FsmOpen(&CcpFsm); - break; - } -} - -static void -CcpDecodeConfig(u_char *cp, int plen, int mode_type) -{ - int type, length; - int f; - - ackp = AckBuff; - nakp = NakBuff; - rejp = RejBuff; - - while (plen >= sizeof(struct fsmconfig)) { - type = *cp; - length = cp[1]; - if (type < NCFTYPES) - LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length); - else - LogPrintf(LogCCP, " ???[%d]\n", length); - - for (f = NALGORITHMS-1; f > -1; f--) - if (algorithm[f]->id == type) - break; - - if (f == -1) { - /* Don't understand that :-( */ - if (mode_type == MODE_REQ) { - CcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - } - } else { - struct lcp_opt o; - - switch (mode_type) { - case MODE_REQ: - if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) { - memcpy(&o, cp, length); - switch ((*algorithm[f]->i.Set)(&o)) { - case MODE_REJ: - memcpy(rejp, &o, o.len); - rejp += o.len; - break; - case MODE_NAK: - memcpy(nakp, &o, o.len); - nakp += o.len; - break; - case MODE_ACK: - memcpy(ackp, cp, length); - ackp += length; - CcpInfo.his_proto = type; - in_algorithm = f; /* This one'll do ! */ - break; - } - } else { - memcpy(rejp, cp, length); - rejp += length; - } - break; - case MODE_NAK: - memcpy(&o, cp, length); - if ((*algorithm[f]->o.Set)(&o) == MODE_ACK) - CcpInfo.my_proto = algorithm[f]->id; - else { - CcpInfo.his_reject |= (1 << type); - CcpInfo.my_proto = -1; - } - break; - case MODE_REJ: - CcpInfo.his_reject |= (1 << type); - CcpInfo.my_proto = -1; - break; - } - } - - plen -= length; - cp += length; - } - - if (rejp != RejBuff) { - ackp = AckBuff; /* let's not send both ! */ - CcpInfo.his_proto = -1; - in_algorithm = -1; - } -} - -void -CcpInput(struct mbuf *bp) -{ - if (phase == PHASE_NETWORK) - FsmInput(&CcpFsm, bp); - else { - if (phase > PHASE_NETWORK) - LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase); - pfree(bp); - } -} - -void -CcpResetInput(u_char id) -{ - if (CcpInfo.reset_sent != -1) { - if (id != CcpInfo.reset_sent) { - LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", - id, CcpInfo.reset_sent); - return; - } - /* Whaddaya know - a correct reset ack */ - } else if (id == CcpInfo.last_reset) - LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); - else { - LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); - return; - } - - CcpInfo.last_reset = CcpInfo.reset_sent; - CcpInfo.reset_sent = -1; - if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) - (*algorithm[in_algorithm]->i.Reset)(); -} - -int -CcpOutput(int pri, u_short proto, struct mbuf *m) -{ - if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) - return (*algorithm[out_algorithm]->o.Write)(pri, proto, m); - return 0; -} - -struct mbuf * -CompdInput(u_short *proto, struct mbuf *m) -{ - if (CcpInfo.reset_sent != -1) { - /* Send another REQ and put the packet in the bit bucket */ - LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent); - FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0); - } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) - return (*algorithm[in_algorithm]->i.Read)(proto, m); - pfree(m); - return NULL; -} - -void -CcpDictSetup(u_short proto, struct mbuf *m) -{ - if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) - (*algorithm[in_algorithm]->i.DictSetup)(proto, m); -} diff --git a/usr.sbin/ppp/ccp.h b/usr.sbin/ppp/ccp.h deleted file mode 100644 index fea7f973c7d..00000000000 --- a/usr.sbin/ppp/ccp.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: ccp.h,v 1.6 1998/06/28 09:41:35 brian Exp $ - * - * TODO: - */ - -#define CCP_MAXCODE CODE_RESETACK - -#define TY_OUI 0 /* OUI */ -#define TY_PRED1 1 /* Predictor type 1 */ -#define TY_PRED2 2 /* Predictor type 2 */ -#define TY_PUDDLE 3 /* Puddle Jumper */ -#define TY_HWPPC 16 /* Hewlett-Packard PPC */ -#define TY_STAC 17 /* Stac Electronics LZS */ -#define TY_MSPPC 18 /* Microsoft PPC */ -#define TY_GAND 19 /* Gandalf FZA */ -#define TY_V42BIS 20 /* V.42bis compression */ -#define TY_BSD 21 /* BSD LZW Compress */ -#define TY_PPPD_DEFLATE 24 /* Deflate (gzip) - (mis) numbered by pppd */ -#define TY_DEFLATE 26 /* Deflate (gzip) - rfc 1979 */ - -struct ccpstate { - int his_proto; /* peer's compression protocol */ - int my_proto; /* our compression protocol */ - - int reset_sent; /* If != -1, ignore compressed 'till ack */ - int last_reset; /* We can receive more (dups) w/ this id */ - - u_int32_t his_reject; /* Request codes rejected by peer */ - u_int32_t my_reject; /* Request codes I have rejected */ - - int out_init; /* Init called for out algorithm */ - int in_init; /* Init called for in algorithm */ - - u_long uncompout, compout; /* Outgoing bytes before/after compression */ - u_long uncompin, compin; /* Incoming bytes after/before decompression */ -}; - -extern struct ccpstate CcpInfo; - -struct ccp_algorithm { - int id; - int Conf; /* A Conf value from vars.h */ - const char *(*Disp)(struct lcp_opt *); - struct { - void (*Get)(struct lcp_opt *); - int (*Set)(struct lcp_opt *); - int (*Init)(void); - void (*Term)(void); - void (*Reset)(void); - struct mbuf *(*Read)(u_short *, struct mbuf *); - void (*DictSetup)(u_short, struct mbuf *); - } i; - struct { - void (*Get)(struct lcp_opt *); - int (*Set)(struct lcp_opt *); - int (*Init)(void); - void (*Term)(void); - void (*Reset)(void); - int (*Write)(int, u_short, struct mbuf *); - } o; -}; - -extern struct fsm CcpFsm; - -extern void CcpRecvResetReq(struct fsm *); -extern void CcpSendResetReq(struct fsm *); -extern void CcpInput(struct mbuf *); -extern void CcpUp(void); -extern void CcpOpen(void); -extern void CcpInit(void); -extern int ReportCcpStatus(struct cmdargs const *); -extern void CcpResetInput(u_char); -extern int CcpOutput(int, u_short, struct mbuf *); -extern struct mbuf *CompdInput(u_short *, struct mbuf *); -extern void CcpDictSetup(u_short, struct mbuf *); diff --git a/usr.sbin/ppp/chat.c b/usr.sbin/ppp/chat.c deleted file mode 100644 index 6bcd5cb4226..00000000000 --- a/usr.sbin/ppp/chat.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com). - * - * Chat -- a program for automatic session establishment (i.e. dial - * the phone and log in). - * - * This software is in the public domain. - * - * Please send all bug reports, requests for information, etc. to: - * - * Karl Fox <karl@MorningStar.Com> - * Morning Star Technologies, Inc. - * 1760 Zollinger Road - * Columbus, OH 43221 - * (614)451-1883 - * - * $Id: chat.c,v 1.6 1998/01/21 02:13:30 brian Exp $ - * - * TODO: - * o Support more UUCP compatible control sequences. - * o Dialing shoud not block monitor process. - * o Reading modem by select should be unified into main.c - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <setjmp.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <termios.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "loadalias.h" -#include "vars.h" -#include "chat.h" -#include "modem.h" - -#ifndef isblank -#define isblank(c) ((c) == '\t' || (c) == ' ') -#endif - - -#define IBSIZE LINE_LEN - -static int TimeoutSec; -static int abort_next, timeout_next; -static int numaborts; -static char *AbortStrings[50]; -static char inbuff[IBSIZE * 2 + 1]; -static jmp_buf ChatEnv; - -#define MATCH 1 -#define NOMATCH 0 -#define ABORT -1 - -static char * -findblank(char *p, int instring) -{ - if (instring) { - while (*p) { - if (*p == '\\') { - strcpy(p, p + 1); - if (!*p) - break; - } else if (*p == '"') - return (p); - p++; - } - } else { - while (*p) { - if (isblank(*p)) - return (p); - p++; - } - } - return p; -} - -int -MakeArgs(char *script, char **pvect, int maxargs) -{ - int nargs, nb; - int instring; - - nargs = 0; - while (*script) { - nb = strspn(script, " \t"); - script += nb; - if (*script) { - if (*script == '"') { - instring = 1; - script++; - if (*script == '\0') - break; /* Shouldn't return here. Need to null - * terminate below */ - } else - instring = 0; - if (nargs >= maxargs - 1) - break; - *pvect++ = script; - nargs++; - script = findblank(script, instring); - if (*script) - *script++ = '\0'; - } - } - *pvect = NULL; - return nargs; -} - -/* - * \c don't add a cr - * \d Sleep a little (delay 2 seconds - * \n Line feed character - * \P Auth Key password - * \p pause 0.25 sec - * \r Carrige return character - * \s Space character - * \T Telephone number(s) (defined via `set phone') - * \t Tab character - * \U Auth User - */ -char * -ExpandString(const char *str, char *result, int reslen, int sendmode) -{ - int addcr = 0; - char *phone; - - result[--reslen] = '\0'; - if (sendmode) - addcr = 1; - while (*str && reslen > 0) { - switch (*str) { - case '\\': - str++; - switch (*str) { - case 'c': - if (sendmode) - addcr = 0; - break; - case 'd': /* Delay 2 seconds */ - nointr_sleep(2); - break; - case 'p': - nointr_usleep(250000); - break; /* Pause 0.25 sec */ - case 'n': - *result++ = '\n'; - reslen--; - break; - case 'r': - *result++ = '\r'; - reslen--; - break; - case 's': - *result++ = ' '; - reslen--; - break; - case 't': - *result++ = '\t'; - reslen--; - break; - case 'P': - strncpy(result, VarAuthKey, reslen); - reslen -= strlen(result); - result += strlen(result); - break; - case 'T': - if (VarAltPhone == NULL) { - if (VarNextPhone == NULL) { - strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1); - VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0'; - VarNextPhone = VarPhoneCopy; - } - VarAltPhone = strsep(&VarNextPhone, ":"); - } - phone = strsep(&VarAltPhone, "|"); - strncpy(result, phone, reslen); - reslen -= strlen(result); - result += strlen(result); - if (VarTerm) - fprintf(VarTerm, "Phone: %s\n", phone); - LogPrintf(LogPHASE, "Phone: %s\n", phone); - break; - case 'U': - strncpy(result, VarAuthName, reslen); - reslen -= strlen(result); - result += strlen(result); - break; - default: - reslen--; - *result++ = *str; - break; - } - if (*str) - str++; - break; - case '^': - str++; - if (*str) { - *result++ = *str++ & 0x1f; - reslen--; - } - break; - default: - *result++ = *str++; - reslen--; - break; - } - } - if (--reslen > 0) { - if (addcr) - *result++ = '\r'; - } - if (--reslen > 0) - *result++ = '\0'; - return (result); -} - -#define MAXLOGBUFF LINE_LEN -static char logbuff[MAXLOGBUFF]; -static int loglen = 0; - -static void -clear_log(void) -{ - memset(logbuff, 0, MAXLOGBUFF); - loglen = 0; -} - -static void -flush_log(void) -{ - if (LogIsKept(LogCONNECT)) - LogPrintf(LogCONNECT, "%s\n", logbuff); - else if (LogIsKept(LogCARRIER) && strstr(logbuff, "CARRIER")) - LogPrintf(LogCARRIER, "%s\n", logbuff); - - clear_log(); -} - -static void -connect_log(const char *str, int single_p) -{ - int space = MAXLOGBUFF - loglen - 1; - - while (space--) { - if (*str == '\n') { - flush_log(); - } else { - logbuff[loglen++] = *str; - } - if (single_p || !*++str) - break; - } - if (!space) - flush_log(); -} - -static void -ExecStr(char *command, char *out, int olen) -{ - pid_t pid; - int fids[2]; - char *vector[MAXARGS], *startout, *endout; - int stat, nb; - - LogPrintf(LogCHAT, "Exec: %s\n", command); - MakeArgs(command, vector, VECSIZE(vector)); - - if (pipe(fids) < 0) { - LogPrintf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", - strerror(errno)); - longjmp(ChatEnv, 2); - } - if ((pid = fork()) == 0) { - TermTimerService(); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGALRM, SIG_DFL); - if (modem == 2) { - int nmodem; - nmodem = dup(modem); - close(modem); - modem = nmodem; - } - close(fids[0]); - dup2(fids[1], 2); - close(fids[1]); - dup2(modem, 0); - dup2(modem, 1); - if ((nb = open("/dev/tty", O_RDWR)) > 3) { - dup2(nb, 3); - close(nb); - } - setuid(geteuid()); - execvp(vector[0], vector); - fprintf(stderr, "execvp failed: %s: %s\n", vector[0], strerror(errno)); - exit(127); - } else { - char *name = strdup(vector[0]); - - close(fids[1]); - endout = out + olen - 1; - startout = out; - while (out < endout) { - nb = read(fids[0], out, 1); - if (nb <= 0) - break; - out++; - } - *out = '\0'; - close(fids[0]); - close(fids[1]); - waitpid(pid, &stat, WNOHANG); - if (WIFSIGNALED(stat)) { - LogPrintf(LogWARN, "%s: signal %d\n", name, WTERMSIG(stat)); - free(name); - longjmp(ChatEnv, 3); - } else if (WIFEXITED(stat)) { - switch (WEXITSTATUS(stat)) { - case 0: - free(name); - break; - case 127: - LogPrintf(LogWARN, "%s: %s\n", name, startout); - free(name); - longjmp(ChatEnv, 4); - break; - default: - LogPrintf(LogWARN, "%s: exit %d\n", name, WEXITSTATUS(stat)); - free(name); - longjmp(ChatEnv, 5); - break; - } - } else { - LogPrintf(LogWARN, "%s: Unexpected exit result\n", name); - free(name); - longjmp(ChatEnv, 6); - } - } -} - -static int -WaitforString(const char *estr) -{ - struct timeval timeout; - char *s, *str, ch; - char *inp; - fd_set rfds; - int i, nfds, nb; - char buff[IBSIZE]; -#ifdef SIGALRM - int omask; - - omask = sigblock(sigmask(SIGALRM)); -#endif - clear_log(); - if (*estr == '!') { - ExpandString(estr + 1, buff, sizeof buff, 0); - ExecStr(buff, buff, sizeof buff); - } else { - ExpandString(estr, buff, sizeof buff, 0); - } - if (LogIsKept(LogCHAT)) { - s = buff + strlen(buff) - 1; - while (s >= buff && *s == '\n') - s--; - if (!strcmp(estr, buff)) - LogPrintf(LogCHAT, "Wait for (%d): %.*s\n", - TimeoutSec, s - buff + 1, buff); - else - LogPrintf(LogCHAT, "Wait for (%d): %s --> %.*s\n", - TimeoutSec, estr, s - buff + 1, buff); - } - - if (buff[0] == '\0') - return (MATCH); - - str = buff; - inp = inbuff; - - if (strlen(str) >= IBSIZE) { - str[IBSIZE - 1] = 0; - LogPrintf(LogCHAT, "Truncating String to %d character: %s\n", IBSIZE, str); - } - nfds = modem + 1; - s = str; - for (;;) { - FD_ZERO(&rfds); - FD_SET(modem, &rfds); - - /* - * Because it is not clear whether select() modifies timeout value, it is - * better to initialize timeout values everytime. - */ - timeout.tv_sec = TimeoutSec; - timeout.tv_usec = 0; - i = select(nfds, &rfds, NULL, NULL, &timeout); -#ifdef notdef - TimerService(); -#endif - if (i < 0) { -#ifdef SIGALRM - if (errno == EINTR) - continue; - sigsetmask(omask); -#endif - LogPrintf(LogERROR, "WaitForString: select(): %s\n", strerror(errno)); - *inp = 0; - return (NOMATCH); - } else if (i == 0) { /* Timeout reached! */ - *inp = 0; - if (inp != inbuff) - LogPrintf(LogCHAT, "Got: %s\n", inbuff); - LogPrintf(LogCHAT, "Can't get (%d).\n", timeout.tv_sec); -#ifdef SIGALRM - sigsetmask(omask); -#endif - return (NOMATCH); - } - if (FD_ISSET(modem, &rfds)) { /* got something */ - if (DEV_IS_SYNC) { - int length; - - if ((length = strlen(inbuff)) > IBSIZE) { - /* shuffle down next part */ - memcpy(inbuff, &(inbuff[IBSIZE]), IBSIZE + 1); - length = strlen(inbuff); - } - nb = read(modem, &(inbuff[length]), IBSIZE); - inbuff[nb + length] = 0; - connect_log(inbuff, 0); - if (strstr(inbuff, str)) { -#ifdef SIGALRM - sigsetmask(omask); -#endif - flush_log(); - return (MATCH); - } - for (i = 0; i < numaborts; i++) { - if (strstr(inbuff, AbortStrings[i])) { - LogPrintf(LogCHAT, "Abort: %s\n", AbortStrings[i]); -#ifdef SIGALRM - sigsetmask(omask); -#endif - flush_log(); - return (ABORT); - } - } - } else { - if (read(modem, &ch, 1) < 0) { - LogPrintf(LogERROR, "read error: %s\n", strerror(errno)); - *inp = '\0'; - return (NOMATCH); - } - connect_log(&ch, 1); - *inp++ = ch; - if (ch == *s) { - s++; - if (*s == '\0') { -#ifdef SIGALRM - sigsetmask(omask); -#endif - *inp = 0; - flush_log(); - return (MATCH); - } - } else - s = str; - if (inp == inbuff + IBSIZE) { - memcpy(inbuff, inp - 100, 100); - inp = inbuff + 100; - } - if (s == str) { - for (i = 0; i < numaborts; i++) { /* Look for Abort strings */ - int len; - char *s1; - - s1 = AbortStrings[i]; - len = strlen(s1); - if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) { - LogPrintf(LogCHAT, "Abort: %s\n", s1); - *inp = 0; -#ifdef SIGALRM - sigsetmask(omask); -#endif - flush_log(); - return (ABORT); - } - } - } - } - } - } -} - -static void -SendString(const char *str) -{ - char *cp; - int on; - char buff[LINE_LEN]; - - if (abort_next) { - abort_next = 0; - ExpandString(str, buff, sizeof buff, 0); - AbortStrings[numaborts++] = strdup(buff); - } else if (timeout_next) { - timeout_next = 0; - TimeoutSec = atoi(str); - if (TimeoutSec <= 0) - TimeoutSec = 30; - } else { - if (*str == '!') { - ExpandString(str + 1, buff + 2, sizeof buff - 2, 0); - ExecStr(buff + 2, buff + 2, sizeof buff - 2); - } else { - ExpandString(str, buff + 2, sizeof buff - 2, 1); - } - if (strstr(str, "\\P")) /* Do not log the password itself. */ - LogPrintf(LogCHAT, "Sending: %s", str); - else { - cp = buff + strlen(buff + 2) + 1; - while (cp >= buff + 2 && *cp == '\n') - cp--; - LogPrintf(LogCHAT, "Sending: %.*s\n", cp - buff - 1, buff + 2); - } - cp = buff; - if (DEV_IS_SYNC) - memcpy(buff, "\377\003", 2); /* Prepend HDLC header */ - else - cp += 2; - on = strlen(cp); - write(modem, cp, on); - } -} - -static int -ExpectString(char *str) -{ - char *minus; - int state; - - if (strcmp(str, "ABORT") == 0) { - ++abort_next; - return (MATCH); - } - if (strcmp(str, "TIMEOUT") == 0) { - ++timeout_next; - return (MATCH); - } - LogPrintf(LogCHAT, "Expecting: %s\n", str); - while (*str) { - /* - * Check whether if string contains sub-send-expect. - */ - for (minus = str; *minus; minus++) { - if (*minus == '-') { - if (minus == str || minus[-1] != '\\') - break; - } - } - if (*minus == '-') { /* We have sub-send-expect. */ - *minus = '\0'; /* XXX: Cheat with the const string */ - state = WaitforString(str); - *minus = '-'; /* XXX: Cheat with the const string */ - minus++; - if (state != NOMATCH) - return (state); - - /* - * Can't get expect string. Sendout send part. - */ - str = minus; - for (minus = str; *minus; minus++) { - if (*minus == '-') { - if (minus == str || minus[-1] != '\\') - break; - } - } - if (*minus == '-') { - *minus = '\0'; /* XXX: Cheat with the const string */ - SendString(str); - *minus = '-'; /* XXX: Cheat with the const string */ - str = ++minus; - } else { - SendString(str); - return (MATCH); - } - } else { - /* - * Simple case. Wait for string. - */ - return (WaitforString(str)); - } - } - return (MATCH); -} - -static void (*oint) (int); - -static void -StopDial(int sig) -{ - LogPrintf(LogPHASE, "DoChat: Caught signal %d, abort connect\n", sig); - longjmp(ChatEnv, 1); -} - -int -DoChat(char *script) -{ - char *vector[MAXARGS]; - char *const *argv; - int argc, n, state, err; - - if (!script || !*script) - return MATCH; - - if ((err = setjmp(ChatEnv))) { - signal(SIGINT, oint); - if (err == 1) - /* Caught a SIGINT during chat */ - return (-1); - return (NOMATCH); - } - oint = signal(SIGINT, StopDial); - - timeout_next = abort_next = 0; - for (n = 0; AbortStrings[n]; n++) { - free(AbortStrings[n]); - AbortStrings[n] = NULL; - } - numaborts = 0; - - memset(vector, '\0', sizeof vector); - argc = MakeArgs(script, vector, VECSIZE(vector)); - argv = vector; - TimeoutSec = 30; - while (*argv) { - if (strcmp(*argv, "P_ZERO") == 0 || - strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) { - ChangeParity(*argv++); - continue; - } - state = ExpectString(*argv++); - switch (state) { - case MATCH: - if (*argv) - SendString(*argv++); - break; - case ABORT: - case NOMATCH: - signal(SIGINT, oint); - return (NOMATCH); - } - } - signal(SIGINT, oint); - return (MATCH); -} diff --git a/usr.sbin/ppp/chat.h b/usr.sbin/ppp/chat.h deleted file mode 100644 index 4a53844c35c..00000000000 --- a/usr.sbin/ppp/chat.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com). - * - * Chat -- a program for automatic session establishment (i.e. dial - * the phone and log in). - * - * This software is in the public domain. - * - * Please send all bug reports, requests for information, etc. to: - * - * Karl Fox <karl@MorningStar.Com> - * Morning Star Technologies, Inc. - * 1760 Zollinger Road - * Columbus, OH 43221 - * (614)451-1883 - * - * $Id: chat.h,v 1.1 1997/11/23 20:27:33 brian Exp $ - * - */ - -#define VECSIZE(v) (sizeof(v) / sizeof(v[0])) - -extern char *ExpandString(const char *, char *, int, int); -extern int MakeArgs(char *, char **, int); /* Mangles the first arg ! */ -extern int DoChat(char *); /* passes arg to MakeArgs() */ diff --git a/usr.sbin/ppp/command.c b/usr.sbin/ppp/command.c deleted file mode 100644 index 7f78149c1ac..00000000000 --- a/usr.sbin/ppp/command.c +++ /dev/null @@ -1,1687 +0,0 @@ -/* - * PPP User command processing module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: command.c,v 1.31 1998/06/28 09:41:37 brian Exp $ - * - */ -#include <sys/param.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <arpa/inet.h> -#include <sys/socket.h> -#include <net/route.h> -#include <netdb.h> - -#ifndef NOALIAS -#include <alias.h> -#endif -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <termios.h> -#include <time.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "phase.h" -#include "lcp.h" -#include "iplist.h" -#include "ipcp.h" -#include "modem.h" -#include "filter.h" -#ifndef NOALIAS -#include "alias_cmd.h" -#endif -#include "hdlc.h" -#include "loadalias.h" -#include "vars.h" -#include "systems.h" -#include "chat.h" -#include "os.h" -#include "server.h" -#include "main.h" -#include "route.h" -#include "ccp.h" -#include "ip.h" -#include "slcompress.h" -#include "auth.h" - -struct in_addr ifnetmask; -static const char *HIDDEN = "********"; - -static int ShowCommand(struct cmdargs const *arg); -static int TerminalCommand(struct cmdargs const *arg); -static int QuitCommand(struct cmdargs const *arg); -static int CloseCommand(struct cmdargs const *arg); -static int DialCommand(struct cmdargs const *arg); -static int DownCommand(struct cmdargs const *arg); -static int AllowCommand(struct cmdargs const *arg); -static int SetCommand(struct cmdargs const *arg); -static int AddCommand(struct cmdargs const *arg); -static int DeleteCommand(struct cmdargs const *arg); -static int BgShellCommand(struct cmdargs const *arg); -static int FgShellCommand(struct cmdargs const *arg); -#ifndef NOALIAS -static int AliasCommand(struct cmdargs const *arg); -static int AliasEnable(struct cmdargs const *arg); -static int AliasOption(struct cmdargs const *arg); -#endif - -static int -HelpCommand(struct cmdargs const *arg) -{ - struct cmdtab const *cmd; - int n, cmax, dmax, cols; - - if (!VarTerm) - return 0; - - if (arg->argc > 0) { - for (cmd = arg->cmd; cmd->name; cmd++) - if (strcasecmp(cmd->name, *arg->argv) == 0 && - (cmd->lauth & VarLocalAuth)) { - fprintf(VarTerm, "%s\n", cmd->syntax); - return 0; - } - return -1; - } - cmax = dmax = 0; - for (cmd = arg->cmd; cmd->func; cmd++) - if (cmd->name && (cmd->lauth & VarLocalAuth)) { - if ((n = strlen(cmd->name)) > cmax) - cmax = n; - if ((n = strlen(cmd->helpmes)) > dmax) - dmax = n; - } - - cols = 80 / (dmax + cmax + 3); - n = 0; - for (cmd = arg->cmd; cmd->func; cmd++) - if (cmd->name && (cmd->lauth & VarLocalAuth)) { - fprintf(VarTerm, " %-*.*s: %-*.*s", - cmax, cmax, cmd->name, dmax, dmax, cmd->helpmes); - if (++n % cols == 0) - fprintf(VarTerm, "\n"); - } - if (n % cols != 0) - fprintf(VarTerm, "\n"); - - return 0; -} - -int -IsInteractive(int Display) -{ - const char *m = NULL; - - if (mode & MODE_DDIAL) - m = "direct dial"; - else if (mode & MODE_BACKGROUND) - m = "background"; - else if (mode & MODE_AUTO) - m = "auto"; - else if (mode & MODE_DIRECT) - m = "direct"; - else if (mode & MODE_DEDICATED) - m = "dedicated"; - else if (mode & MODE_INTER) - m = "interactive"; - if (m) { - if (Display && VarTerm) - fprintf(VarTerm, "Working in %s mode\n", m); - } - return mode & MODE_INTER; -} - -static int -DialCommand(struct cmdargs const *arg) -{ - int tries; - int res; - - if (LcpFsm.state > ST_CLOSED) { - if (VarTerm) - fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]); - return 0; - } - - if ((mode & MODE_DAEMON) && !(mode & MODE_AUTO)) { - LogPrintf(LogWARN, - "Manual dial is only available in auto and interactive mode\n"); - return 1; - } - - if (arg->argc > 0 && (res = LoadCommand(arg)) != 0) - return res; - - tries = 0; - do { - if (tries) { - LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", - VarRedialNextTimeout); - nointr_sleep(VarRedialNextTimeout); - } - if (VarTerm) - fprintf(VarTerm, "Dial attempt %u of %d\n", ++tries, VarDialTries); - if (OpenModem() < 0) { - if (VarTerm) - fprintf(VarTerm, "Failed to open modem.\n"); - break; - } - if ((res = DialModem()) == EX_DONE) { - ModemTimeout(NULL); - PacketMode(VarOpenMode); - break; - } else if (res == EX_SIG) - return 1; - } while (VarDialTries == 0 || tries < VarDialTries); - - return 0; -} - -static int -SetLoopback(struct cmdargs const *arg) -{ - if (arg->argc == 1) { - if (!strcasecmp(*arg->argv, "on")) { - VarLoopback = 1; - return 0; - } else if (!strcasecmp(*arg->argv, "off")) { - VarLoopback = 0; - return 0; - } - } - return -1; -} - -static int -ShellCommand(struct cmdargs const *arg, int bg) -{ - const char *shell; - pid_t shpid; - int argc; - char *argv[MAXARGS]; - -#ifdef SHELL_ONLY_INTERACTIVELY - /* we're only allowed to shell when we run ppp interactively */ - if (mode != MODE_INTER) { - LogPrintf(LogWARN, "Can only start a shell in interactive mode\n"); - return 1; - } -#endif -#ifdef NO_SHELL_IN_AUTO_INTERACTIVE - - /* - * we want to stop shell commands when we've got a telnet connection to an - * auto mode ppp - */ - if (VarTerm && !(mode & MODE_INTER)) { - LogPrintf(LogWARN, "Shell is not allowed interactively in auto mode\n"); - return 1; - } -#endif - - if (arg->argc == 0) { - if (!(mode & MODE_INTER)) { - if (VarTerm) - LogPrintf(LogWARN, "Can't start an interactive shell from" - " a telnet session\n"); - else - LogPrintf(LogWARN, "Can only start an interactive shell in" - " interactive mode\n"); - return 1; - } else if (bg) { - LogPrintf(LogWARN, "Can only start an interactive shell in" - " the foreground mode\n"); - return 1; - } - } - - if ((shell = getenv("SHELL")) == 0) - shell = _PATH_BSHELL; - - if ((shpid = fork()) == 0) { - int dtablesize, i, fd; - - TermTimerService(); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGALRM, SIG_DFL); - - if (VarTerm) - fd = fileno(VarTerm); - else if ((fd = open("/dev/null", O_RDWR)) == -1) { - LogPrintf(LogALERT, "Failed to open /dev/null: %s\n", strerror(errno)); - exit(1); - } - for (i = 0; i < 3; i++) - dup2(fd, i); - - for (dtablesize = getdtablesize(), i = 3; i < dtablesize; i++) - close(i); - - TtyOldMode(); - setuid(geteuid()); - if (arg->argc > 0) { - /* substitute pseudo args */ - argv[0] = strdup(arg->argv[0]); - for (argc = 1; argc < arg->argc; argc++) { - if (strcasecmp(arg->argv[argc], "HISADDR") == 0) - argv[argc] = strdup(inet_ntoa(IpcpInfo.his_ipaddr)); - else if (strcasecmp(arg->argv[argc], "INTERFACE") == 0) - argv[argc] = strdup(IfDevName); - else if (strcasecmp(arg->argv[argc], "MYADDR") == 0) - argv[argc] = strdup(inet_ntoa(IpcpInfo.want_ipaddr)); - else - argv[argc] = strdup(arg->argv[argc]); - } - argv[argc] = NULL; - if (bg) { - pid_t p; - - p = getpid(); - if (daemon(1, 1) == -1) { - LogPrintf(LogERROR, "%d: daemon: %s\n", p, strerror(errno)); - exit(1); - } - } else if (VarTerm) - printf("ppp: Pausing until %s finishes\n", arg->argv[0]); - execvp(argv[0], argv); - } else { - if (VarTerm) - printf("ppp: Pausing until %s finishes\n", shell); - execl(shell, shell, NULL); - } - - LogPrintf(LogWARN, "exec() of %s failed\n", - arg->argc > 0 ? arg->argv[0] : shell); - exit(255); - } - if (shpid == (pid_t) - 1) { - LogPrintf(LogERROR, "Fork failed: %s\n", strerror(errno)); - } else { - int status; - - waitpid(shpid, &status, 0); - } - - TtyCommandMode(0); - - return (0); -} - -static int -BgShellCommand(struct cmdargs const *arg) -{ - if (arg->argc == 0) - return -1; - return ShellCommand(arg, 1); -} - -static int -FgShellCommand(struct cmdargs const *arg) -{ - return ShellCommand(arg, 0); -} - -static struct cmdtab const Commands[] = { - {"accept", NULL, AcceptCommand, LOCAL_AUTH, - "accept option request", "accept option .."}, - {"add", NULL, AddCommand, LOCAL_AUTH, - "add route", "add dest mask gateway", NULL}, - {"add!", NULL, AddCommand, LOCAL_AUTH, - "add or change route", "add! dest mask gateway", (void *)1}, - {"allow", "auth", AllowCommand, LOCAL_AUTH, - "Allow ppp access", "allow users|modes ...."}, - {"bg", "!bg", BgShellCommand, LOCAL_AUTH, - "Run a background command", "[!]bg command"}, - {"close", NULL, CloseCommand, LOCAL_AUTH, - "Close connection", "close"}, - {"delete", NULL, DeleteCommand, LOCAL_AUTH, - "delete route", "delete dest", NULL}, - {"delete!", NULL, DeleteCommand, LOCAL_AUTH, - "delete a route if it exists", "delete! dest", (void *)1}, - {"deny", NULL, DenyCommand, LOCAL_AUTH, - "Deny option request", "deny option .."}, - {"dial", "call", DialCommand, LOCAL_AUTH, - "Dial and login", "dial|call [remote]"}, - {"disable", NULL, DisableCommand, LOCAL_AUTH, - "Disable option", "disable option .."}, - {"display", NULL, DisplayCommand, LOCAL_AUTH, - "Display option configs", "display"}, - {"enable", NULL, EnableCommand, LOCAL_AUTH, - "Enable option", "enable option .."}, - {"passwd", NULL, LocalAuthCommand, LOCAL_NO_AUTH, - "Password for manipulation", "passwd LocalPassword"}, - {"load", NULL, LoadCommand, LOCAL_AUTH, - "Load settings", "load [remote]"}, - {"save", NULL, SaveCommand, LOCAL_AUTH, - "Save settings", "save"}, - {"set", "setup", SetCommand, LOCAL_AUTH, - "Set parameters", "set[up] var value"}, - {"shell", "!", FgShellCommand, LOCAL_AUTH, - "Run a subshell", "shell|! [sh command]"}, - {"show", NULL, ShowCommand, LOCAL_AUTH, - "Show status and stats", "show var"}, - {"term", NULL, TerminalCommand, LOCAL_AUTH, - "Enter terminal mode", "term"}, -#ifndef NOALIAS - {"alias", NULL, AliasCommand, LOCAL_AUTH, - "alias control", "alias option [yes|no]"}, -#endif - {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Quit PPP program", "quit|bye [all]"}, - {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Display this message", "help|? [command]", Commands}, - {NULL, "down", DownCommand, LOCAL_AUTH, - "Generate down event", "down"}, - {NULL, NULL, NULL}, -}; - -static int -ShowLoopback(struct cmdargs const *arg) -{ - if (VarTerm) - fprintf(VarTerm, "Local loopback is %s\n", VarLoopback ? "on" : "off"); - - return 0; -} - -static int -ShowLogLevel(struct cmdargs const *arg) -{ - int i; - - if (!VarTerm) - return 0; - - fprintf(VarTerm, "Log: "); - for (i = LogMIN; i <= LogMAX; i++) - if (LogIsKept(i) & LOG_KEPT_SYSLOG) - fprintf(VarTerm, " %s", LogName(i)); - - fprintf(VarTerm, "\nLocal:"); - for (i = LogMIN; i <= LogMAX; i++) - if (LogIsKept(i) & LOG_KEPT_LOCAL) - fprintf(VarTerm, " %s", LogName(i)); - - fprintf(VarTerm, "\n"); - - return 0; -} - -static int -ShowEscape(struct cmdargs const *arg) -{ - int code, bit; - - if (!VarTerm) - return 0; - if (EscMap[32]) { - for (code = 0; code < 32; code++) - if (EscMap[code]) - for (bit = 0; bit < 8; bit++) - if (EscMap[code] & (1 << bit)) - fprintf(VarTerm, " 0x%02x", (code << 3) + bit); - fprintf(VarTerm, "\n"); - } - return 0; -} - -static int -ShowTimeout(struct cmdargs const *arg) -{ - if (VarTerm) { - int remaining; - - fprintf(VarTerm, " Idle Timer: %d secs LQR Timer: %d secs" - " Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout, - VarRetryTimeout); - remaining = RemainingIdleTime(); - if (remaining != -1) - fprintf(VarTerm, " %d secs remaining\n", remaining); - } - return 0; -} - -static int -ShowStopped(struct cmdargs const *arg) -{ - if (!VarTerm) - return 0; - - fprintf(VarTerm, " Stopped Timer: LCP: "); - if (!LcpFsm.StoppedTimer.load) - fprintf(VarTerm, "Disabled"); - else - fprintf(VarTerm, "%ld secs", LcpFsm.StoppedTimer.load / SECTICKS); - - fprintf(VarTerm, ", IPCP: "); - if (!IpcpFsm.StoppedTimer.load) - fprintf(VarTerm, "Disabled"); - else - fprintf(VarTerm, "%ld secs", IpcpFsm.StoppedTimer.load / SECTICKS); - - fprintf(VarTerm, ", CCP: "); - if (!CcpFsm.StoppedTimer.load) - fprintf(VarTerm, "Disabled"); - else - fprintf(VarTerm, "%ld secs", CcpFsm.StoppedTimer.load / SECTICKS); - - fprintf(VarTerm, "\n"); - - return 0; -} - -static int -ShowAuthKey(struct cmdargs const *arg) -{ - if (!VarTerm) - return 0; - fprintf(VarTerm, "AuthName = %s\n", VarAuthName); - fprintf(VarTerm, "AuthKey = %s\n", HIDDEN); -#ifdef HAVE_DES - fprintf(VarTerm, "Encrypt = %s\n", VarMSChap ? "MSChap" : "MD5" ); -#endif - return 0; -} - -static int -ShowVersion(struct cmdargs const *arg) -{ - if (VarTerm) - fprintf(VarTerm, "%s - %s \n", VarVersion, VarLocalVersion); - return 0; -} - -static int -ShowInitialMRU(struct cmdargs const *arg) -{ - if (VarTerm) - fprintf(VarTerm, " Initial MRU: %d\n", VarMRU); - return 0; -} - -static int -ShowPreferredMTU(struct cmdargs const *arg) -{ - if (VarTerm) { - if (VarPrefMTU) - fprintf(VarTerm, " Preferred MTU: %d\n", VarPrefMTU); - else - fprintf(VarTerm, " Preferred MTU: unspecified\n"); - } - return 0; -} - -static int -ShowReconnect(struct cmdargs const *arg) -{ - if (VarTerm) - fprintf(VarTerm, " Reconnect Timer: %d, %d tries\n", - VarReconnectTimer, VarReconnectTries); - return 0; -} - -static int -ShowRedial(struct cmdargs const *arg) -{ - if (!VarTerm) - return 0; - fprintf(VarTerm, " Redial Timer: "); - - if (VarRedialTimeout >= 0) { - fprintf(VarTerm, " %d seconds, ", VarRedialTimeout); - } else { - fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD); - } - - fprintf(VarTerm, " Redial Next Timer: "); - - if (VarRedialNextTimeout >= 0) { - fprintf(VarTerm, " %d seconds, ", VarRedialNextTimeout); - } else { - fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD); - } - - if (VarDialTries) - fprintf(VarTerm, "%d dial tries", VarDialTries); - - fprintf(VarTerm, "\n"); - - return 0; -} - -#ifndef NOMSEXT -static int -ShowMSExt(struct cmdargs const *arg) -{ - if (VarTerm) { - fprintf(VarTerm, " MS PPP extention values \n"); - fprintf(VarTerm, " Primary NS : %s\n", inet_ntoa(ns_entries[0])); - fprintf(VarTerm, " Secondary NS : %s\n", inet_ntoa(ns_entries[1])); - fprintf(VarTerm, " Primary NBNS : %s\n", inet_ntoa(nbns_entries[0])); - fprintf(VarTerm, " Secondary NBNS : %s\n", inet_ntoa(nbns_entries[1])); - } - return 0; -} - -#endif - -static struct cmdtab const ShowCommands[] = { - {"afilter", NULL, ShowAfilter, LOCAL_AUTH, - "Show keep-alive filters", "show afilter option .."}, - {"auth", NULL, ShowAuthKey, LOCAL_AUTH, - "Show auth details", "show auth"}, - {"ccp", NULL, ReportCcpStatus, LOCAL_AUTH, - "Show CCP status", "show cpp"}, - {"compress", NULL, ReportCompress, LOCAL_AUTH, - "Show compression stats", "show compress"}, - {"dfilter", NULL, ShowDfilter, LOCAL_AUTH, - "Show Demand filters", "show dfilteroption .."}, - {"escape", NULL, ShowEscape, LOCAL_AUTH, - "Show escape characters", "show escape"}, - {"hdlc", NULL, ReportHdlcStatus, LOCAL_AUTH, - "Show HDLC errors", "show hdlc"}, - {"ifilter", NULL, ShowIfilter, LOCAL_AUTH, - "Show Input filters", "show ifilter option .."}, - {"ipcp", NULL, ReportIpcpStatus, LOCAL_AUTH, - "Show IPCP status", "show ipcp"}, - {"lcp", NULL, ReportLcpStatus, LOCAL_AUTH, - "Show LCP status", "show lcp"}, - {"loopback", NULL, ShowLoopback, LOCAL_AUTH, - "Show loopback setting", "show loopback"}, - {"log", NULL, ShowLogLevel, LOCAL_AUTH, - "Show log levels", "show log"}, - {"mem", NULL, ShowMemMap, LOCAL_AUTH, - "Show memory map", "show mem"}, - {"modem", NULL, ShowModemStatus, LOCAL_AUTH, - "Show modem setups", "show modem"}, - {"mru", NULL, ShowInitialMRU, LOCAL_AUTH, - "Show Initial MRU", "show mru"}, -#ifndef NOMSEXT - {"msext", NULL, ShowMSExt, LOCAL_AUTH, - "Show MS PPP extentions", "show msext"}, -#endif - {"mtu", NULL, ShowPreferredMTU, LOCAL_AUTH, - "Show Preferred MTU", "show mtu"}, - {"ofilter", NULL, ShowOfilter, LOCAL_AUTH, - "Show Output filters", "show ofilter option .."}, - {"proto", NULL, ReportProtStatus, LOCAL_AUTH, - "Show protocol summary", "show proto"}, - {"reconnect", NULL, ShowReconnect, LOCAL_AUTH, - "Show reconnect timer", "show reconnect"}, - {"redial", NULL, ShowRedial, LOCAL_AUTH, - "Show Redial timeout", "show redial"}, - {"route", NULL, ShowRoute, LOCAL_AUTH, - "Show routing table", "show route"}, - {"timeout", NULL, ShowTimeout, LOCAL_AUTH, - "Show Idle timeout", "show timeout"}, - {"stopped", NULL, ShowStopped, LOCAL_AUTH, - "Show STOPPED timeout", "show stopped"}, - {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, - "Show version string", "show version"}, - {"vj", NULL, ShowInitVJ, LOCAL_AUTH, - "Show VJ values", "show vj"}, - {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, - "Display this message", "show help|? [command]", ShowCommands}, - {NULL, NULL, NULL}, -}; - -static struct cmdtab const * -FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) -{ - int nmatch; - int len; - struct cmdtab const *found; - - found = NULL; - len = strlen(str); - nmatch = 0; - while (cmds->func) { - if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { - if (cmds->name[len] == '\0') { - *pmatch = 1; - return cmds; - } - nmatch++; - found = cmds; - } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { - if (cmds->alias[len] == '\0') { - *pmatch = 1; - return cmds; - } - nmatch++; - found = cmds; - } - cmds++; - } - *pmatch = nmatch; - return found; -} - -static int -FindExec(struct cmdtab const *cmds, int argc, char const *const *argv, - const char *prefix) -{ - struct cmdtab const *cmd; - int val = 1; - int nmatch; - struct cmdargs arg; - - cmd = FindCommand(cmds, *argv, &nmatch); - if (nmatch > 1) - LogPrintf(LogWARN, "%s%s: Ambiguous command\n", prefix, *argv); - else if (cmd && (cmd->lauth & VarLocalAuth)) { - arg.cmd = cmds; - arg.argc = argc-1; - arg.argv = argv+1; - arg.data = cmd->args; - val = (cmd->func) (&arg); - } else - LogPrintf(LogWARN, "%s%s: Invalid command\n", prefix, *argv); - - if (val == -1) - LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax); - else if (val) - LogPrintf(LogWARN, "%s%s: Failed %d\n", prefix, *argv, val); - - return val; -} - -int aft_cmd = 1; - -void -Prompt() -{ - const char *pconnect, *pauth; - - if (!VarTerm || TermMode) - return; - - if (!aft_cmd) - fprintf(VarTerm, "\n"); - else - aft_cmd = 0; - - if (VarLocalAuth == LOCAL_AUTH) - pauth = " ON "; - else - pauth = " on "; - if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK) - pconnect = "PPP"; - else - pconnect = "ppp"; - fprintf(VarTerm, "%s%s%s> ", pconnect, pauth, VarShortHost); - fflush(VarTerm); -} - -void -InterpretCommand(char *buff, int nb, int *argc, char ***argv) -{ - static char *vector[MAXARGS]; - char *cp; - - if (nb > 0) { - cp = buff + strcspn(buff, "\r\n"); - if (cp) - *cp = '\0'; - *argc = MakeArgs(buff, vector, VECSIZE(vector)); - *argv = vector; - } else - *argc = 0; -} - -static int -arghidden(int argc, char const *const *argv, int n) -{ - /* Is arg n of the given command to be hidden from the log ? */ - - /* set authkey xxxxx */ - /* set key xxxxx */ - if (n == 2 && !strncasecmp(argv[0], "se", 2) && - (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) - return 1; - - /* passwd xxxxx */ - if (n == 1 && !strncasecmp(argv[0], "p", 1)) - return 1; - - return 0; -} - -void -RunCommand(int argc, char const *const *argv, const char *label) -{ - if (argc > 0) { - if (LogIsKept(LogCOMMAND)) { - static char buf[LINE_LEN]; - int f, n; - - *buf = '\0'; - if (label) { - strncpy(buf, label, sizeof buf - 3); - buf[sizeof buf - 3] = '\0'; - strcat(buf, ": "); - } - n = strlen(buf); - for (f = 0; f < argc; f++) { - if (n < sizeof buf - 1 && f) - buf[n++] = ' '; - if (arghidden(argc, argv, f)) - strncpy(buf+n, HIDDEN, sizeof buf - n - 1); - else - strncpy(buf+n, argv[f], sizeof buf - n - 1); - n += strlen(buf+n); - } - LogPrintf(LogCOMMAND, "%s\n", buf); - } - FindExec(Commands, argc, argv, ""); - } -} - -void -DecodeCommand(char *buff, int nb, const char *label) -{ - int argc; - char **argv; - - InterpretCommand(buff, nb, &argc, &argv); - RunCommand(argc, (char const *const *)argv, label); -} - -static int -ShowCommand(struct cmdargs const *arg) -{ - if (arg->argc > 0) - FindExec(ShowCommands, arg->argc, arg->argv, "show "); - else if (VarTerm) - fprintf(VarTerm, "Use ``show ?'' to get a arg->cmd.\n"); - else - LogPrintf(LogWARN, "show command must have arguments\n"); - - return 0; -} - -static int -TerminalCommand(struct cmdargs const *arg) -{ - if (LcpFsm.state > ST_CLOSED) { - if (VarTerm) - fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]); - return 1; - } - if (!IsInteractive(1)) - return (1); - if (OpenModem() < 0) { - if (VarTerm) - fprintf(VarTerm, "Failed to open modem.\n"); - return (1); - } - if (VarTerm) { - fprintf(VarTerm, "Entering terminal mode.\n"); - fprintf(VarTerm, "Type `~?' for help.\n"); - } - TtyTermMode(); - return (0); -} - -static int -QuitCommand(struct cmdargs const *arg) -{ - if (VarTerm) { - DropClient(1); - if (mode & MODE_INTER) - Cleanup(EX_NORMAL); - else if (arg->argc > 0 && !strcasecmp(*arg->argv, "all") && VarLocalAuth&LOCAL_AUTH) - Cleanup(EX_NORMAL); - } - - return 0; -} - -static int -CloseCommand(struct cmdargs const *arg) -{ - reconnect(RECON_FALSE); - LcpClose(); - return 0; -} - -static int -DownCommand(struct cmdargs const *arg) -{ - LcpDown(); - return 0; -} - -static int -SetModemSpeed(struct cmdargs const *arg) -{ - int speed; - - if (arg->argc > 0) { - if (strcasecmp(*arg->argv, "sync") == 0) { - VarSpeed = 0; - return 0; - } - speed = atoi(*arg->argv); - if (IntToSpeed(speed) != B0) { - VarSpeed = speed; - return 0; - } - LogPrintf(LogWARN, "%s: Invalid speed\n", *arg->argv); - } - return -1; -} - -static int -SetReconnect(struct cmdargs const *arg) -{ - if (arg->argc == 2) { - VarReconnectTimer = atoi(arg->argv[0]); - VarReconnectTries = atoi(arg->argv[1]); - return 0; - } - return -1; -} - -static int -SetRedialTimeout(struct cmdargs const *arg) -{ - int timeout; - int tries; - char *dot; - - if (arg->argc == 1 || arg->argc == 2) { - if (strncasecmp(arg->argv[0], "random", 6) == 0 && - (arg->argv[0][6] == '\0' || arg->argv[0][6] == '.')) { - VarRedialTimeout = -1; - randinit(); - } else { - timeout = atoi(arg->argv[0]); - - if (timeout >= 0) - VarRedialTimeout = timeout; - else { - LogPrintf(LogWARN, "Invalid redial timeout\n"); - return -1; - } - } - - dot = strchr(arg->argv[0], '.'); - if (dot) { - if (strcasecmp(++dot, "random") == 0) { - VarRedialNextTimeout = -1; - randinit(); - } else { - timeout = atoi(dot); - if (timeout >= 0) - VarRedialNextTimeout = timeout; - else { - LogPrintf(LogWARN, "Invalid next redial timeout\n"); - return -1; - } - } - } else - VarRedialNextTimeout = NEXT_REDIAL_PERIOD; /* Default next timeout */ - - if (arg->argc == 2) { - tries = atoi(arg->argv[1]); - - if (tries >= 0) { - VarDialTries = tries; - } else { - LogPrintf(LogWARN, "Invalid retry value\n"); - return 1; - } - } - return 0; - } - return -1; -} - -static int -SetStoppedTimeout(struct cmdargs const *arg) -{ - LcpFsm.StoppedTimer.load = 0; - IpcpFsm.StoppedTimer.load = 0; - CcpFsm.StoppedTimer.load = 0; - if (arg->argc <= 3) { - if (arg->argc > 0) { - LcpFsm.StoppedTimer.load = atoi(arg->argv[0]) * SECTICKS; - if (arg->argc > 1) { - IpcpFsm.StoppedTimer.load = atoi(arg->argv[1]) * SECTICKS; - if (arg->argc > 2) - CcpFsm.StoppedTimer.load = atoi(arg->argv[2]) * SECTICKS; - } - } - return 0; - } - return -1; -} - -#define ismask(x) \ - (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3) - -static int -SetServer(struct cmdargs const *arg) -{ - int res = -1; - - if (arg->argc > 0 && arg->argc < 4) { - const char *port, *passwd, *mask; - - /* What's what ? */ - port = arg->argv[0]; - if (arg->argc == 2) { - if (ismask(arg->argv[1])) { - passwd = NULL; - mask = arg->argv[1]; - } else { - passwd = arg->argv[1]; - mask = NULL; - } - } else if (arg->argc == 3) { - passwd = arg->argv[1]; - mask = arg->argv[2]; - if (!ismask(mask)) - return -1; - } else - passwd = mask = NULL; - - if (passwd == NULL) - VarHaveLocalAuthKey = 0; - else { - strncpy(VarLocalAuthKey, passwd, sizeof VarLocalAuthKey - 1); - VarLocalAuthKey[sizeof VarLocalAuthKey - 1] = '\0'; - VarHaveLocalAuthKey = 1; - } - LocalAuthInit(); - - if (strcasecmp(port, "none") == 0) { - int oserver; - - if (mask != NULL || passwd != NULL) - return -1; - oserver = server; - ServerClose(); - if (oserver != -1) - LogPrintf(LogPHASE, "Disabling server port.\n"); - res = 0; - } else if (*port == '/') { - mode_t imask; - - if (mask != NULL) { - unsigned m; - - if (sscanf(mask, "%o", &m) == 1) - imask = m; - else - return -1; - } else - imask = (mode_t)-1; - res = ServerLocalOpen(port, imask); - } else { - int iport; - - if (mask != NULL) - return -1; - - if (strspn(port, "0123456789") != strlen(port)) { - struct servent *s; - - if ((s = getservbyname(port, "tcp")) == NULL) { - iport = 0; - LogPrintf(LogWARN, "%s: Invalid port or service\n", port); - } else - iport = ntohs(s->s_port); - } else - iport = atoi(port); - res = iport ? ServerTcpOpen(iport) : -1; - } - } - - return res; -} - -static int -SetModemParity(struct cmdargs const *arg) -{ - return arg->argc > 0 ? ChangeParity(*arg->argv) : -1; -} - -static int -SetLogLevel(struct cmdargs const *arg) -{ - int i; - int res; - int argc; - char const *const *argv, *argp; - void (*Discard)(int), (*Keep)(int); - void (*DiscardAll)(void); - - argc = arg->argc; - argv = arg->argv; - res = 0; - if (argc == 0 || strcasecmp(argv[0], "local")) { - Discard = LogDiscard; - Keep = LogKeep; - DiscardAll = LogDiscardAll; - } else { - argc--; - argv++; - Discard = LogDiscardLocal; - Keep = LogKeepLocal; - DiscardAll = LogDiscardAllLocal; - } - - if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) - DiscardAll(); - while (argc--) { - argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv; - for (i = LogMIN; i <= LogMAX; i++) - if (strcasecmp(argp, LogName(i)) == 0) { - if (**argv == '-') - (*Discard)(i); - else - (*Keep)(i); - break; - } - if (i > LogMAX) { - LogPrintf(LogWARN, "%s: Invalid log value\n", argp); - res = -1; - } - argv++; - } - return res; -} - -static int -SetEscape(struct cmdargs const *arg) -{ - int code; - int argc = arg->argc; - char const *const *argv = arg->argv; - - for (code = 0; code < 33; code++) - EscMap[code] = 0; - - while (argc-- > 0) { - sscanf(*argv++, "%x", &code); - code &= 0xff; - EscMap[code >> 3] |= (1 << (code & 7)); - EscMap[32] = 1; - } - return 0; -} - -static int -SetInitialMRU(struct cmdargs const *arg) -{ - long mru; - const char *err; - - if (arg->argc > 0) { - mru = atol(*arg->argv); - if (mru < MIN_MRU) - err = "Given MRU value (%ld) is too small.\n"; - else if (mru > MAX_MRU) - err = "Given MRU value (%ld) is too big.\n"; - else { - VarMRU = mru; - return 0; - } - LogPrintf(LogWARN, err, mru); - } - return -1; -} - -static int -SetPreferredMTU(struct cmdargs const *arg) -{ - long mtu; - const char *err; - - if (arg->argc > 0) { - mtu = atol(*arg->argv); - if (mtu == 0) { - VarPrefMTU = 0; - return 0; - } else if (mtu < MIN_MTU) - err = "Given MTU value (%ld) is too small.\n"; - else if (mtu > MAX_MTU) - err = "Given MTU value (%ld) is too big.\n"; - else { - VarPrefMTU = mtu; - return 0; - } - LogPrintf(LogWARN, err, mtu); - } - return -1; -} - -static int -SetTimeout(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - VarIdleTimeout = atoi(arg->argv[0]); - UpdateIdleTimer(); /* If we're connected, restart the idle timer */ - if (arg->argc > 1) { - VarLqrTimeout = atoi(arg->argv[1]); - if (VarLqrTimeout < 1) - VarLqrTimeout = 30; - if (arg->argc > 2) { - VarRetryTimeout = atoi(arg->argv[2]); - if (VarRetryTimeout < 1 || VarRetryTimeout > 10) - VarRetryTimeout = 3; - } - } - return 0; - } - return -1; -} - -static struct in_addr -GetIpAddr(const char *cp) -{ - struct hostent *hp; - struct in_addr ipaddr; - - if (inet_aton(cp, &ipaddr) == 0) { - hp = gethostbyname(cp); - if (hp && hp->h_addrtype == AF_INET) - memcpy(&ipaddr, hp->h_addr, hp->h_length); - else - ipaddr.s_addr = 0; - } - return (ipaddr); -} - -static int -SetInterfaceAddr(struct cmdargs const *arg) -{ - const char *hisaddr; - - hisaddr = NULL; - DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L; - - if (arg->argc > 4) - return -1; - - HaveTriggerAddress = 0; - ifnetmask.s_addr = 0; - iplist_reset(&DefHisChoice); - - if (arg->argc > 0) { - if (!ParseAddr(arg->argc, arg->argv, &DefMyAddress.ipaddr, - &DefMyAddress.mask, &DefMyAddress.width)) - return 1; - if (arg->argc > 1) { - hisaddr = arg->argv[1]; - if (arg->argc > 2) { - ifnetmask = GetIpAddr(arg->argv[2]); - if (arg->argc > 3) { - TriggerAddress = GetIpAddr(arg->argv[3]); - HaveTriggerAddress = 1; - } - } - } - } - - /* - * For backwards compatibility, 0.0.0.0 means any address. - */ - if (DefMyAddress.ipaddr.s_addr == 0) { - DefMyAddress.mask.s_addr = 0; - DefMyAddress.width = 0; - } - IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; - - if (hisaddr && !UseHisaddr(hisaddr, mode & MODE_AUTO)) - return 4; - - if (DefHisAddress.ipaddr.s_addr == 0) { - DefHisAddress.mask.s_addr = 0; - DefHisAddress.width = 0; - } - - return 0; -} - -#ifndef NOMSEXT - -static void -SetMSEXT(struct in_addr * pri_addr, - struct in_addr * sec_addr, - int argc, - char const *const *argv) -{ - int dummyint; - struct in_addr dummyaddr; - - pri_addr->s_addr = sec_addr->s_addr = 0L; - - if (argc > 0) { - ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint); - if (--argc > 0) - ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint); - else - sec_addr->s_addr = pri_addr->s_addr; - } - - /* - * if the primary/secondary ns entries are 0.0.0.0 we should set them to - * either the localhost's ip, or the values in /etc/resolv.conf ?? - * - * up to you if you want to implement this... - */ - -} - -static int -SetNS(struct cmdargs const *arg) -{ - SetMSEXT(&ns_entries[0], &ns_entries[1], arg->argc, arg->argv); - return 0; -} - -static int -SetNBNS(struct cmdargs const *arg) -{ - SetMSEXT(&nbns_entries[0], &nbns_entries[1], arg->argc, arg->argv); - return 0; -} - -#endif /* MS_EXT */ - -int -SetVariable(struct cmdargs const *arg) -{ - u_long map; - const char *argp; - long param = (long)arg->data; - - if (arg->argc > 0) - argp = *arg->argv; - else - argp = ""; - - switch (param) { - case VAR_AUTHKEY: - strncpy(VarAuthKey, argp, sizeof VarAuthKey - 1); - VarAuthKey[sizeof VarAuthKey - 1] = '\0'; - break; - case VAR_AUTHNAME: - strncpy(VarAuthName, argp, sizeof VarAuthName - 1); - VarAuthName[sizeof VarAuthName - 1] = '\0'; - break; - case VAR_DIAL: - strncpy(VarDialScript, argp, sizeof VarDialScript - 1); - VarDialScript[sizeof VarDialScript - 1] = '\0'; - break; - case VAR_LOGIN: - strncpy(VarLoginScript, argp, sizeof VarLoginScript - 1); - VarLoginScript[sizeof VarLoginScript - 1] = '\0'; - break; - case VAR_DEVICE: - if (mode & MODE_INTER) - HangupModem(0); - if (modem != -1) - LogPrintf(LogWARN, "Cannot change device to \"%s\" when \"%s\" is open\n", - argp, VarDevice); - else { - strncpy(VarDeviceList, argp, sizeof VarDeviceList - 1); - VarDeviceList[sizeof VarDeviceList - 1] = '\0'; - } - break; - case VAR_ACCMAP: - sscanf(argp, "%lx", &map); - VarAccmap = map; - break; - case VAR_PHONE: - strncpy(VarPhoneList, argp, sizeof VarPhoneList - 1); - VarPhoneList[sizeof VarPhoneList - 1] = '\0'; - strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1); - VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0'; - VarNextPhone = VarPhoneCopy; - VarAltPhone = NULL; - break; - case VAR_HANGUP: - strncpy(VarHangupScript, argp, sizeof VarHangupScript - 1); - VarHangupScript[sizeof VarHangupScript - 1] = '\0'; - break; -#ifdef HAVE_DES - case VAR_ENC: - VarMSChap = !strcasecmp(argp, "mschap"); - break; -#endif - } - return 0; -} - -static int -SetCtsRts(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - if (strcmp(*arg->argv, "on") == 0) - VarCtsRts = 1; - else if (strcmp(*arg->argv, "off") == 0) - VarCtsRts = 0; - else - return -1; - return 0; - } - return -1; -} - - -static int -SetOpenMode(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - if (strcasecmp(*arg->argv, "active") == 0) - VarOpenMode = arg->argc > 1 ? atoi(arg->argv[1]) : 1; - else if (strcasecmp(*arg->argv, "passive") == 0) - VarOpenMode = OPEN_PASSIVE; - else - return -1; - return 0; - } - return -1; -} - -static struct cmdtab const SetCommands[] = { - {"accmap", NULL, SetVariable, LOCAL_AUTH, - "Set accmap value", "set accmap hex-value", (const void *) VAR_ACCMAP}, - {"afilter", NULL, SetAfilter, LOCAL_AUTH, - "Set keep Alive filter", "set afilter ..."}, - {"authkey", "key", SetVariable, LOCAL_AUTH, - "Set authentication key", "set authkey|key key", (const void *) VAR_AUTHKEY}, - {"authname", NULL, SetVariable, LOCAL_AUTH, - "Set authentication name", "set authname name", (const void *) VAR_AUTHNAME}, - {"ctsrts", NULL, SetCtsRts, LOCAL_AUTH, - "Use CTS/RTS modem signalling", "set ctsrts [on|off]"}, - {"device", "line", SetVariable, LOCAL_AUTH, "Set modem device name", - "set device|line device-name[,device-name]", (const void *) VAR_DEVICE}, - {"dfilter", NULL, SetDfilter, LOCAL_AUTH, - "Set demand filter", "set dfilter ..."}, - {"dial", NULL, SetVariable, LOCAL_AUTH, - "Set dialing script", "set dial chat-script", (const void *) VAR_DIAL}, -#ifdef HAVE_DES - {"encrypt", NULL, SetVariable, LOCAL_AUTH, "Set CHAP encryption algorithm", - "set encrypt MSChap|MD5", (const void *) VAR_ENC}, -#endif - {"escape", NULL, SetEscape, LOCAL_AUTH, - "Set escape characters", "set escape hex-digit ..."}, - {"hangup", NULL, SetVariable, LOCAL_AUTH, - "Set hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, - {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "Set destination address", - "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, - {"ifilter", NULL, SetIfilter, LOCAL_AUTH, - "Set input filter", "set ifilter ..."}, - {"loopback", NULL, SetLoopback, LOCAL_AUTH, - "Set loopback facility", "set loopback on|off"}, - {"log", NULL, SetLogLevel, LOCAL_AUTH, - "Set log level", "set log [local] [+|-]value..."}, - {"login", NULL, SetVariable, LOCAL_AUTH, - "Set login script", "set login chat-script", (const void *) VAR_LOGIN}, - {"mru", NULL, SetInitialMRU, LOCAL_AUTH, - "Set Initial MRU value", "set mru value"}, - {"mtu", NULL, SetPreferredMTU, LOCAL_AUTH, - "Set Preferred MTU value", "set mtu value"}, -#ifndef NOMSEXT - {"nbns", NULL, SetNBNS, LOCAL_AUTH, - "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"}, - {"ns", NULL, SetNS, LOCAL_AUTH, - "Set NameServer", "set ns pri-addr [sec-addr]"}, -#endif - {"ofilter", NULL, SetOfilter, LOCAL_AUTH, - "Set output filter", "set ofilter ..."}, - {"openmode", NULL, SetOpenMode, LOCAL_AUTH, - "Set open mode", "set openmode [active|passive]"}, - {"parity", NULL, SetModemParity, LOCAL_AUTH, - "Set modem parity", "set parity [odd|even|none]"}, - {"phone", NULL, SetVariable, LOCAL_AUTH, "Set telephone number(s)", - "set phone phone1[:phone2[...]]", (const void *) VAR_PHONE}, - {"reconnect", NULL, SetReconnect, LOCAL_AUTH, - "Set Reconnect timeout", "set reconnect value ntries"}, - {"redial", NULL, SetRedialTimeout, LOCAL_AUTH, "Set Redial timeout", - "set redial value|random[.value|random] [dial_attempts]"}, - {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH, "Set STOPPED timeouts", - "set stopped [LCPseconds [IPCPseconds [CCPseconds]]]"}, - {"server", "socket", SetServer, LOCAL_AUTH, - "Set server port", "set server|socket TcpPort|LocalName|none [mask]"}, - {"speed", NULL, SetModemSpeed, LOCAL_AUTH, - "Set modem speed", "set speed value"}, - {"timeout", NULL, SetTimeout, LOCAL_AUTH, - "Set Idle timeout", "set timeout idle LQR FSM-resend"}, - {"vj", NULL, SetInitVJ, LOCAL_AUTH, - "Set vj values", "set vj slots|slotcomp"}, - {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Display this message", "set help|? [command]", SetCommands}, - {NULL, NULL, NULL}, -}; - -static int -SetCommand(struct cmdargs const *arg) -{ - if (arg->argc > 0) - FindExec(SetCommands, arg->argc, arg->argv, "set "); - else if (VarTerm) - fprintf(VarTerm, "Use `set ?' to get a arg->cmd or `set ? <var>' for" - " syntax help.\n"); - else - LogPrintf(LogWARN, "set command must have arguments\n"); - - return 0; -} - - -static int -AddCommand(struct cmdargs const *arg) -{ - struct in_addr dest, gateway, netmask; - int gw; - - if (arg->argc != 3 && arg->argc != 2) - return -1; - - if (arg->argc == 2) { - if (strcasecmp(arg->argv[0], "default")) - return -1; - else { - dest.s_addr = netmask.s_addr = INADDR_ANY; - gw = 1; - } - } else { - if (strcasecmp(arg->argv[0], "MYADDR") == 0) - dest = IpcpInfo.want_ipaddr; - else if (strcasecmp(arg->argv[0], "HISADDR") == 0) - dest = IpcpInfo.his_ipaddr; - else - dest = GetIpAddr(arg->argv[0]); - netmask = GetIpAddr(arg->argv[1]); - gw = 2; - } - if (strcasecmp(arg->argv[gw], "HISADDR") == 0) - gateway = IpcpInfo.his_ipaddr; - else if (strcasecmp(arg->argv[gw], "INTERFACE") == 0) - gateway.s_addr = INADDR_ANY; - else - gateway = GetIpAddr(arg->argv[gw]); - OsSetRoute(RTM_ADD, dest, gateway, netmask, arg->data ? 1 : 0); - return 0; -} - -static int -DeleteCommand(struct cmdargs const *arg) -{ - struct in_addr dest, none; - - if (arg->argc == 1) { - if(strcasecmp(arg->argv[0], "all") == 0) - DeleteIfRoutes(0); - else { - if (strcasecmp(arg->argv[0], "MYADDR") == 0) - dest = IpcpInfo.want_ipaddr; - else if (strcasecmp(arg->argv[0], "default") == 0) - dest.s_addr = INADDR_ANY; - else - dest = GetIpAddr(arg->argv[0]); - none.s_addr = INADDR_ANY; - OsSetRoute(RTM_DELETE, dest, none, none, arg->data ? 1 : 0); - } - } else - return -1; - - return 0; -} - -#ifndef NOALIAS -static struct cmdtab const AliasCommands[] = -{ - {"enable", NULL, AliasEnable, LOCAL_AUTH, - "enable IP aliasing", "alias enable [yes|no]"}, - {"port", NULL, AliasRedirectPort, LOCAL_AUTH, - "port redirection", "alias port [proto addr_local:port_local port_alias]"}, - {"addr", NULL, AliasRedirectAddr, LOCAL_AUTH, - "static address translation", "alias addr [addr_local addr_alias]"}, - {"deny_incoming", NULL, AliasOption, LOCAL_AUTH, - "stop incoming connections", "alias deny_incoming [yes|no]", - (const void *) PKT_ALIAS_DENY_INCOMING}, - {"log", NULL, AliasOption, LOCAL_AUTH, - "log aliasing link creation", "alias log [yes|no]", - (const void *) PKT_ALIAS_LOG}, - {"same_ports", NULL, AliasOption, LOCAL_AUTH, - "try to leave port numbers unchanged", "alias same_ports [yes|no]", - (const void *) PKT_ALIAS_SAME_PORTS}, - {"use_sockets", NULL, AliasOption, LOCAL_AUTH, - "allocate host sockets", "alias use_sockets [yes|no]", - (const void *) PKT_ALIAS_USE_SOCKETS}, - {"unregistered_only", NULL, AliasOption, LOCAL_AUTH, - "alias unregistered (private) IP address space only", - "alias unregistered_only [yes|no]", - (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, - {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Display this message", "alias help|? [command]", AliasCommands}, - {NULL, NULL, NULL}, -}; - - -static int -AliasCommand(struct cmdargs const *arg) -{ - if (arg->argc > 0) - FindExec(AliasCommands, arg->argc, arg->argv, "alias "); - else if (VarTerm) - fprintf(VarTerm, "Use `alias help' to get a arg->cmd or `alias help <option>'" - " for syntax help.\n"); - else - LogPrintf(LogWARN, "alias command must have arguments\n"); - - return 0; -} - -static int -AliasEnable(struct cmdargs const *arg) -{ - if (arg->argc == 1) { - if (strcasecmp(arg->argv[0], "yes") == 0) { - if (!(mode & MODE_ALIAS)) { - if (loadAliasHandlers(&VarAliasHandlers) == 0) { - mode |= MODE_ALIAS; - return 0; - } - LogPrintf(LogWARN, "Cannot load alias library\n"); - return 1; - } - return 0; - } else if (strcasecmp(arg->argv[0], "no") == 0) { - if (mode & MODE_ALIAS) { - unloadAliasHandlers(); - mode &= ~MODE_ALIAS; - } - return 0; - } - } - return -1; -} - - -static int -AliasOption(struct cmdargs const *arg) -{ - unsigned param = (unsigned)arg->data; - if (arg->argc == 1) { - if (strcasecmp(arg->argv[0], "yes") == 0) { - if (mode & MODE_ALIAS) { - VarPacketAliasSetMode(param, param); - return 0; - } - LogPrintf(LogWARN, "alias not enabled\n"); - } else if (strcmp(arg->argv[0], "no") == 0) { - if (mode & MODE_ALIAS) { - VarPacketAliasSetMode(0, param); - return 0; - } - LogPrintf(LogWARN, "alias not enabled\n"); - } - } - return -1; -} -#endif /* #ifndef NOALIAS */ - -static struct cmdtab const AllowCommands[] = { - {"users", "user", AllowUsers, LOCAL_AUTH, - "Allow users access to ppp", "allow users logname..."}, - {"modes", "mode", AllowModes, LOCAL_AUTH, - "Only allow certain ppp modes", "allow modes mode..."}, - {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Display this message", "allow help|? [command]", AllowCommands}, - {NULL, NULL, NULL}, -}; - -static int -AllowCommand(struct cmdargs const *arg) -{ - if (arg->argc > 0) - FindExec(AllowCommands, arg->argc, arg->argv, "allow "); - else if (VarTerm) - fprintf(VarTerm, "Use `allow ?' to get a arg->cmd or `allow ? <cmd>' for" - " syntax help.\n"); - else - LogPrintf(LogWARN, "allow command must have arguments\n"); - - return 0; -} diff --git a/usr.sbin/ppp/command.h b/usr.sbin/ppp/command.h deleted file mode 100644 index e74f7c48031..00000000000 --- a/usr.sbin/ppp/command.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: command.h,v 1.1 1997/11/23 20:27:33 brian Exp $ - * - * TODO: - */ - -struct cmdtab; - -struct cmdargs { - struct cmdtab const *cmd; - int argc; - char const *const *argv; - const void *data; -}; - -struct cmdtab { - const char *name; - const char *alias; - int (*func) (struct cmdargs const *); - u_char lauth; - const char *helpmes; - const char *syntax; - const void *args; -}; - -#define VAR_AUTHKEY 0 -#define VAR_DIAL 1 -#define VAR_LOGIN 2 -#define VAR_AUTHNAME 3 -#define VAR_DEVICE 4 -#define VAR_ACCMAP 5 -#define VAR_PHONE 6 -#define VAR_HANGUP 7 -#ifdef HAVE_DES -#define VAR_ENC 8 -#endif - -extern struct in_addr ifnetmask; -extern int aft_cmd; - -extern int SetVariable(struct cmdargs const *); -extern void Prompt(void); -extern int IsInteractive(int); -extern void InterpretCommand(char *, int, int *, char ***); -extern void RunCommand(int, char const *const *, const char *label); -extern void DecodeCommand(char *, int, const char *label); diff --git a/usr.sbin/ppp/deflate.c b/usr.sbin/ppp/deflate.c deleted file mode 100644 index 24f9ee1aeba..00000000000 --- a/usr.sbin/ppp/deflate.c +++ /dev/null @@ -1,618 +0,0 @@ -/*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: deflate.c,v 1.6 1998/03/13 01:25:55 brian Exp $ - */ - -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <stdlib.h> -#include <zlib.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "loadalias.h" -#include "vars.h" -#include "hdlc.h" -#include "lcp.h" -#include "ccp.h" -#include "lcpproto.h" -#include "timer.h" -#include "fsm.h" -#include "deflate.h" - -/* Our state */ -struct deflate_state { - u_short seqno; - int uncomp_rec; - z_stream cx; -}; - -static int iWindowSize = 15; -static int oWindowSize = 15; -static struct deflate_state InputState, OutputState; -static char garbage[10]; -static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; - -#define DEFLATE_CHUNK_LEN 1024 /* Allocate mbufs this size */ - -static void -DeflateResetOutput(void) -{ - OutputState.seqno = 0; - OutputState.uncomp_rec = 0; - deflateReset(&OutputState.cx); - LogPrintf(LogCCP, "Deflate: Output channel reset\n"); -} - -static int -DeflateOutput(int pri, u_short proto, struct mbuf *mp) -{ - u_char *wp, *rp; - int olen, ilen, len, res, flush; - struct mbuf *mo_head, *mo, *mi_head, *mi; - - ilen = plength(mp); - LogPrintf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", proto, ilen); - LogDumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp); - - /* Stuff the protocol in front of the input */ - mi_head = mi = mballoc(2, MB_HDLCOUT); - mi->next = mp; - rp = MBUF_CTOP(mi); - if (proto < 0x100) { /* Compress the protocol */ - rp[0] = proto & 0377; - mi->cnt = 1; - } else { /* Don't compress the protocol */ - rp[0] = proto >> 8; - rp[1] = proto & 0377; - mi->cnt = 2; - } - - /* Allocate the initial output mbuf */ - mo_head = mo = mballoc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); - mo->cnt = 2; - wp = MBUF_CTOP(mo); - *wp++ = OutputState.seqno >> 8; - *wp++ = OutputState.seqno & 0377; - LogPrintf(LogDEBUG, "DeflateOutput: Seq %d\n", OutputState.seqno); - OutputState.seqno++; - - /* Set up the deflation context */ - OutputState.cx.next_out = wp; - OutputState.cx.avail_out = DEFLATE_CHUNK_LEN - 2; - OutputState.cx.next_in = MBUF_CTOP(mi); - OutputState.cx.avail_in = mi->cnt; - flush = Z_NO_FLUSH; - - olen = 0; - while (1) { - if ((res = deflate(&OutputState.cx, flush)) != Z_OK) { - if (res == Z_STREAM_END) - break; /* Done */ - LogPrintf(LogERROR, "DeflateOutput: deflate returned %d (%s)\n", - res, OutputState.cx.msg ? OutputState.cx.msg : ""); - pfree(mo_head); - mbfree(mi_head); - OutputState.seqno--; - return 1; /* packet dropped */ - } - - if (flush == Z_SYNC_FLUSH && OutputState.cx.avail_out != 0) - break; - - if (OutputState.cx.avail_in == 0 && mi->next != NULL) { - mi = mi->next; - OutputState.cx.next_in = MBUF_CTOP(mi); - OutputState.cx.avail_in = mi->cnt; - if (mi->next == NULL) - flush = Z_SYNC_FLUSH; - } - - if (OutputState.cx.avail_out == 0) { - mo->next = mballoc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); - olen += (mo->cnt = DEFLATE_CHUNK_LEN); - mo = mo->next; - mo->cnt = 0; - OutputState.cx.next_out = MBUF_CTOP(mo); - OutputState.cx.avail_out = DEFLATE_CHUNK_LEN; - } - } - - olen += (mo->cnt = DEFLATE_CHUNK_LEN - OutputState.cx.avail_out); - olen -= 4; /* exclude the trailing EMPTY_BLOCK */ - - /* - * If the output packet (including seqno and excluding the EMPTY_BLOCK) - * got bigger, send the original - returning 0 to HdlcOutput() will - * continue to send ``mp''. - */ - if (olen >= ilen) { - pfree(mo_head); - mbfree(mi_head); - LogPrintf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n", - ilen, olen, proto); - CcpInfo.uncompout += ilen; - CcpInfo.compout += ilen; /* We measure this stuff too */ - return 0; - } - - pfree(mi_head); - - /* - * Lose the last four bytes of our output. - * XXX: We should probably assert that these are the same as the - * contents of EMPTY_BLOCK. - */ - for (mo = mo_head, len = mo->cnt; len < olen; mo = mo->next, len += mo->cnt) - ; - mo->cnt -= len - olen; - if (mo->next != NULL) { - pfree(mo->next); - mo->next = NULL; - } - - CcpInfo.uncompout += ilen; - CcpInfo.compout += olen; - - LogPrintf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n", - ilen, olen, proto); - - HdlcOutput(PRI_NORMAL, PROTO_COMPD, mo_head); - return 1; -} - -static void -DeflateResetInput(void) -{ - InputState.seqno = 0; - InputState.uncomp_rec = 0; - inflateReset(&InputState.cx); - LogPrintf(LogCCP, "Deflate: Input channel reset\n"); -} - -static struct mbuf * -DeflateInput(u_short *proto, struct mbuf *mi) -{ - struct mbuf *mo, *mo_head, *mi_head; - u_char *wp; - int ilen, olen; - int seq, flush, res, first; - u_char hdr[2]; - - LogDumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi); - mi_head = mi = mbread(mi, hdr, 2); - ilen = 2; - - /* Check the sequence number. */ - seq = (hdr[0] << 8) + hdr[1]; - LogPrintf(LogDEBUG, "DeflateInput: Seq %d\n", seq); - if (seq != InputState.seqno) { - if (seq <= InputState.uncomp_rec) - /* - * So the peer's started at zero again - fine ! If we're wrong, - * inflate() will fail. This is better than getting into a loop - * trying to get a ResetReq to a busy sender. - */ - InputState.seqno = seq; - else { - LogPrintf(LogERROR, "DeflateInput: Seq error: Got %d, expected %d\n", - seq, InputState.seqno); - pfree(mi_head); - CcpSendResetReq(&CcpFsm); - return NULL; - } - } - InputState.seqno++; - InputState.uncomp_rec = 0; - - /* Allocate an output mbuf */ - mo_head = mo = mballoc(DEFLATE_CHUNK_LEN, MB_IPIN); - - /* Our proto starts with 0 if it's compressed */ - wp = MBUF_CTOP(mo); - wp[0] = '\0'; - - /* - * We set avail_out to 1 initially so we can look at the first - * byte of the output and decide whether we have a compressed - * proto field. - */ - InputState.cx.next_in = MBUF_CTOP(mi); - InputState.cx.avail_in = mi->cnt; - InputState.cx.next_out = wp + 1; - InputState.cx.avail_out = 1; - ilen += mi->cnt; - - flush = mi->next ? Z_NO_FLUSH : Z_SYNC_FLUSH; - first = 1; - olen = 0; - - while (1) { - if ((res = inflate(&InputState.cx, flush)) != Z_OK) { - if (res == Z_STREAM_END) - break; /* Done */ - LogPrintf(LogERROR, "DeflateInput: inflate returned %d (%s)\n", - res, InputState.cx.msg ? InputState.cx.msg : ""); - pfree(mo_head); - pfree(mi); - CcpSendResetReq(&CcpFsm); - return NULL; - } - - if (flush == Z_SYNC_FLUSH && InputState.cx.avail_out != 0) - break; - - if (InputState.cx.avail_in == 0 && mi && (mi = mbfree(mi)) != NULL) { - /* underflow */ - InputState.cx.next_in = MBUF_CTOP(mi); - ilen += (InputState.cx.avail_in = mi->cnt); - if (mi->next == NULL) - flush = Z_SYNC_FLUSH; - } - - if (InputState.cx.avail_out == 0) { - /* overflow */ - if (first) { - if (!(wp[1] & 1)) { - /* 2 byte proto, shuffle it back in output */ - wp[0] = wp[1]; - InputState.cx.next_out--; - InputState.cx.avail_out = DEFLATE_CHUNK_LEN-1; - } else - InputState.cx.avail_out = DEFLATE_CHUNK_LEN-2; - first = 0; - } else { - olen += (mo->cnt = DEFLATE_CHUNK_LEN); - mo->next = mballoc(DEFLATE_CHUNK_LEN, MB_IPIN); - mo = mo->next; - InputState.cx.next_out = MBUF_CTOP(mo); - InputState.cx.avail_out = DEFLATE_CHUNK_LEN; - } - } - } - - if (mi != NULL) - pfree(mi); - - if (first) { - LogPrintf(LogERROR, "DeflateInput: Length error\n"); - pfree(mo_head); - CcpSendResetReq(&CcpFsm); - return NULL; - } - - olen += (mo->cnt = DEFLATE_CHUNK_LEN - InputState.cx.avail_out); - - *proto = ((u_short)wp[0] << 8) | wp[1]; - mo_head->offset += 2; - mo_head->cnt -= 2; - olen -= 2; - - CcpInfo.compin += ilen; - CcpInfo.uncompin += olen; - - LogPrintf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n", - ilen, olen, *proto); - - /* - * Simulate an EMPTY_BLOCK so that our dictionary stays in sync. - * The peer will have silently removed this! - */ - InputState.cx.next_out = garbage; - InputState.cx.avail_out = sizeof garbage; - InputState.cx.next_in = EMPTY_BLOCK; - InputState.cx.avail_in = sizeof EMPTY_BLOCK; - inflate(&InputState.cx, Z_SYNC_FLUSH); - - return mo_head; -} - -static void -DeflateDictSetup(u_short proto, struct mbuf *mi) -{ - int res, flush, expect_error; - u_char *rp; - struct mbuf *mi_head; - short len; - - LogPrintf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", InputState.seqno); - - /* - * Stuff an ``uncompressed data'' block header followed by the - * protocol in front of the input - */ - mi_head = mballoc(7, MB_HDLCOUT); - mi_head->next = mi; - len = plength(mi); - mi = mi_head; - rp = MBUF_CTOP(mi); - if (proto < 0x100) { /* Compress the protocol */ - rp[5] = proto & 0377; - mi->cnt = 6; - len++; - } else { /* Don't compress the protocol */ - rp[5] = proto >> 8; - rp[6] = proto & 0377; - mi->cnt = 7; - len += 2; - } - rp[0] = 0x80; /* BITS: 100xxxxx */ - rp[1] = len & 0377; /* The length */ - rp[2] = len >> 8; - rp[3] = (~len) & 0377; /* One's compliment of the length */ - rp[4] = (~len) >> 8; - - InputState.cx.next_in = rp; - InputState.cx.avail_in = mi->cnt; - InputState.cx.next_out = garbage; - InputState.cx.avail_out = sizeof garbage; - flush = Z_NO_FLUSH; - expect_error = 0; - - while (1) { - if ((res = inflate(&InputState.cx, flush)) != Z_OK) { - if (res == Z_STREAM_END) - break; /* Done */ - if (expect_error && res == Z_BUF_ERROR) - break; - LogPrintf(LogERROR, "DeflateDictSetup: inflate returned %d (%s)\n", - res, InputState.cx.msg ? InputState.cx.msg : ""); - LogPrintf(LogERROR, "DeflateDictSetup: avail_in %d, avail_out %d\n", - InputState.cx.avail_in, InputState.cx.avail_out); - CcpSendResetReq(&CcpFsm); - mbfree(mi_head); /* lose our allocated ``head'' buf */ - return; - } - - if (flush == Z_SYNC_FLUSH && InputState.cx.avail_out != 0) - break; - - if (InputState.cx.avail_in == 0 && mi && (mi = mi->next) != NULL) { - /* underflow */ - InputState.cx.next_in = MBUF_CTOP(mi); - InputState.cx.avail_in = mi->cnt; - if (mi->next == NULL) - flush = Z_SYNC_FLUSH; - } - - if (InputState.cx.avail_out == 0) { - if (InputState.cx.avail_in == 0) - /* - * This seems to be a bug in libz ! If inflate() finished - * with 0 avail_in and 0 avail_out *and* this is the end of - * our input *and* inflate() *has* actually written all the - * output it's going to, it *doesn't* return Z_STREAM_END ! - * When we subsequently call it with no more input, it gives - * us Z_BUF_ERROR :-( It seems pretty safe to ignore this - * error (the dictionary seems to stay in sync). In the worst - * case, we'll drop the next compressed packet and do a - * CcpReset() then. - */ - expect_error = 1; - /* overflow */ - InputState.cx.next_out = garbage; - InputState.cx.avail_out = sizeof garbage; - } - } - - CcpInfo.compin += len; - CcpInfo.uncompin += len; - - InputState.seqno++; - InputState.uncomp_rec++; - mbfree(mi_head); /* lose our allocated ``head'' buf */ -} - -static const char * -DeflateDispOpts(struct lcp_opt *o) -{ - static char disp[7]; - - sprintf(disp, "win %d", (o->data[0]>>4) + 8); - return disp; -} - -static void -DeflateGetInputOpts(struct lcp_opt *o) -{ - o->id = TY_DEFLATE; - o->len = 4; - o->data[0] = ((iWindowSize-8)<<4)+8; - o->data[1] = '\0'; -} - -static void -DeflateGetOutputOpts(struct lcp_opt *o) -{ - o->id = TY_DEFLATE; - o->len = 4; - o->data[0] = ((oWindowSize-8)<<4)+8; - o->data[1] = '\0'; -} - -static void -PppdDeflateGetInputOpts(struct lcp_opt *o) -{ - o->id = TY_PPPD_DEFLATE; - o->len = 4; - o->data[0] = ((iWindowSize-8)<<4)+8; - o->data[1] = '\0'; -} - -static void -PppdDeflateGetOutputOpts(struct lcp_opt *o) -{ - o->id = TY_PPPD_DEFLATE; - o->len = 4; - o->data[0] = ((oWindowSize-8)<<4)+8; - o->data[1] = '\0'; -} - -static int -DeflateSetOpts(struct lcp_opt *o, int *sz) -{ - if (o->len != 4 || (o->data[0]&15) != 8 || o->data[1] != '\0') { - return MODE_REJ; - } - *sz = (o->data[0] >> 4) + 8; - if (*sz > 15) { - *sz = 15; - return MODE_NAK; - } - - return MODE_ACK; -} - -static int -DeflateSetInputOpts(struct lcp_opt *o) -{ - int res; - res = DeflateSetOpts(o, &iWindowSize); - if (res != MODE_ACK) - DeflateGetInputOpts(o); - return res; -} - -static int -DeflateSetOutputOpts(struct lcp_opt *o) -{ - int res; - res = DeflateSetOpts(o, &oWindowSize); - if (res != MODE_ACK) - DeflateGetOutputOpts(o); - return res; -} - -static int -PppdDeflateSetInputOpts(struct lcp_opt *o) -{ - int res; - res = DeflateSetOpts(o, &iWindowSize); - if (res != MODE_ACK) - PppdDeflateGetInputOpts(o); - return res; -} - -static int -PppdDeflateSetOutputOpts(struct lcp_opt *o) -{ - int res; - res = DeflateSetOpts(o, &oWindowSize); - if (res != MODE_ACK) - PppdDeflateGetOutputOpts(o); - return res; -} - -static int -DeflateInitInput(void) -{ - InputState.cx.zalloc = NULL; - InputState.cx.opaque = NULL; - InputState.cx.zfree = NULL; - InputState.cx.next_out = NULL; - if (inflateInit2(&InputState.cx, -iWindowSize) != Z_OK) - return 0; - DeflateResetInput(); - return 1; -} - -static int -DeflateInitOutput(void) -{ - OutputState.cx.zalloc = NULL; - OutputState.cx.opaque = NULL; - OutputState.cx.zfree = NULL; - OutputState.cx.next_in = NULL; - if (deflateInit2(&OutputState.cx, Z_DEFAULT_COMPRESSION, 8, - -oWindowSize, 8, Z_DEFAULT_STRATEGY) != Z_OK) - return 0; - DeflateResetOutput(); - return 1; -} - -static void -DeflateTermInput(void) -{ - iWindowSize = 15; - inflateEnd(&InputState.cx); -} - -static void -DeflateTermOutput(void) -{ - oWindowSize = 15; - deflateEnd(&OutputState.cx); -} - -const struct ccp_algorithm PppdDeflateAlgorithm = { - TY_PPPD_DEFLATE, /* pppd (wrongly) expects this ``type'' field */ - ConfPppdDeflate, - DeflateDispOpts, - { - PppdDeflateGetInputOpts, - PppdDeflateSetInputOpts, - DeflateInitInput, - DeflateTermInput, - DeflateResetInput, - DeflateInput, - DeflateDictSetup - }, - { - PppdDeflateGetOutputOpts, - PppdDeflateSetOutputOpts, - DeflateInitOutput, - DeflateTermOutput, - DeflateResetOutput, - DeflateOutput - }, -}; - -const struct ccp_algorithm DeflateAlgorithm = { - TY_DEFLATE, /* rfc 1979 */ - ConfDeflate, - DeflateDispOpts, - { - DeflateGetInputOpts, - DeflateSetInputOpts, - DeflateInitInput, - DeflateTermInput, - DeflateResetInput, - DeflateInput, - DeflateDictSetup - }, - { - DeflateGetOutputOpts, - DeflateSetOutputOpts, - DeflateInitOutput, - DeflateTermOutput, - DeflateResetOutput, - DeflateOutput - }, -}; diff --git a/usr.sbin/ppp/filter.c b/usr.sbin/ppp/filter.c deleted file mode 100644 index 697c9a8ec27..00000000000 --- a/usr.sbin/ppp/filter.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * PPP Filter command Interface - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: filter.c,v 1.5 1998/06/27 12:06:41 brian Exp $ - * - * TODO: Shoud send ICMP error message when we discard packets. - */ - -#include <sys/param.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "loadalias.h" -#include "defs.h" -#include "vars.h" -#include "ipcp.h" -#include "filter.h" - -struct filterent ifilters[MAXFILTERS]; /* incoming packet filter */ -struct filterent ofilters[MAXFILTERS]; /* outgoing packet filter */ -struct filterent dfilters[MAXFILTERS]; /* dial-out packet filter */ -struct filterent afilters[MAXFILTERS]; /* keep-alive packet filter */ - -static struct filterent filterdata; - -static u_int32_t netmasks[33] = { - 0x00000000, - 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, - 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, - 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, - 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, - 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, - 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, - 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, - 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, -}; - -int -ParseAddr(int argc, - char const *const *argv, - struct in_addr * paddr, - struct in_addr * pmask, - int *pwidth) -{ - int bits, len; - char *wp; - const char *cp; - - if (argc < 1) { - LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n"); - return (0); - } - - if (pmask) - pmask->s_addr = 0xffffffff; /* Assume 255.255.255.255 as default */ - - cp = pmask || pwidth ? strchr(*argv, '/') : NULL; - len = cp ? cp - *argv : strlen(*argv); - - if (strncasecmp(*argv, "HISADDR", len) == 0) - *paddr = IpcpInfo.his_ipaddr; - else if (strncasecmp(*argv, "MYADDR", len) == 0) - *paddr = IpcpInfo.want_ipaddr; - else if (len > 15) - LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", *argv); - else { - char s[16]; - strncpy(s, *argv, len); - s[len] = '\0'; - if (inet_aton(s, paddr) == 0) { - LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", s); - return (0); - } - } - if (cp && *++cp) { - bits = strtol(cp, &wp, 0); - if (cp == wp || bits < 0 || bits > 32) { - LogPrintf(LogWARN, "ParseAddr: bad mask width.\n"); - return (0); - } - } else { - /* if width is not given, assume whole 32 bits are meaningfull */ - bits = 32; - } - - if (pwidth) - *pwidth = bits; - - if (pmask) - pmask->s_addr = htonl(netmasks[bits]); - - return (1); -} - -static int -ParseProto(int argc, char const *const *argv) -{ - int proto; - - if (argc < 1) - return (P_NONE); - - if (!strcmp(*argv, "tcp")) - proto = P_TCP; - else if (!strcmp(*argv, "udp")) - proto = P_UDP; - else if (!strcmp(*argv, "icmp")) - proto = P_ICMP; - else - proto = P_NONE; - return (proto); -} - -static int -ParsePort(const char *service, int proto) -{ - const char *protocol_name; - char *cp; - struct servent *servent; - int port; - - switch (proto) { - case P_UDP: - protocol_name = "udp"; - break; - case P_TCP: - protocol_name = "tcp"; - break; - default: - protocol_name = 0; - } - - servent = getservbyname(service, protocol_name); - if (servent != 0) - return (ntohs(servent->s_port)); - - port = strtol(service, &cp, 0); - if (cp == service) { - LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n", - service); - return (0); - } - return (port); -} - -/* - * ICMP Syntax: src eq icmp_message_type - */ -static int -ParseIcmp(int argc, char const *const *argv) -{ - int type; - char *cp; - - switch (argc) { - case 0: - /* permit/deny all ICMP types */ - filterdata.opt.srcop = OP_NONE; - break; - default: - LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); - return (0); - case 3: - if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { - type = strtol(argv[2], &cp, 0); - if (cp == argv[2]) { - LogPrintf(LogWARN, "ParseIcmp: type is expected.\n"); - return (0); - } - filterdata.opt.srcop = OP_EQ; - filterdata.opt.srcport = type; - } - break; - } - return (1); -} - -static int -ParseOp(const char *cp) -{ - int op = OP_NONE; - - if (!strcmp(cp, "eq")) - op = OP_EQ; - else if (!strcmp(cp, "gt")) - op = OP_GT; - else if (!strcmp(cp, "lt")) - op = OP_LT; - return (op); -} - -/* - * UDP Syntax: [src op port] [dst op port] - */ -static int -ParseUdpOrTcp(int argc, char const *const *argv, int proto) -{ - filterdata.opt.srcop = filterdata.opt.dstop = OP_NONE; - filterdata.opt.estab = 0; - - if (argc == 0) { - /* permit/deny all tcp traffic */ - return (1); - } - - if (argc >= 3 && !strcmp(*argv, "src")) { - filterdata.opt.srcop = ParseOp(argv[1]); - if (filterdata.opt.srcop == OP_NONE) { - LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n"); - return (0); - } - filterdata.opt.srcport = ParsePort(argv[2], proto); - if (filterdata.opt.srcport == 0) - return (0); - argc -= 3; - argv += 3; - if (argc == 0) - return (1); - } - if (argc >= 3 && !strcmp(argv[0], "dst")) { - filterdata.opt.dstop = ParseOp(argv[1]); - if (filterdata.opt.dstop == OP_NONE) { - LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n"); - return (0); - } - filterdata.opt.dstport = ParsePort(argv[2], proto); - if (filterdata.opt.dstport == 0) - return (0); - argc -= 3; - argv += 3; - if (argc == 0) - return (1); - } - if (argc == 1 && proto == P_TCP) { - if (!strcmp(*argv, "estab")) { - filterdata.opt.estab = 1; - return (1); - } - LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv); - return (0); - } - if (argc > 0) - LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); - return (0); -} - -static const char *opname[] = {"none", "eq", "gt", NULL, "lt"}; - -static int -Parse(int argc, char const *const *argv, struct filterent * ofp) -{ - int action, proto; - int val; - char *wp; - struct filterent *fp = &filterdata; - - val = strtol(*argv, &wp, 0); - if (*argv == wp || val > MAXFILTERS) { - LogPrintf(LogWARN, "Parse: invalid filter number.\n"); - return (0); - } - if (val < 0) { - for (val = 0; val < MAXFILTERS; val++) { - ofp->action = A_NONE; - ofp++; - } - LogPrintf(LogWARN, "Parse: filter cleared.\n"); - return (1); - } - ofp += val; - - if (--argc == 0) { - LogPrintf(LogWARN, "Parse: missing action.\n"); - return (0); - } - argv++; - - proto = P_NONE; - memset(&filterdata, '\0', sizeof filterdata); - - if (!strcmp(*argv, "permit")) { - action = A_PERMIT; - } else if (!strcmp(*argv, "deny")) { - action = A_DENY; - } else if (!strcmp(*argv, "clear")) { - ofp->action = A_NONE; - return (1); - } else { - LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv); - return (0); - } - fp->action = action; - - argc--; - argv++; - - if (fp->action == A_DENY) { - if (!strcmp(*argv, "host")) { - fp->action |= A_UHOST; - argc--; - argv++; - } else if (!strcmp(*argv, "port")) { - fp->action |= A_UPORT; - argc--; - argv++; - } - } - proto = ParseProto(argc, argv); - if (proto == P_NONE) { - if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) { - argc--; - argv++; - proto = ParseProto(argc, argv); - if (proto == P_NONE) { - if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) { - argc--; - argv++; - } - proto = ParseProto(argc, argv); - if (proto != P_NONE) { - argc--; - argv++; - } - } else { - argc--; - argv++; - } - } else { - LogPrintf(LogWARN, "Parse: Address/protocol expected.\n"); - return (0); - } - } else { - argc--; - argv++; - } - - val = 1; - fp->proto = proto; - - switch (proto) { - case P_TCP: - val = ParseUdpOrTcp(argc, argv, P_TCP); - break; - case P_UDP: - val = ParseUdpOrTcp(argc, argv, P_UDP); - break; - case P_ICMP: - val = ParseIcmp(argc, argv); - break; - } - - LogPrintf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(fp->saddr)); - LogPrintf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(fp->smask)); - LogPrintf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(fp->daddr)); - LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask)); - LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto); - - LogPrintf(LogDEBUG, "Parse: src: %s (%d)\n", opname[fp->opt.srcop], - fp->opt.srcport); - LogPrintf(LogDEBUG, "Parse: dst: %s (%d)\n", opname[fp->opt.dstop], - fp->opt.dstport); - LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab); - - if (val) - *ofp = *fp; - return (val); -} - -int -SetIfilter(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - Parse(arg->argc, arg->argv, ifilters); - return 0; - } - return -1; -} - -int -SetOfilter(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - (void) Parse(arg->argc, arg->argv, ofilters); - return 0; - } - return -1; -} - -int -SetDfilter(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - (void) Parse(arg->argc, arg->argv, dfilters); - return 0; - } - return -1; -} - -int -SetAfilter(struct cmdargs const *arg) -{ - if (arg->argc > 0) { - (void) Parse(arg->argc, arg->argv, afilters); - return 0; - } - return -1; -} - -static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; -static const char *actname[] = { "none ", "permit ", "deny " }; - -static void -ShowFilter(struct filterent * fp) -{ - int n; - - if (!VarTerm) - return; - - for (n = 0; n < MAXFILTERS; n++, fp++) { - if (fp->action != A_NONE) { - fprintf(VarTerm, "%2d %s", n, actname[fp->action & (A_PERMIT|A_DENY)]); - if (fp->action & A_UHOST) - fprintf(VarTerm, "host "); - else if (fp->action & A_UPORT) - fprintf(VarTerm, "port "); - else - fprintf(VarTerm, " "); - fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth); - fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); - if (fp->proto) { - fprintf(VarTerm, "%s", protoname[fp->proto]); - - if (fp->opt.srcop) - fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop], - fp->opt.srcport); - if (fp->opt.dstop) - fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop], - fp->opt.dstport); - if (fp->opt.estab) - fprintf(VarTerm, " estab"); - - } - fprintf(VarTerm, "\n"); - } - } -} - -int -ShowIfilter(struct cmdargs const *arg) -{ - ShowFilter(ifilters); - return 0; -} - -int -ShowOfilter(struct cmdargs const *arg) -{ - ShowFilter(ofilters); - return 0; -} - -int -ShowDfilter(struct cmdargs const *arg) -{ - ShowFilter(dfilters); - return 0; -} - -int -ShowAfilter(struct cmdargs const *arg) -{ - ShowFilter(afilters); - return 0; -} diff --git a/usr.sbin/ppp/fsm.c b/usr.sbin/ppp/fsm.c deleted file mode 100644 index 079fd718c56..00000000000 --- a/usr.sbin/ppp/fsm.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * PPP Finite State Machine for LCP/IPCP - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: fsm.c,v 1.7 1998/06/28 09:41:38 brian Exp $ - * - * TODO: - * o Refer loglevel for log output - * o Better option log display - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <string.h> -#include <termios.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "hdlc.h" -#include "lqr.h" -#include "lcpproto.h" -#include "lcp.h" -#include "ccp.h" -#include "modem.h" -#include "loadalias.h" -#include "vars.h" - -u_char AckBuff[200]; -u_char NakBuff[200]; -u_char RejBuff[100]; -u_char ReqBuff[200]; -u_char *ackp = NULL; -u_char *nakp = NULL; -u_char *rejp = NULL; - -static void FsmSendConfigReq(struct fsm *); -static void FsmSendTerminateReq(struct fsm *); -static void FsmInitRestartCounter(struct fsm *); - -char const *StateNames[] = { - "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", - "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", -}; - -static void -StoppedTimeout(void *v) -{ - struct fsm *fp = (struct fsm *)v; - - LogPrintf(fp->LogLevel, "Stopped timer expired\n"); - if (fp->OpenTimer.state == TIMER_RUNNING) { - LogPrintf(LogWARN, "%s: aborting open delay due to stopped timer\n", - fp->name); - StopTimer(&fp->OpenTimer); - } - if (modem != -1) - DownConnection(); - else - FsmDown(fp); -} - -void -FsmInit(struct fsm * fp) -{ - LogPrintf(LogDEBUG, "FsmInit\n"); - fp->state = ST_INITIAL; - fp->reqid = 1; - fp->restart = 1; - fp->maxconfig = 3; -} - -static void -NewState(struct fsm * fp, int new) -{ - LogPrintf(fp->LogLevel, "State change %s --> %s\n", - StateNames[fp->state], StateNames[new]); - if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) - StopTimer(&fp->StoppedTimer); - fp->state = new; - if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { - StopTimer(&fp->FsmTimer); - if (new == ST_STOPPED && fp->StoppedTimer.load) { - fp->StoppedTimer.state = TIMER_STOPPED; - fp->StoppedTimer.func = StoppedTimeout; - fp->StoppedTimer.arg = (void *) fp; - StartTimer(&fp->StoppedTimer); - } - } -} - -void -FsmOutput(struct fsm * fp, u_int code, u_int id, u_char * ptr, int count) -{ - int plen; - struct fsmheader lh; - struct mbuf *bp; - - plen = sizeof(struct fsmheader) + count; - lh.code = code; - lh.id = id; - lh.length = htons(plen); - bp = mballoc(plen, MB_FSM); - memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); - if (count) - memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); - LogDumpBp(LogDEBUG, "FsmOutput", bp); - HdlcOutput(PRI_LINK, fp->proto, bp); -} - -static void -FsmOpenNow(void *v) -{ - struct fsm *fp = (struct fsm *)v; - - StopTimer(&fp->OpenTimer); - if (fp->state <= ST_STOPPED) { - FsmInitRestartCounter(fp); - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - } -} - -void -FsmOpen(struct fsm * fp) -{ - switch (fp->state) { - case ST_INITIAL: - (fp->LayerStart) (fp); - NewState(fp, ST_STARTING); - break; - case ST_STARTING: - break; - case ST_CLOSED: - if (fp->open_mode == OPEN_PASSIVE) { - NewState(fp, ST_STOPPED); - } else if (fp->open_mode > 0) { - if (fp->open_mode > 1) - LogPrintf(LogPHASE, "Entering STOPPED state for %d seconds\n", - fp->open_mode); - NewState(fp, ST_STOPPED); - fp->OpenTimer.state = TIMER_STOPPED; - fp->OpenTimer.load = fp->open_mode * SECTICKS; - fp->OpenTimer.func = FsmOpenNow; - fp->OpenTimer.arg = (void *)fp; - StartTimer(&fp->OpenTimer); - } else - FsmOpenNow(fp); - break; - case ST_STOPPED: /* XXX: restart option */ - case ST_REQSENT: - case ST_ACKRCVD: - case ST_ACKSENT: - case ST_OPENED: /* XXX: restart option */ - break; - case ST_CLOSING: /* XXX: restart option */ - case ST_STOPPING: /* XXX: restart option */ - NewState(fp, ST_STOPPING); - break; - } -} - -void -FsmUp(struct fsm * fp) -{ - switch (fp->state) { - case ST_INITIAL: - NewState(fp, ST_CLOSED); - break; - case ST_STARTING: - FsmInitRestartCounter(fp); - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - default: - LogPrintf(fp->LogLevel, "Oops, Up at %s\n", StateNames[fp->state]); - break; - } -} - -void -FsmDown(struct fsm * fp) -{ - switch (fp->state) { - case ST_CLOSED: - case ST_CLOSING: - NewState(fp, ST_INITIAL); - break; - case ST_STOPPED: - (fp->LayerStart) (fp); - /* Fall into.. */ - case ST_STOPPING: - case ST_REQSENT: - case ST_ACKRCVD: - case ST_ACKSENT: - NewState(fp, ST_STARTING); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - NewState(fp, ST_STARTING); - break; - } -} - -void -FsmClose(struct fsm * fp) -{ - switch (fp->state) { - case ST_STARTING: - NewState(fp, ST_INITIAL); - break; - case ST_STOPPED: - NewState(fp, ST_CLOSED); - break; - case ST_STOPPING: - NewState(fp, ST_CLOSING); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - /* Fall down */ - case ST_REQSENT: - case ST_ACKRCVD: - case ST_ACKSENT: - FsmInitRestartCounter(fp); - FsmSendTerminateReq(fp); - NewState(fp, ST_CLOSING); - break; - } -} - -/* - * Send functions - */ -static void -FsmSendConfigReq(struct fsm * fp) -{ - if (--fp->maxconfig > 0) { - (fp->SendConfigReq) (fp); - StartTimer(&fp->FsmTimer); /* Start restart timer */ - fp->restart--; /* Decrement restart counter */ - } else { - FsmClose(fp); - } -} - -static void -FsmSendTerminateReq(struct fsm * fp) -{ - LogPrintf(fp->LogLevel, "SendTerminateReq.\n"); - FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0); - (fp->SendTerminateReq) (fp); - StartTimer(&fp->FsmTimer); /* Start restart timer */ - fp->restart--; /* Decrement restart counter */ -} - -static void -FsmSendConfigAck(struct fsm * fp, - struct fsmheader * lhp, - u_char * option, - int count) -{ - LogPrintf(fp->LogLevel, "SendConfigAck(%s)\n", StateNames[fp->state]); - (fp->DecodeConfig) (option, count, MODE_NOP); - FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count); -} - -static void -FsmSendConfigRej(struct fsm * fp, - struct fsmheader * lhp, - u_char * option, - int count) -{ - LogPrintf(fp->LogLevel, "SendConfigRej(%s)\n", StateNames[fp->state]); - (fp->DecodeConfig) (option, count, MODE_NOP); - FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count); -} - -static void -FsmSendConfigNak(struct fsm * fp, - struct fsmheader * lhp, - u_char * option, - int count) -{ - LogPrintf(fp->LogLevel, "SendConfigNak(%s)\n", StateNames[fp->state]); - (fp->DecodeConfig) (option, count, MODE_NOP); - FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count); -} - -/* - * Timeout actions - */ -static void -FsmTimeout(void *v) -{ - struct fsm *fp = (struct fsm *)v; - - if (fp->restart) { - switch (fp->state) { - case ST_CLOSING: - case ST_STOPPING: - FsmSendTerminateReq(fp); - break; - case ST_REQSENT: - case ST_ACKSENT: - FsmSendConfigReq(fp); - break; - case ST_ACKRCVD: - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - } - StartTimer(&fp->FsmTimer); - } else { - switch (fp->state) { - case ST_CLOSING: - NewState(fp, ST_CLOSED); - (fp->LayerFinish) (fp); - break; - case ST_STOPPING: - NewState(fp, ST_STOPPED); - (fp->LayerFinish) (fp); - break; - case ST_REQSENT: /* XXX: 3p */ - case ST_ACKSENT: - case ST_ACKRCVD: - NewState(fp, ST_STOPPED); - (fp->LayerFinish) (fp); - break; - } - } -} - -static void -FsmInitRestartCounter(struct fsm * fp) -{ - StopTimer(&fp->FsmTimer); - fp->FsmTimer.state = TIMER_STOPPED; - fp->FsmTimer.func = FsmTimeout; - fp->FsmTimer.arg = (void *) fp; - (fp->InitRestartCounter) (fp); -} - -/* - * Actions when receive packets - */ -static void -FsmRecvConfigReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RCR */ -{ - int plen, flen; - int ackaction = 0; - - plen = plength(bp); - flen = ntohs(lhp->length) - sizeof *lhp; - if (plen < flen) { - LogPrintf(LogERROR, "FsmRecvConfigReq: plen (%d) < flen (%d)\n", - plen, flen); - pfree(bp); - return; - } - - /* - * Check and process easy case - */ - switch (fp->state) { - case ST_INITIAL: - case ST_STARTING: - LogPrintf(fp->LogLevel, "Oops, RCR in %s.\n", StateNames[fp->state]); - pfree(bp); - return; - case ST_CLOSED: - (fp->SendTerminateAck) (fp); - pfree(bp); - return; - case ST_CLOSING: - LogPrintf(fp->LogLevel, "Error: Got ConfigReq while state = %d\n", - fp->state); - case ST_STOPPING: - pfree(bp); - return; - } - - (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REQ); - - if (nakp == NakBuff && rejp == RejBuff) - ackaction = 1; - - switch (fp->state) { - case ST_OPENED: - (fp->LayerDown) (fp); - FsmSendConfigReq(fp); - break; - case ST_STOPPED: - FsmInitRestartCounter(fp); - FsmSendConfigReq(fp); - break; - } - - if (rejp != RejBuff) - FsmSendConfigRej(fp, lhp, RejBuff, rejp - RejBuff); - if (nakp != NakBuff) - FsmSendConfigNak(fp, lhp, NakBuff, nakp - NakBuff); - if (ackaction) - FsmSendConfigAck(fp, lhp, AckBuff, ackp - AckBuff); - - switch (fp->state) { - case ST_STOPPED: - case ST_OPENED: - if (ackaction) - NewState(fp, ST_ACKSENT); - else - NewState(fp, ST_REQSENT); - break; - case ST_REQSENT: - if (ackaction) - NewState(fp, ST_ACKSENT); - break; - case ST_ACKRCVD: - if (ackaction) { - NewState(fp, ST_OPENED); - (fp->LayerUp) (fp); - } - break; - case ST_ACKSENT: - if (!ackaction) - NewState(fp, ST_REQSENT); - break; - } - pfree(bp); -} - -static void -FsmRecvConfigAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RCA */ -{ - switch (fp->state) { - case ST_CLOSED: - case ST_STOPPED: - (fp->SendTerminateAck) (fp); - break; - case ST_CLOSING: - case ST_STOPPING: - break; - case ST_REQSENT: - FsmInitRestartCounter(fp); - NewState(fp, ST_ACKRCVD); - break; - case ST_ACKRCVD: - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - case ST_ACKSENT: - FsmInitRestartCounter(fp); - NewState(fp, ST_OPENED); - (fp->LayerUp) (fp); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - } - pfree(bp); -} - -static void -FsmRecvConfigNak(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RCN */ -{ - int plen, flen; - - plen = plength(bp); - flen = ntohs(lhp->length) - sizeof *lhp; - if (plen < flen) { - pfree(bp); - return; - } - - /* - * Check and process easy case - */ - switch (fp->state) { - case ST_INITIAL: - case ST_STARTING: - LogPrintf(fp->LogLevel, "Oops, RCN in %s.\n", StateNames[fp->state]); - pfree(bp); - return; - case ST_CLOSED: - case ST_STOPPED: - (fp->SendTerminateAck) (fp); - pfree(bp); - return; - case ST_CLOSING: - case ST_STOPPING: - pfree(bp); - return; - } - - (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_NAK); - - switch (fp->state) { - case ST_REQSENT: - case ST_ACKSENT: - FsmInitRestartCounter(fp); - FsmSendConfigReq(fp); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - /* Fall down */ - case ST_ACKRCVD: - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - } - - pfree(bp); -} - -static void -FsmRecvTermReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RTR */ -{ - switch (fp->state) { - case ST_INITIAL: - case ST_STARTING: - LogPrintf(fp->LogLevel, "Oops, RTR in %s\n", StateNames[fp->state]); - break; - case ST_CLOSED: - case ST_STOPPED: - case ST_CLOSING: - case ST_STOPPING: - case ST_REQSENT: - (fp->SendTerminateAck) (fp); - break; - case ST_ACKRCVD: - case ST_ACKSENT: - (fp->SendTerminateAck) (fp); - NewState(fp, ST_REQSENT); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - (fp->SendTerminateAck) (fp); - StartTimer(&fp->FsmTimer); /* Start restart timer */ - fp->restart = 0; - NewState(fp, ST_STOPPING); - break; - } - pfree(bp); -} - -static void -FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RTA */ -{ - switch (fp->state) { - case ST_CLOSING: - NewState(fp, ST_CLOSED); - (fp->LayerFinish) (fp); - break; - case ST_STOPPING: - NewState(fp, ST_STOPPED); - (fp->LayerFinish) (fp); - break; - case ST_ACKRCVD: - NewState(fp, ST_REQSENT); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - } - pfree(bp); -} - -static void -FsmRecvConfigRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -/* RCJ */ -{ - int plen, flen; - - plen = plength(bp); - flen = ntohs(lhp->length) - sizeof *lhp; - if (plen < flen) { - pfree(bp); - return; - } - LogPrintf(fp->LogLevel, "RecvConfigRej.\n"); - - /* - * Check and process easy case - */ - switch (fp->state) { - case ST_INITIAL: - case ST_STARTING: - LogPrintf(fp->LogLevel, "Oops, RCJ in %s.\n", StateNames[fp->state]); - pfree(bp); - return; - case ST_CLOSED: - case ST_STOPPED: - (fp->SendTerminateAck) (fp); - pfree(bp); - return; - case ST_CLOSING: - case ST_STOPPING: - pfree(bp); - return; - } - - (fp->DecodeConfig) (MBUF_CTOP(bp), flen, MODE_REJ); - - switch (fp->state) { - case ST_REQSENT: - case ST_ACKSENT: - FsmInitRestartCounter(fp); - FsmSendConfigReq(fp); - break; - case ST_OPENED: - (fp->LayerDown) (fp); - /* Fall down */ - case ST_ACKRCVD: - FsmSendConfigReq(fp); - NewState(fp, ST_REQSENT); - break; - } - pfree(bp); -} - -static void -FsmRecvCodeRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvCodeRej\n"); - pfree(bp); -} - -static void -FsmRecvProtoRej(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - u_short *sp, proto; - - sp = (u_short *) MBUF_CTOP(bp); - proto = ntohs(*sp); - LogPrintf(fp->LogLevel, "-- Protocol (%04x) was rejected.\n", proto); - - switch (proto) { - case PROTO_LQR: - StopLqr(LQM_LQR); - break; - case PROTO_CCP: - fp = &CcpFsm; - (fp->LayerFinish) (fp); - switch (fp->state) { - case ST_CLOSED: - case ST_CLOSING: - NewState(fp, ST_CLOSED); - default: - NewState(fp, ST_STOPPED); - break; - } - break; - } - pfree(bp); -} - -static void -FsmRecvEchoReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - u_char *cp; - u_int32_t *lp, magic; - - cp = MBUF_CTOP(bp); - lp = (u_int32_t *) cp; - magic = ntohl(*lp); - if (magic != LcpInfo.his_magic) { - LogPrintf(LogERROR, "RecvEchoReq: his magic is bad!!\n"); - /* XXX: We should send terminate request */ - } - if (fp->state == ST_OPENED) { - *lp = htonl(LcpInfo.want_magic); /* Insert local magic number */ - LogPrintf(fp->LogLevel, "SendEchoRep(%s)\n", StateNames[fp->state]); - FsmOutput(fp, CODE_ECHOREP, lhp->id, cp, plength(bp)); - } - pfree(bp); -} - -static void -FsmRecvEchoRep(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - u_int32_t *lp, magic; - - lp = (u_int32_t *) MBUF_CTOP(bp); - magic = ntohl(*lp); -/* - * Tolerate echo replies with either magic number - */ - if (magic != 0 && magic != LcpInfo.his_magic && magic != LcpInfo.want_magic) { - LogPrintf(LogERROR, "RecvEchoRep: his magic is wrong! expect: %x got: %x\n", - LcpInfo.his_magic, magic); - - /* - * XXX: We should send terminate request. But poor implementation may die - * as a result. - */ - } - RecvEchoLqr(bp); - pfree(bp); -} - -static void -FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvDiscReq\n"); - pfree(bp); -} - -static void -FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvIdent\n"); - pfree(bp); -} - -static void -FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvTimeRemain\n"); - pfree(bp); -} - -static void -FsmRecvResetReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvResetReq(%d)\n", lhp->id); - CcpRecvResetReq(fp); - /* - * All sendable compressed packets are queued in the PRI_NORMAL modem - * output queue.... dump 'em to the priority queue so that they arrive - * at the peer before our ResetAck. - */ - SequenceQueues(); - LogPrintf(fp->LogLevel, "SendResetAck(%d)\n", lhp->id); - FsmOutput(fp, CODE_RESETACK, lhp->id, NULL, 0); - pfree(bp); -} - -static void -FsmRecvResetAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) -{ - LogPrintf(fp->LogLevel, "RecvResetAck(%d)\n", lhp->id); - CcpResetInput(lhp->id); - fp->reqid++; - pfree(bp); -} - -static const struct fsmcodedesc FsmCodes[] = { - {FsmRecvConfigReq, "Configure Request",}, - {FsmRecvConfigAck, "Configure Ack",}, - {FsmRecvConfigNak, "Configure Nak",}, - {FsmRecvConfigRej, "Configure Reject",}, - {FsmRecvTermReq, "Terminate Request",}, - {FsmRecvTermAck, "Terminate Ack",}, - {FsmRecvCodeRej, "Code Reject",}, - {FsmRecvProtoRej, "Protocol Reject",}, - {FsmRecvEchoReq, "Echo Request",}, - {FsmRecvEchoRep, "Echo Reply",}, - {FsmRecvDiscReq, "Discard Request",}, - {FsmRecvIdent, "Ident",}, - {FsmRecvTimeRemain, "Time Remain",}, - {FsmRecvResetReq, "Reset Request",}, - {FsmRecvResetAck, "Reset Ack",}, -}; - -void -FsmInput(struct fsm * fp, struct mbuf * bp) -{ - int len; - struct fsmheader *lhp; - const struct fsmcodedesc *codep; - - len = plength(bp); - if (len < sizeof(struct fsmheader)) { - pfree(bp); - return; - } - lhp = (struct fsmheader *) MBUF_CTOP(bp); - if (lhp->code == 0 || lhp->code > fp->max_code) { - pfree(bp); /* XXX: Should send code reject */ - return; - } - bp->offset += sizeof(struct fsmheader); - bp->cnt -= sizeof(struct fsmheader); - - codep = FsmCodes + lhp->code - 1; - LogPrintf(fp->LogLevel, "Received %s (%d) state = %s (%d)\n", - codep->name, lhp->id, StateNames[fp->state], fp->state); - if (LogIsKept(LogDEBUG)) - LogMemory(); - (codep->action) (fp, lhp, bp); - if (LogIsKept(LogDEBUG)) - LogMemory(); -} diff --git a/usr.sbin/ppp/hdlc.h b/usr.sbin/ppp/hdlc.h deleted file mode 100644 index 2dcad67426b..00000000000 --- a/usr.sbin/ppp/hdlc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: hdlc.h,v 1.3 1998/01/21 02:13:32 brian Exp $ - * - * TODO: - */ - -/* - * Definition for Async HDLC - */ -#define HDLC_SYN 0x7e /* SYNC character */ -#define HDLC_ESC 0x7d /* Escape character */ -#define HDLC_XOR 0x20 /* Modifier value */ - -#define HDLC_ADDR 0xff -#define HDLC_UI 0x03 -/* - * Definition for HDLC Frame Check Sequence - */ -#define INITFCS 0xffff /* Initial value for FCS computation */ -#define GOODFCS 0xf0b8 /* Good FCS value */ - -#define DEF_MRU 1500 -#define MAX_MRU 2048 -#define MIN_MRU 296 - -#define DEF_MTU 0 /* whatever peer says */ -#define MAX_MTU 2048 -#define MIN_MTU 296 - -/* - * Output priority - */ -/* PRI_NORMAL and PRI_FAST have meaning only on the IP queue. - * All IP frames have the same priority once they are compressed. - * IP frames stay on the IP queue till they can be sent on the - * link. They are compressed at that time. -*/ -#define PRI_NORMAL 0 /* Normal priority */ -#define PRI_FAST 1 /* Fast (interractive) */ -#define PRI_LINK 1 /* Urgent (LQR packets) */ - -extern u_char EscMap[33]; - -extern void HdlcInit(void); -extern void HdlcErrorCheck(void); -extern void HdlcInput(struct mbuf *); -extern void HdlcOutput(int, u_short, struct mbuf *bp); -extern u_short HdlcFcs(u_short, u_char *, int); -extern int ReportHdlcStatus(struct cmdargs const *); -extern int ReportProtStatus(struct cmdargs const *); diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c deleted file mode 100644 index 382a4075ef4..00000000000 --- a/usr.sbin/ppp/ipcp.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - * PPP IP Control Protocol (IPCP) Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: ipcp.c,v 1.14 1998/06/27 16:27:02 brian Exp $ - * - * TODO: - * o More RFC1772 backwoard compatibility - */ -#include <sys/param.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <arpa/inet.h> -#include <sys/socket.h> -#include <netdb.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "lcpproto.h" -#include "lcp.h" -#include "iplist.h" -#include "ipcp.h" -#include "slcompress.h" -#include "os.h" -#include "phase.h" -#include "loadalias.h" -#include "vars.h" -#include "vjcomp.h" -#include "ip.h" -#include "throughput.h" -#include "route.h" -#include "filter.h" - -#ifndef NOMSEXT -struct in_addr ns_entries[2]; -struct in_addr nbns_entries[2]; -#endif - -struct ipcpstate IpcpInfo; -struct in_range DefMyAddress; -struct in_range DefHisAddress; -struct iplist DefHisChoice; -struct in_addr TriggerAddress; -int HaveTriggerAddress; - -static void IpcpSendConfigReq(struct fsm *); -static void IpcpSendTerminateAck(struct fsm *); -static void IpcpSendTerminateReq(struct fsm *); -static void IpcpDecodeConfig(u_char *, int, int); -static void IpcpLayerStart(struct fsm *); -static void IpcpLayerFinish(struct fsm *); -static void IpcpLayerUp(struct fsm *); -static void IpcpLayerDown(struct fsm *); -static void IpcpInitRestartCounter(struct fsm *); - -struct fsm IpcpFsm = { - "IPCP", - PROTO_IPCP, - IPCP_MAXCODE, - 0, - ST_INITIAL, - 0, 0, 0, - - {0, 0, 0, NULL, NULL, NULL}, /* FSM timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Open timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */ - LogIPCP, - - IpcpLayerUp, - IpcpLayerDown, - IpcpLayerStart, - IpcpLayerFinish, - IpcpInitRestartCounter, - IpcpSendConfigReq, - IpcpSendTerminateReq, - IpcpSendTerminateAck, - IpcpDecodeConfig, -}; - -static const char *cftypes[] = { - /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ - "???", - "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ - "COMPPROTO", /* 2: IP-Compression-Protocol */ - "IPADDR", /* 3: IP-Address */ -}; - -#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) - -static const char *cftypes128[] = { - /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ - "???", - "PRIDNS", /* 129: Primary DNS Server Address */ - "PRINBNS", /* 130: Primary NBNS Server Address */ - "SECDNS", /* 131: Secondary DNS Server Address */ - "SECNBNS", /* 132: Secondary NBNS Server Address */ -}; - -#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) - -static struct pppThroughput throughput; - -void -IpcpAddInOctets(int n) -{ - throughput_addin(&throughput, n); -} - -void -IpcpAddOutOctets(int n) -{ - throughput_addout(&throughput, n); -} - -int -ReportIpcpStatus(struct cmdargs const *arg) -{ - struct fsm *fp = &IpcpFsm; - - if (!VarTerm) - return 1; - fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); - if (IpcpFsm.state == ST_OPENED) { - fprintf(VarTerm, " his side: %s, %s\n", - inet_ntoa(IpcpInfo.his_ipaddr), vj2asc(IpcpInfo.his_compproto)); - fprintf(VarTerm, " my side: %s, %s\n", - inet_ntoa(IpcpInfo.want_ipaddr), vj2asc(IpcpInfo.want_compproto)); - } - - fprintf(VarTerm, "Defaults:\n"); - fprintf(VarTerm, " My Address: %s/%d\n", - inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); - if (iplist_isvalid(&DefHisChoice)) - fprintf(VarTerm, " His Address: %s\n", DefHisChoice.src); - else - fprintf(VarTerm, " His Address: %s/%d\n", - inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); - if (HaveTriggerAddress) - fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress)); - else - fprintf(VarTerm, " Negotiation(trigger): MYADDR\n"); - - fprintf(VarTerm, "\n"); - throughput_disp(&throughput, VarTerm); - - return 0; -} - -void -IpcpDefAddress() -{ - struct hostent *hp; - char name[200]; - - memset(&DefMyAddress, '\0', sizeof DefMyAddress); - memset(&DefHisAddress, '\0', sizeof DefHisAddress); - TriggerAddress.s_addr = 0; - HaveTriggerAddress = 0; - if (gethostname(name, sizeof name) == 0) { - hp = gethostbyname(name); - if (hp && hp->h_addrtype == AF_INET) { - memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length); - } - } -} - -static int VJInitSlots = MAX_STATES; -static int VJInitComp = 1; - -int -SetInitVJ(struct cmdargs const *args) -{ - if (args->argc != 2) - return -1; - if (!strcasecmp(args->argv[0], "slots")) { - int slots; - - slots = atoi(args->argv[1]); - if (slots < 4 || slots > 16) - return 1; - VJInitSlots = slots; - return 0; - } else if (!strcasecmp(args->argv[0], "slotcomp")) { - if (!strcasecmp(args->argv[1], "on")) - VJInitComp = 1; - else if (!strcasecmp(args->argv[1], "off")) - VJInitComp = 0; - else - return 2; - return 0; - } - return -1; -} - -int -ShowInitVJ(struct cmdargs const *args) -{ - if (VarTerm) { - fprintf(VarTerm, "Initial slots: %d\n", VJInitSlots); - fprintf(VarTerm, "Initial compression: %s\n", VJInitComp ? "on" : "off"); - } - return 0; -} - -void -IpcpInit() -{ - if (iplist_isvalid(&DefHisChoice)) - iplist_setrandpos(&DefHisChoice); - FsmInit(&IpcpFsm); - memset(&IpcpInfo, '\0', sizeof IpcpInfo); - if ((mode & MODE_DEDICATED) && !GetLabel()) { - IpcpInfo.want_ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr = 0; - } else { - IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; - IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; - } - - /* - * Some implementations of PPP require that we send a - * *special* value as our address, even though the rfc specifies - * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). - */ - if (HaveTriggerAddress) { - IpcpInfo.want_ipaddr.s_addr = TriggerAddress.s_addr; - LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress)); - } - if (Enabled(ConfVjcomp)) - IpcpInfo.want_compproto = (PROTO_VJCOMP << 16) | ((VJInitSlots - 1) << 8) | - VJInitComp; - else - IpcpInfo.want_compproto = 0; - IpcpInfo.heis1172 = 0; - IpcpFsm.maxconfig = 10; - throughput_init(&throughput); -} - -static void -IpcpInitRestartCounter(struct fsm * fp) -{ - fp->FsmTimer.load = VarRetryTimeout * SECTICKS; - fp->restart = 5; -} - -static void -IpcpSendConfigReq(struct fsm * fp) -{ - u_char *cp; - struct lcp_opt o; - - cp = ReqBuff; - LogPrintf(LogIPCP, "IpcpSendConfigReq\n"); - if (!DEV_IS_SYNC || !REJECTED(&IpcpInfo, TY_IPADDR)) { - o.id = TY_IPADDR; - o.len = 6; - *(u_int32_t *)o.data = IpcpInfo.want_ipaddr.s_addr; - cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], - inet_ntoa(IpcpInfo.want_ipaddr)); - } - - if (IpcpInfo.want_compproto && !REJECTED(&IpcpInfo, TY_COMPPROTO)) { - const char *args; - o.id = TY_COMPPROTO; - if (IpcpInfo.heis1172) { - o.len = 4; - *(u_short *)o.data = htons(PROTO_VJCOMP); - args = ""; - } else { - o.len = 6; - *(u_int32_t *)o.data = htonl(IpcpInfo.want_compproto); - args = vj2asc(IpcpInfo.want_compproto); - } - cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args); - } - FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); -} - -static void -IpcpSendTerminateReq(struct fsm * fp) -{ - /* XXX: No code yet */ -} - -static void -IpcpSendTerminateAck(struct fsm * fp) -{ - LogPrintf(LogIPCP, "IpcpSendTerminateAck\n"); - FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); -} - -static void -IpcpLayerStart(struct fsm * fp) -{ - LogPrintf(LogIPCP, "IpcpLayerStart.\n"); -} - -static void -IpcpLayerFinish(struct fsm * fp) -{ - LogPrintf(LogIPCP, "IpcpLayerFinish.\n"); - reconnect(RECON_FALSE); - LcpClose(); - NewPhase(PHASE_TERMINATE); -} - -static void -IpcpLayerDown(struct fsm * fp) -{ - LogPrintf(LogIPCP, "IpcpLayerDown.\n"); - throughput_stop(&throughput); - throughput_log(&throughput, LogIPCP, NULL); -} - -/* - * Called when IPCP has reached to OPEN state - */ -static void -IpcpLayerUp(struct fsm * fp) -{ - char tbuff[100]; - - Prompt(); - LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state); - snprintf(tbuff, sizeof tbuff, "myaddr = %s ", - inet_ntoa(IpcpInfo.want_ipaddr)); - - if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP) - VjInit((IpcpInfo.his_compproto >> 8) & 255); - - LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n", - tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); - if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr) < 0) { - if (VarTerm) - LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); - return; - } -#ifndef NOALIAS - if (mode & MODE_ALIAS) - VarPacketAliasSetAddress(IpcpInfo.want_ipaddr); -#endif - OsLinkup(); - throughput_start(&throughput); - StartIdleTimer(); -} - -void -IpcpUp() -{ - FsmUp(&IpcpFsm); - LogPrintf(LogIPCP, "IPCP Up event!!\n"); -} - -void -IpcpOpen() -{ - FsmOpen(&IpcpFsm); -} - -static int -AcceptableAddr(struct in_range * prange, struct in_addr ipaddr) -{ - LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr)); - LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr)); - LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr)); - LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange-> - mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr)); - return (prange->ipaddr.s_addr & prange->mask.s_addr) == - (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; -} - -static void -IpcpDecodeConfig(u_char * cp, int plen, int mode_type) -{ - int type, length; - u_int32_t *lp, compproto; - struct compreq *pcomp; - struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; - char tbuff[100]; - char tbuff2[100]; - - ackp = AckBuff; - nakp = NakBuff; - rejp = RejBuff; - - while (plen >= sizeof(struct fsmconfig)) { - type = *cp; - length = cp[1]; - if (type < NCFTYPES) - snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); - else if (type > 128 && type < 128 + NCFTYPES128) - snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); - else - snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); - - switch (type) { - case TY_IPADDR: /* RFC1332 */ - lp = (u_int32_t *) (cp + 2); - ipaddr.s_addr = *lp; - LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); - - switch (mode_type) { - case MODE_REQ: - if (iplist_isvalid(&DefHisChoice)) { - if (ipaddr.s_addr == INADDR_ANY || - iplist_ip2pos(&DefHisChoice, ipaddr) < 0 || - OsTrySetIpaddress(DefMyAddress.ipaddr, ipaddr) != 0) { - LogPrintf(LogIPCP, "%s: Address invalid or already in use\n", - inet_ntoa(ipaddr)); - IpcpInfo.his_ipaddr = ChooseHisAddr(DefMyAddress.ipaddr); - if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) { - memcpy(rejp, cp, length); - rejp += length; - } else { - memcpy(nakp, cp, 2); - memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2); - nakp += length; - } - break; - } - } else if (!AcceptableAddr(&DefHisAddress, ipaddr)) { - /* - * If destination address is not acceptable, insist to use what we - * want to use. - */ - memcpy(nakp, cp, 2); - memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2); - nakp += length; - break; - } - IpcpInfo.his_ipaddr = ipaddr; - memcpy(ackp, cp, length); - ackp += length; - break; - case MODE_NAK: - if (AcceptableAddr(&DefMyAddress, ipaddr)) { - /* Use address suggested by peer */ - snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, - inet_ntoa(IpcpInfo.want_ipaddr)); - LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); - IpcpInfo.want_ipaddr = ipaddr; - } else { - LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); - FsmClose(&IpcpFsm); - } - break; - case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); - break; - } - break; - case TY_COMPPROTO: - lp = (u_int32_t *) (cp + 2); - compproto = htonl(*lp); - LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); - - switch (mode_type) { - case MODE_REQ: - if (!Acceptable(ConfVjcomp)) { - memcpy(rejp, cp, length); - rejp += length; - } else { - pcomp = (struct compreq *) (cp + 2); - switch (length) { - case 4: /* RFC1172 */ - if (ntohs(pcomp->proto) == PROTO_VJCOMP) { - LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); - IpcpInfo.heis1172 = 1; - IpcpInfo.his_compproto = compproto; - memcpy(ackp, cp, length); - ackp += length; - } else { - memcpy(nakp, cp, 2); - pcomp->proto = htons(PROTO_VJCOMP); - memcpy(nakp+2, &pcomp, 2); - nakp += length; - } - break; - case 6: /* RFC1332 */ - if (ntohs(pcomp->proto) == PROTO_VJCOMP - && pcomp->slots < MAX_STATES && pcomp->slots > 2) { - IpcpInfo.his_compproto = compproto; - IpcpInfo.heis1172 = 0; - memcpy(ackp, cp, length); - ackp += length; - } else { - memcpy(nakp, cp, 2); - pcomp->proto = htons(PROTO_VJCOMP); - pcomp->slots = MAX_STATES - 1; - pcomp->compcid = 0; - memcpy(nakp+2, &pcomp, sizeof pcomp); - nakp += length; - } - break; - default: - memcpy(rejp, cp, length); - rejp += length; - break; - } - } - break; - case MODE_NAK: - LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n", - tbuff, IpcpInfo.want_compproto, compproto); - IpcpInfo.want_compproto = compproto; - break; - case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); - break; - } - break; - case TY_IPADDRS: /* RFC1172 */ - lp = (u_int32_t *) (cp + 2); - ipaddr.s_addr = *lp; - lp = (u_int32_t *) (cp + 6); - dstipaddr.s_addr = *lp; - snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); - LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); - - switch (mode_type) { - case MODE_REQ: - IpcpInfo.his_ipaddr = ipaddr; - IpcpInfo.want_ipaddr = dstipaddr; - memcpy(ackp, cp, length); - ackp += length; - break; - case MODE_NAK: - snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, - inet_ntoa(IpcpInfo.want_ipaddr)); - LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); - IpcpInfo.want_ipaddr = ipaddr; - IpcpInfo.his_ipaddr = dstipaddr; - break; - case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); - break; - } - break; - - /* - * MS extensions for MS's PPP - */ - -#ifndef NOMSEXT - case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ - case TY_SECONDARY_DNS: - if (!Enabled(ConfMSExt)) { - LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n"); - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - break; - } - switch (mode_type) { - case MODE_REQ: - lp = (u_int32_t *) (cp + 2); - dnsstuff.s_addr = *lp; - ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr; - if (dnsstuff.s_addr != ms_info_req.s_addr) { - - /* - * So the client has got the DNS stuff wrong (first request) so - * we'll tell 'em how it is - */ - memcpy(nakp, cp, 2); /* copy first two (type/length) */ - LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n", - type, - inet_ntoa(dnsstuff), - inet_ntoa(ms_info_req)); - memcpy(nakp+2, &ms_info_req, length); - nakp += length; - break; - } - - /* - * Otherwise they have it right (this time) so we send a ack packet - * back confirming it... end of story - */ - LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n", - type, - inet_ntoa(ms_info_req)); - memcpy(ackp, cp, length); - ackp += length; - break; - case MODE_NAK: /* what does this mean?? */ - LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type); - break; - case MODE_REJ: /* confused?? me to :) */ - LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type); - break; - } - break; - - case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ - case TY_SECONDARY_NBNS: - if (!Enabled(ConfMSExt)) { - LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n"); - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - break; - } - switch (mode_type) { - case MODE_REQ: - lp = (u_int32_t *) (cp + 2); - dnsstuff.s_addr = *lp; - ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr; - if (dnsstuff.s_addr != ms_info_req.s_addr) { - memcpy(nakp, cp, 2); - memcpy(nakp+2, &ms_info_req.s_addr, length); - LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n", - type, - inet_ntoa(dnsstuff), - inet_ntoa(ms_info_req)); - nakp += length; - break; - } - LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n", - type, - inet_ntoa(ms_info_req)); - memcpy(ackp, cp, length); - ackp += length; - break; - case MODE_NAK: - LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type); - break; - case MODE_REJ: - LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type); - break; - } - break; - -#endif - - default: - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - break; - } - plen -= length; - cp += length; - } -} - -void -IpcpInput(struct mbuf * bp) -{ - FsmInput(&IpcpFsm, bp); -} - -int -UseHisaddr(const char *hisaddr, int setaddr) -{ - memset(&DefHisAddress, '\0', sizeof DefHisAddress); - iplist_reset(&DefHisChoice); - if (strpbrk(hisaddr, ",-")) { - iplist_setsrc(&DefHisChoice, hisaddr); - if (iplist_isvalid(&DefHisChoice)) { - iplist_setrandpos(&DefHisChoice); - IpcpInfo.his_ipaddr = ChooseHisAddr(IpcpInfo.want_ipaddr); - if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) { - LogPrintf(LogWARN, "%s: None available !\n", DefHisChoice.src); - return(0); - } - DefHisAddress.ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr; - DefHisAddress.mask.s_addr = 0xffffffff; - DefHisAddress.width = 32; - } else { - LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr); - return 0; - } - } else if (ParseAddr(1, &hisaddr, &DefHisAddress.ipaddr, - &DefHisAddress.mask, &DefHisAddress.width) != 0) { - IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; - - if (setaddr && OsSetIpaddress - (DefMyAddress.ipaddr, DefHisAddress.ipaddr) < 0) { - DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L; - return 0; - } - } else - return 0; - - return 1; -} diff --git a/usr.sbin/ppp/ipcp.h b/usr.sbin/ppp/ipcp.h deleted file mode 100644 index b5d23687cd0..00000000000 --- a/usr.sbin/ppp/ipcp.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: ipcp.h,v 1.5 1998/01/18 20:47:20 brian Exp $ - * - * TODO: - */ - -#define IPCP_MAXCODE CODE_CODEREJ - -#define TY_IPADDRS 1 -#define TY_COMPPROTO 2 -#define TY_IPADDR 3 - -/* MS PPP NameServer and NetBIOS NameServer stuff */ - -#ifndef NOMSEXT -#define TY_PRIMARY_DNS 129 -#define TY_PRIMARY_NBNS 130 -#define TY_SECONDARY_DNS 131 -#define TY_SECONDARY_NBNS 132 - -extern struct in_addr ns_entries[2]; -extern struct in_addr nbns_entries[2]; -#endif - -struct ipcpstate { - struct in_addr his_ipaddr; /* IP address he is willing to use */ - u_int32_t his_compproto; - - struct in_addr want_ipaddr; /* IP address I'm willing to use */ - u_int32_t want_compproto; - - u_int32_t his_reject; /* Request codes rejected by peer */ - u_int32_t my_reject; /* Request codes I have rejected */ - int heis1172; /* True if he is speaking rfc1172 */ -}; - -struct compreq { - u_short proto; - u_char slots; - u_char compcid; -}; - -struct in_range { - struct in_addr ipaddr; - struct in_addr mask; - int width; -}; - -extern struct ipcpstate IpcpInfo; -extern struct in_range DefMyAddress; -extern struct in_range DefHisAddress; -extern struct iplist DefHisChoice; -extern struct in_addr TriggerAddress; -extern int HaveTriggerAddress; -extern struct fsm IpcpFsm; - -extern void IpcpInit(void); -extern void IpcpDefAddress(void); -extern void IpcpUp(void); -extern void IpcpOpen(void); -extern int ReportIpcpStatus(struct cmdargs const *); -extern void IpcpInput(struct mbuf *); -extern void IpcpAddInOctets(int); -extern void IpcpAddOutOctets(int); -extern int UseHisaddr(const char *, int); -extern int SetInitVJ(struct cmdargs const *); -extern int ShowInitVJ(struct cmdargs const *); diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c deleted file mode 100644 index fe0e29d662c..00000000000 --- a/usr.sbin/ppp/lcp.c +++ /dev/null @@ -1,834 +0,0 @@ -/* - * PPP Link Control Protocol (LCP) Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: lcp.c,v 1.11 1998/06/28 09:41:40 brian Exp $ - * - * TODO: - * o Validate magic number received from peer. - * o Limit data field length by MRU - */ -#include <sys/param.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <net/if.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> -#include <termios.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "lcp.h" -#include "ipcp.h" -#include "lcpproto.h" -#include "os.h" -#include "hdlc.h" -#include "ccp.h" -#include "lqr.h" -#include "phase.h" -#include "loadalias.h" -#include "vars.h" -#include "auth.h" -#include "pap.h" -#include "chap.h" -#include "async.h" -#include "main.h" -#include "ip.h" -#include "modem.h" -#include "tun.h" - -/* for received LQRs */ -struct lqrreq { - u_char type; - u_char length; - u_short proto; /* Quality protocol */ - u_long period; /* Reporting interval */ -}; - -struct lcpstate LcpInfo; - -static void LcpSendConfigReq(struct fsm *); -static void LcpSendTerminateReq(struct fsm *); -static void LcpSendTerminateAck(struct fsm *); -static void LcpDecodeConfig(u_char *, int, int); -static void LcpInitRestartCounter(struct fsm *); -static void LcpLayerUp(struct fsm *); -static void LcpLayerDown(struct fsm *); -static void LcpLayerStart(struct fsm *); -static void LcpLayerFinish(struct fsm *); - -static const char *cftypes[] = { - /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ - "???", - "MRU", /* 1: Maximum-Receive-Unit */ - "ACCMAP", /* 2: Async-Control-Character-Map */ - "AUTHPROTO", /* 3: Authentication-Protocol */ - "QUALPROTO", /* 4: Quality-Protocol */ - "MAGICNUM", /* 5: Magic-Number */ - "RESERVED", /* 6: RESERVED */ - "PROTOCOMP", /* 7: Protocol-Field-Compression */ - "ACFCOMP", /* 8: Address-and-Control-Field-Compression */ - "FCSALT", /* 9: FCS-Alternatives */ - "SDP", /* 10: Self-Describing-Pad */ - "NUMMODE", /* 11: Numbered-Mode */ - "MULTIPROC", /* 12: Multi-Link-Procedure */ - "CALLBACK", /* 13: Callback */ - "CONTIME", /* 14: Connect-Time */ - "COMPFRAME", /* 15: Compound-Frames */ - "NDE", /* 16: Nominal-Data-Encapsulation */ - "MULTIMRRU", /* 17: Multilink-MRRU */ - "MULTISSNH", /* 18: Multilink-Short-Sequence-Number-Header */ - "MULTIED", /* 19: Multilink-Endpoint-Descriminator */ - "PROPRIETRY", /* 20: Proprietary */ - "DCEID", /* 21: DCE-Identifier */ - "MULTIPP", /* 22: Multi-Link-Plus-Procedure */ - "LDBACP", /* 23: Link Discriminator for BACP */ -}; - -#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) - -struct fsm LcpFsm = { - "LCP", /* Name of protocol */ - PROTO_LCP, /* Protocol Number */ - LCP_MAXCODE, - 1, /* Open mode delay */ - ST_INITIAL, /* State of machine */ - 0, 0, 0, - {0, 0, 0, NULL, NULL, NULL}, /* FSM timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Open timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */ - LogLCP, - - LcpLayerUp, - LcpLayerDown, - LcpLayerStart, - LcpLayerFinish, - LcpInitRestartCounter, - LcpSendConfigReq, - LcpSendTerminateReq, - LcpSendTerminateAck, - LcpDecodeConfig, -}; - -static struct pppTimer LcpReportTimer; -static int LcpFailedMagic; - -static void -LcpReportTime(void *data) -{ - if (LogIsKept(LogDEBUG)) { - time_t t; - - time(&t); - LogPrintf(LogDEBUG, "LcpReportTime: %s\n", ctime(&t)); - } - StopTimer(&LcpReportTimer); - LcpReportTimer.state = TIMER_STOPPED; - StartTimer(&LcpReportTimer); - HdlcErrorCheck(); -} - -int -ReportLcpStatus(struct cmdargs const *arg) -{ - struct lcpstate *lcp = &LcpInfo; - struct fsm *fp = &LcpFsm; - - if (!VarTerm) - return 1; - - fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); - fprintf(VarTerm, - " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n" - " MAGIC %08lx, REJECT %04x\n", - lcp->his_mru, (u_long)lcp->his_accmap, lcp->his_protocomp, - lcp->his_acfcomp, (u_long)lcp->his_magic, lcp->his_reject); - fprintf(VarTerm, - " my side: MRU %d, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d,\n" - " MAGIC %08lx, REJECT %04x\n", - lcp->want_mru, (u_long)lcp->want_accmap, lcp->want_protocomp, - lcp->want_acfcomp, (u_long)lcp->want_magic, lcp->my_reject); - fprintf(VarTerm, "\nDefaults: MRU = %d, ACCMAP = %08lx\t", - VarMRU, (u_long)VarAccmap); - fprintf(VarTerm, "Open Mode: %s", - (VarOpenMode == OPEN_PASSIVE) ? "passive" : "active"); - if (VarOpenMode > 0) - fprintf(VarTerm, " (delay %d)", VarOpenMode); - fputc('\n', VarTerm); - return 0; -} - -/* - * Generate random number which will be used as magic number. - */ -static u_int32_t -GenerateMagic(void) -{ - randinit(); - return (random()); -} - -void -LcpInit() -{ - struct lcpstate *lcp = &LcpInfo; - - FsmInit(&LcpFsm); - HdlcInit(); - - memset(lcp, '\0', sizeof(struct lcpstate)); - lcp->want_mru = VarMRU; - lcp->his_mru = DEF_MRU; - lcp->his_accmap = 0xffffffff; - lcp->want_accmap = VarAccmap; - lcp->want_magic = GenerateMagic(); - lcp->want_auth = lcp->his_auth = 0; - if (Enabled(ConfChap)) - lcp->want_auth = PROTO_CHAP; - else if (Enabled(ConfPap)) - lcp->want_auth = PROTO_PAP; - if (Enabled(ConfLqr)) - lcp->want_lqrperiod = VarLqrTimeout * 100; - if (Enabled(ConfAcfcomp)) - lcp->want_acfcomp = 1; - if (Enabled(ConfProtocomp)) - lcp->want_protocomp = 1; - LcpFsm.maxconfig = 10; -} - -static void -LcpInitRestartCounter(struct fsm * fp) -{ - fp->FsmTimer.load = VarRetryTimeout * SECTICKS; - fp->restart = 5; -} - -int -LcpPutConf(int log, u_char *tgt, const struct lcp_opt *o, const char *nm, - const char *arg, ...) -{ - va_list ap; - char buf[30]; - - va_start(ap, arg); - memcpy(tgt, o, o->len); - if (arg == NULL || *arg == '\0') - LogPrintf(log, " %s[%d]\n", nm, o->len); - else { - vsnprintf(buf, sizeof buf, arg, ap); - LogPrintf(log, " %s[%d] %s\n", nm, o->len, buf); - } - va_end(ap); - - return o->len; -} - -#define PUTN(ty) \ -do { \ - o.id = ty; \ - o.len = 2; \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], NULL); \ -} while (0) - -#define PUTHEX32(ty, arg) \ -do { \ - o.id = ty; \ - o.len = 6; \ - *(u_int32_t *)o.data = htonl(arg); \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "0x%08lx", (u_long)arg);\ -} while (0) - -#define PUTACCMAP(arg) PUTHEX32(TY_ACCMAP, arg) -#define PUTMAGIC(arg) PUTHEX32(TY_MAGICNUM, arg) - -#define PUTMRU(arg) \ -do { \ - o.id = TY_MRU; \ - o.len = 4; \ - *(u_short *)o.data = htons(arg); \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], "%u", arg); \ -} while (0) - -#define PUTLQR(period) \ -do { \ - o.id = TY_QUALPROTO; \ - o.len = 8; \ - *(u_short *)o.data = htons(PROTO_LQR); \ - *(u_int32_t *)(o.data+2) = htonl(period); \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \ - "period %ld", (u_long)period); \ -} while (0) - -#define PUTPAP() \ -do { \ - o.id = TY_AUTHPROTO; \ - o.len = 4; \ - *(u_short *)o.data = htons(PROTO_PAP); \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \ - "0x%04x (PAP)", PROTO_PAP); \ -} while (0) - -#define PUTCHAP(val) \ -do { \ - o.id = TY_AUTHPROTO; \ - o.len = 5; \ - *(u_short *)o.data = htons(PROTO_CHAP); \ - o.data[2] = val; \ - cp += LcpPutConf(LogLCP, cp, &o, cftypes[o.id], \ - "0x%04x (CHAP 0x%02x)", PROTO_CHAP, val); \ -} while (0) - -#define PUTMD5CHAP() PUTCHAP(0x05) -#define PUTMSCHAP() PUTCHAP(0x80) - -static void -LcpSendConfigReq(struct fsm * fp) -{ - u_char *cp; - struct lcpstate *lcp = &LcpInfo; - struct lcp_opt o; - - LogPrintf(LogLCP, "LcpSendConfigReq\n"); - cp = ReqBuff; - if (!DEV_IS_SYNC) { - if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) - PUTN(TY_ACFCOMP); - - if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) - PUTN(TY_PROTOCOMP); - - if (!REJECTED(lcp, TY_ACCMAP)) - PUTACCMAP(lcp->want_accmap); - } - - if (!REJECTED(lcp, TY_MRU)) - PUTMRU(lcp->want_mru); - - if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) - PUTMAGIC(lcp->want_magic); - - if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) - PUTLQR(lcp->want_lqrperiod); - - switch (lcp->want_auth) { - case PROTO_PAP: - PUTPAP(); - break; - - case PROTO_CHAP: -#ifdef HAVE_DES - if (VarMSChap) - PUTMSCHAP(); /* Use MSChap */ - else -#endif - PUTMD5CHAP(); /* Use MD5 */ - break; - } - FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); -} - -void -LcpSendProtoRej(u_char * option, int count) -{ - struct fsm *fp = &LcpFsm; - - LogPrintf(LogLCP, "LcpSendProtoRej\n"); - FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count); -} - -static void -LcpSendTerminateReq(struct fsm * fp) -{ - /* Most thins are done in fsm layer. Nothing to to. */ -} - -static void -LcpSendTerminateAck(struct fsm * fp) -{ - LogPrintf(LogLCP, "LcpSendTerminateAck.\n"); - FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); -} - -static void -LcpLayerStart(struct fsm * fp) -{ - LogPrintf(LogLCP, "LcpLayerStart\n"); - NewPhase(PHASE_ESTABLISH); -} - -static void -StopAllTimers(void) -{ - StopTimer(&LcpReportTimer); - StopIdleTimer(); - StopTimer(&AuthPapInfo.authtimer); - StopTimer(&AuthChapInfo.authtimer); - StopLqrTimer(); -} - -static void -LcpLayerFinish(struct fsm * fp) -{ - LogPrintf(LogLCP, "LcpLayerFinish\n"); - HangupModem(0); - StopAllTimers(); - /* We're down at last. Lets tell background and direct mode to get out */ - NewPhase(PHASE_DEAD); - LcpInit(); - IpcpInit(); - CcpInit(); - Prompt(); -} - -static void -LcpLayerUp(struct fsm * fp) -{ - LogPrintf(LogLCP, "LcpLayerUp\n"); - tun_configure(LcpInfo.his_mru, ModemSpeed()); - SetLinkParams(&LcpInfo); - - NewPhase(PHASE_AUTHENTICATE); - - StartLqm(); - StopTimer(&LcpReportTimer); - LcpReportTimer.state = TIMER_STOPPED; - LcpReportTimer.load = 60 * SECTICKS; - LcpReportTimer.func = LcpReportTime; - StartTimer(&LcpReportTimer); -} - -static void -LcpLayerDown(struct fsm * fp) -{ - StopAllTimers(); - OsLinkdown(); - LogPrintf(LogLCP, "LcpLayerDown\n"); - /* - * OsLinkdown() brings CCP & IPCP down, then waits 'till we go from - * STOPPING to STOPPED. At this point, the FSM gives us a LayerFinish - */ -} - -void -LcpUp() -{ - FsmUp(&LcpFsm); - LcpFailedMagic = 0; -} - -void -LcpDown() -{ /* Sudden death */ - LcpFailedMagic = 0; - FsmDown(&LcpFsm); - /* FsmDown() results in a LcpLayerDown() if we're currently open. */ - LcpLayerFinish(&LcpFsm); -} - -void -LcpOpen(int open_mode) -{ - LcpFsm.open_mode = open_mode; - LcpFailedMagic = 0; - FsmOpen(&LcpFsm); -} - -void -LcpClose() -{ - NewPhase(PHASE_TERMINATE); - OsInterfaceDown(0); - FsmClose(&LcpFsm); - LcpFailedMagic = 0; -} - -/* - * XXX: Should validate option length - */ -static void -LcpDecodeConfig(u_char *cp, int plen, int mode_type) -{ - int type, length, sz, pos; - u_int32_t *lp, magic, accmap; - u_short mtu, mru, *sp, proto; - struct lqrreq *req; - char request[20], desc[22]; - - ackp = AckBuff; - nakp = NakBuff; - rejp = RejBuff; - - while (plen >= sizeof(struct fsmconfig)) { - type = *cp; - length = cp[1]; - - if (type < 0 || type >= NCFTYPES) - snprintf(request, sizeof request, " <%d>[%d]", type, length); - else - snprintf(request, sizeof request, " %s[%d]", cftypes[type], length); - - switch (type) { - case TY_MRU: - sp = (u_short *) (cp + 2); - mru = htons(*sp); - LogPrintf(LogLCP, "%s %d\n", request, mru); - - switch (mode_type) { - case MODE_REQ: - mtu = VarPrefMTU; - if (mtu == 0) - mtu = MAX_MTU; - if (mru > mtu) { - *sp = htons(mtu); - memcpy(nakp, cp, 4); - nakp += 4; - } else if (mru < MIN_MRU) { - *sp = htons(MIN_MRU); - memcpy(nakp, cp, 4); - nakp += 4; - } else { - LcpInfo.his_mru = mru; - memcpy(ackp, cp, 4); - ackp += 4; - } - break; - case MODE_NAK: - if (mru >= MIN_MRU || mru <= MAX_MRU) - LcpInfo.want_mru = mru; - break; - case MODE_REJ: - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_ACCMAP: - lp = (u_int32_t *) (cp + 2); - accmap = htonl(*lp); - LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap); - - switch (mode_type) { - case MODE_REQ: - LcpInfo.his_accmap = accmap; - memcpy(ackp, cp, 6); - ackp += 6; - break; - case MODE_NAK: - LcpInfo.want_accmap = accmap; - break; - case MODE_REJ: - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_AUTHPROTO: - sp = (u_short *) (cp + 2); - proto = ntohs(*sp); - switch (proto) { - case PROTO_PAP: - LogPrintf(LogLCP, "%s 0x%04x (PAP)\n", request, proto); - break; - case PROTO_CHAP: - LogPrintf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]); - break; - default: - LogPrintf(LogLCP, "%s 0x%04x\n", request, proto); - break; - } - - switch (mode_type) { - case MODE_REQ: - switch (proto) { - case PROTO_PAP: - if (length != 4) { - LogPrintf(LogLCP, " Bad length!\n"); - goto reqreject; - } - if (Acceptable(ConfPap)) { - LcpInfo.his_auth = proto; - memcpy(ackp, cp, length); - ackp += length; - } else if (Acceptable(ConfChap)) { - *nakp++ = *cp; - *nakp++ = 5; - *nakp++ = (unsigned char) (PROTO_CHAP >> 8); - *nakp++ = (unsigned char) PROTO_CHAP; -#ifdef HAVE_DES - if (VarMSChap) - *nakp++ = 0x80; - else -#endif - *nakp++ = 5; - } else - goto reqreject; - break; - - case PROTO_CHAP: - if (length < 5) { - LogPrintf(LogLCP, " Bad length!\n"); - goto reqreject; - } -#ifdef HAVE_DES - if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80)) -#else - if (Acceptable(ConfChap) && cp[4] == 5) -#endif - { - LcpInfo.his_auth = proto; - memcpy(ackp, cp, length); - ackp += length; -#ifdef HAVE_DES - VarMSChap = cp[4] == 0x80; -#endif - } else if (Acceptable(ConfPap)) { - *nakp++ = *cp; - *nakp++ = 4; - *nakp++ = (unsigned char) (PROTO_PAP >> 8); - *nakp++ = (unsigned char) PROTO_PAP; - } else - goto reqreject; - break; - - default: - LogPrintf(LogLCP, "%s 0x%04x - not recognised, NAK\n", - request, proto); - memcpy(nakp, cp, length); - nakp += length; - break; - } - break; - case MODE_NAK: - switch (proto) { - case PROTO_PAP: - if (Enabled(ConfPap)) - LcpInfo.want_auth = PROTO_PAP; - else { - LogPrintf(LogLCP, "Peer will only send PAP (not enabled)\n"); - LcpInfo.his_reject |= (1 << type); - } - break; - case PROTO_CHAP: - if (Enabled(ConfChap)) - LcpInfo.want_auth = PROTO_CHAP; - else { - LogPrintf(LogLCP, "Peer will only send CHAP (not enabled)\n"); - LcpInfo.his_reject |= (1 << type); - } - break; - default: - /* We've been NAK'd with something we don't understand :-( */ - LcpInfo.his_reject |= (1 << type); - break; - } - break; - case MODE_REJ: - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_QUALPROTO: - req = (struct lqrreq *) cp; - LogPrintf(LogLCP, "%s proto %x, interval %dms\n", - request, ntohs(req->proto), ntohl(req->period) * 10); - switch (mode_type) { - case MODE_REQ: - if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) - goto reqreject; - else { - LcpInfo.his_lqrperiod = ntohl(req->period); - if (LcpInfo.his_lqrperiod < 500) - LcpInfo.his_lqrperiod = 500; - req->period = htonl(LcpInfo.his_lqrperiod); - memcpy(ackp, cp, length); - ackp += length; - } - break; - case MODE_NAK: - break; - case MODE_REJ: - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_MAGICNUM: - lp = (u_int32_t *) (cp + 2); - magic = ntohl(*lp); - LogPrintf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic); - - switch (mode_type) { - case MODE_REQ: - if (LcpInfo.want_magic) { - /* Validate magic number */ - if (magic == LcpInfo.want_magic) { - LogPrintf(LogLCP, "Magic is same (%08lx) - %d times\n", - (u_long)magic, ++LcpFailedMagic); - LcpInfo.want_magic = GenerateMagic(); - memcpy(nakp, cp, 6); - nakp += 6; - ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0); - sigpause(0); - } else { - LcpInfo.his_magic = magic; - memcpy(ackp, cp, length); - ackp += length; - LcpFailedMagic = 0; - } - } else { - LcpInfo.my_reject |= (1 << type); - goto reqreject; - } - break; - case MODE_NAK: - LogPrintf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic); - LcpInfo.want_magic = GenerateMagic(); - break; - case MODE_REJ: - LogPrintf(LogLCP, " Magic 0x%08x is REJected!\n", magic); - LcpInfo.want_magic = 0; - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_PROTOCOMP: - LogPrintf(LogLCP, "%s\n", request); - - switch (mode_type) { - case MODE_REQ: - if (Acceptable(ConfProtocomp)) { - LcpInfo.his_protocomp = 1; - memcpy(ackp, cp, 2); - ackp += 2; - } else { -#ifdef OLDMST - /* - * MorningStar before v1.3 needs NAK - */ - memcpy(nakp, cp, 2); - nakp += 2; -#else - memcpy(rejp, cp, 2); - rejp += 2; - LcpInfo.my_reject |= (1 << type); -#endif - } - break; - case MODE_NAK: - case MODE_REJ: - LcpInfo.want_protocomp = 0; - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_ACFCOMP: - LogPrintf(LogLCP, "%s\n", request); - switch (mode_type) { - case MODE_REQ: - if (Acceptable(ConfAcfcomp)) { - LcpInfo.his_acfcomp = 1; - memcpy(ackp, cp, 2); - ackp += 2; - } else { -#ifdef OLDMST - /* - * MorningStar before v1.3 needs NAK - */ - memcpy(nakp, cp, 2); - nakp += 2; -#else - memcpy(rejp, cp, 2); - rejp += 2; - LcpInfo.my_reject |= (1 << type); -#endif - } - break; - case MODE_NAK: - case MODE_REJ: - LcpInfo.want_acfcomp = 0; - LcpInfo.his_reject |= (1 << type); - break; - } - break; - - case TY_SDP: - LogPrintf(LogLCP, "%s\n", request); - switch (mode_type) { - case MODE_REQ: - case MODE_NAK: - case MODE_REJ: - break; - } - break; - - default: - sz = (sizeof desc - 2) / 2; - if (sz > length - 2) - sz = length - 2; - pos = 0; - desc[0] = sz ? ' ' : '\0'; - for (pos = 0; sz--; pos++) - sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]); - - LogPrintf(LogLCP, "%s%s\n", request, desc); - - if (mode_type == MODE_REQ) { -reqreject: - if (length > sizeof RejBuff - (rejp - RejBuff)) { - length = sizeof RejBuff - (rejp - RejBuff); - LogPrintf(LogLCP, "Can't REJ length %d - trunating to %d\n", - cp[1], length); - } - memcpy(rejp, cp, length); - rejp += length; - LcpInfo.my_reject |= (1 << type); - if (length != cp[1]) - return; - } - break; - } - /* to avoid inf. loop */ - if (length == 0) { - LogPrintf(LogLCP, "LCP size zero\n"); - break; - } - plen -= length; - cp += length; - } -} - -void -LcpInput(struct mbuf * bp) -{ - FsmInput(&LcpFsm, bp); -} diff --git a/usr.sbin/ppp/lcp.h b/usr.sbin/ppp/lcp.h deleted file mode 100644 index ca2d6edbc77..00000000000 --- a/usr.sbin/ppp/lcp.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: lcp.h,v 1.4 1998/01/11 17:54:47 brian Exp $ - * - * TODO: - */ - -#define REJECTED(p, x) ((p)->his_reject & (1<<(x))) - -struct lcpstate { - u_int16_t his_mru; - u_int32_t his_accmap; - u_int32_t his_magic; - u_int32_t his_lqrperiod; - u_char his_protocomp; - u_char his_acfcomp; - u_short his_auth; - - u_short want_mru; - u_int32_t want_accmap; - u_int32_t want_magic; - u_int32_t want_lqrperiod; - u_char want_protocomp; - u_char want_acfcomp; - u_short want_auth; - - u_int32_t his_reject; /* Request codes rejected by peer */ - u_int32_t my_reject; /* Request codes I have rejected */ - - u_short auth_iwait; - u_short auth_ineed; -}; - -#define LCP_MAXCODE CODE_DISCREQ - -#define TY_MRU 1 /* Maximum-Receive-Unit */ -#define TY_ACCMAP 2 /* Async-Control-Character-Map */ -#define TY_AUTHPROTO 3 /* Authentication-Protocol */ -#define TY_QUALPROTO 4 /* Quality-Protocol */ -#define TY_MAGICNUM 5 /* Magic-Number */ -#define TY_RESERVED 6 /* RESERVED */ -#define TY_PROTOCOMP 7 /* Protocol-Field-Compression */ -#define TY_ACFCOMP 8 /* Address-and-Control-Field-Compression */ -#define TY_FCSALT 9 /* FCS-Alternatives */ -#define TY_SDP 10 /* Self-Describing-Padding */ - -#define MAX_LCP_OPT_LEN 10 -struct lcp_opt { - u_char id; - u_char len; - u_char data[MAX_LCP_OPT_LEN-2]; -}; - - -extern struct lcpstate LcpInfo; -extern struct fsm LcpFsm; - -extern void LcpInit(void); -extern void LcpUp(void); -extern void LcpSendProtoRej(u_char *, int); -extern void LcpOpen(int); -extern void LcpClose(void); -extern void LcpDown(void); -extern int LcpPutConf(int, u_char *, const struct lcp_opt *, const char *, - const char *, ...); -extern int ReportLcpStatus(struct cmdargs const *); -extern void LcpInput(struct mbuf *); diff --git a/usr.sbin/ppp/libalias/HISTORY b/usr.sbin/ppp/libalias/HISTORY new file mode 100644 index 00000000000..3d97fd0803b --- /dev/null +++ b/usr.sbin/ppp/libalias/HISTORY @@ -0,0 +1,129 @@ +Version 1.0: August 11, 1996 (cjm) + +Version 1.1: August 20, 1996 (cjm) + - Host accepts incoming connections for ports 0 to 1023. + +Version 1.2: September 7, 1996 (cjm) + - Fragment handling error in alias_db.c corrected. + +Version 1.3: September 15, 1996 (cjm) + - Generalized mechanism for handling incoming + connections (no more 0 to 1023 restriction). + + - Increased ICMP support (will handle traceroute now). + + - Improved TCP close connection logic. + +Version 1.4: September 16, 1996 (cjm) + +Version 1.5: September 17, 1996 (cjm) + - Corrected error in handling incoming UDP packets + with zero checksum. + +Version 1.6: September 18, 1996 + - Simplified ICMP data storage. Will now handle + tracert from Win95 and NT as well as FreeBSD + traceroute, which uses UDP packets to non-existent + ports. + +Verstion 1.7: January 9, 1997 (cjm) + - Reduced malloc() activity for ICMP echo and + timestamp requests. + + - Added handling for out-of-order IP fragments. + + - Switched to differential checksum computation + for IP headers (TCP, UDP and ICMP checksums + were already differential). + + - Accepts FTP data connections from other than + port 20. This allows one ftp connections + from two hosts which are both running packet + aliasing. + + - Checksum error on FTP transfers. Problem + in code located by Martin Renters and + Brian Somers. + +Version 1.8: January 14, 1997 (cjm) + - Fixed data type error in function StartPoint() + in alias_db.c (this bug did not exist before v1.7) + Problem in code located by Ari Suutari. + +Version 1.9: February 1, 1997 (Eivind Eklund <perhaps@yes.no>) + - Added support for IRC DCC (ee) + + - Changed the aliasing routines to use ANSI style + throughout (ee) + + - Minor API changes for integration with other + programs than PPP (ee) + + - Fixed minor security hole in alias_ftp.c for + other applications of the aliasing software. + Hole could _not_ manifest in ppp+pktAlias, but + could potentially manifest in other applications + of the aliasing. (ee) + + - Connections initiated from packet aliasing + host machine will not have their port number + aliased unless it conflicts with an aliasing + port already being used. (There is an option + to disable this for debugging) (cjm) + + - Sockets will be allocated in cases where + there might be port interference with the + host machine. This can be disabled in cases + where the ppp host will be acting purely as a + masquerading router and not generate any + traffic of its own. + (cjm) + +Version 2.0: March, 1997 (cjm) + - Aliasing links are cleared only when a host interface address + changes. + + - PacketAliasPermanentLink() API added. + + - Option for only aliasing private, unregistered + IP addresses added. + + - Substantial rework to the aliasing lookup engine. + +Version 2.1: May, 1997 (cjm) + - Continuing rework to the aliasing lookup engine + to support multiple incoming addresses and static + NAT. PacketAliasRedirectPort() and + PacketAliasRedirectAddr() added to API. + + - Now supports outgoing as well as incoming ICMP + error messges. + +Version 2.2: July, 1997 (cjm) + - Rationalized API function names to all begin with + "PacketAlias..." Old function names are retained + for backwards compatitibility. + + - Packet aliasing engine will now free memory of + fragments which are never resolved after a timeout + period. Once a fragment is resolved, it becomes + the users responsibility to free the memory. + +Version 2.3: August 11, 1997 (cjm) + - Problem associated with socket file descriptor + accumulation in alias_db.c corrected. The sockets + had to be closed when a binding failed. Problem + in code located by Gordon Burditt. + +Version 2.4: September 1, 1997 (cjm) + - PKT_ALIAS_UNREGISTERED_ONLY option repaired. + This part of the code was incorrectly re-implemented + in version 2.1. + +Version 2.5: December, 1997 (ee) + - Added PKT_ALIAS_PUNCH_FW mode for firewall + bypass of FTP/IRC DCC data connections. Also added + improved TCP connection monitoring. + +Version 2.6: May, 1998 (amurai) + - Added supporting routine for NetBios over TCP/IP. diff --git a/usr.sbin/ppp/libalias/Makefile b/usr.sbin/ppp/libalias/Makefile new file mode 100644 index 00000000000..10f33d2d2b2 --- /dev/null +++ b/usr.sbin/ppp/libalias/Makefile @@ -0,0 +1,20 @@ +LIB= alias +CFLAGS+=-Wall -I${.CURDIR} +SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \ + alias_nbt.c alias_old.c alias_util.c + +OPSYS!= uname -s +.if (${OPSYS} == "OpenBSD") +MAN= libalias.3 +CFLAGS+= -DNO_FW_PUNCH +.else +SHLIB_MAJOR= 2 +SHLIB_MINOR= 5 +MAN3= libalias.3 + +beforeinstall: + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/alias.h \ + ${DESTDIR}/usr/include +.endif + +.include <bsd.lib.mk> diff --git a/usr.sbin/ppp/libalias/alias.c b/usr.sbin/ppp/libalias/alias.c new file mode 100644 index 00000000000..48a852a250f --- /dev/null +++ b/usr.sbin/ppp/libalias/alias.c @@ -0,0 +1,1154 @@ +/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */ +/* + Alias.c provides supervisory control for the functions of the + packet aliasing software. It consists of routines to monitor + TCP connection state, protocol-specific aliasing routines, + fragment handling and the following outside world functional + interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn, + PacketAliasIn and PacketAliasOut. + + The other C program files are briefly described. The data + structure framework which holds information needed to translate + packets is encapsulated in alias_db.c. Data is accessed by + function calls, so other segments of the program need not know + about the underlying data structures. Alias_ftp.c contains + special code for modifying the ftp PORT command used to establish + data connections, while alias_irc.c do the same for IRC + DCC. Alias_util.c contains a few utility routines. + + This software is placed into the public domain with no restrictions + on its distribution. + + Version 1.0 August, 1996 (cjm) + + Version 1.1 August 20, 1996 (cjm) + PPP host accepts incoming connections for ports 0 to 1023. + (Gary Roberts pointed out the need to handle incoming + connections.) + + Version 1.2 September 7, 1996 (cjm) + Fragment handling error in alias_db.c corrected. + (Tom Torrance helped fix this problem.) + + Version 1.4 September 16, 1996 (cjm) + - A more generalized method for handling incoming + connections, without the 0-1023 restriction, is + implemented in alias_db.c + - Improved ICMP support in alias.c. Traceroute + packet streams can now be correctly aliased. + - TCP connection closing logic simplified in + alias.c and now allows for additional 1 minute + "grace period" after FIN or RST is observed. + + Version 1.5 September 17, 1996 (cjm) + Corrected error in handling incoming UDP packets with 0 checksum. + (Tom Torrance helped fix this problem.) + + Version 1.6 September 18, 1996 (cjm) + Simplified ICMP aliasing scheme. Should now support + traceroute from Win95 as well as FreeBSD. + + Version 1.7 January 9, 1997 (cjm) + - Out-of-order fragment handling. + - IP checksum error fixed for ftp transfers + from aliasing host. + - Integer return codes added to all + aliasing/de-aliasing functions. + - Some obsolete comments cleaned up. + - Differential checksum computations for + IP header (TCP, UDP and ICMP were already + differential). + + Version 2.1 May 1997 (cjm) + - Added support for outgoing ICMP error + messages. + - Added two functions PacketAliasIn2() + and PacketAliasOut2() for dynamic address + control (e.g. round-robin allocation of + incoming packets). + + Version 2.2 July 1997 (cjm) + - Rationalized API function names to begin + with "PacketAlias..." + - Eliminated PacketAliasIn2() and + PacketAliasOut2() as poorly conceived. + + See HISTORY file for additional revisions. + +*/ + +#include <stdio.h> +#include <unistd.h> + +#include <sys/param.h> +#include <sys/types.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> + +#include "alias_local.h" +#include "alias.h" + +#define NETBIOS_NS_PORT_NUMBER 137 +#define NETBIOS_DGM_PORT_NUMBER 138 +#define FTP_CONTROL_PORT_NUMBER 21 +#define FTP_CONTROL_PORT_NUMBER 21 +#define IRC_CONTROL_PORT_NUMBER_1 6667 +#define IRC_CONTROL_PORT_NUMBER_2 6668 +#define CUSEEME_PORT_NUMBER 7648 + +/* + The following macro is used to update an + internet checksum. "delta" is a 32-bit + accumulation of all the changes to the + checksum (adding in new 16-bit words and + subtracting out old words), and "cksum" + is the checksum value to be updated. +*/ +#define ADJUST_CHECKSUM(acc, cksum) { \ + acc += cksum; \ + if (acc < 0) \ + { \ + acc = -acc; \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) ~acc; \ + } \ + else \ + { \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) acc; \ + } \ +} + + + + +/* TCP Handling Routines + + TcpMonitorIn() -- These routines monitor TCP connections, and + TcpMonitorOut() -- delete a link node when a connection is closed. + +These routines look for SYN, ACK and RST flags to determine when TCP +connections open and close. When a TCP connection closes, the data +structure containing packet aliasing information is deleted after +a timeout period. +*/ + +/* Local prototypes */ +static void TcpMonitorIn(struct ip *, struct alias_link *); + +static void TcpMonitorOut(struct ip *, struct alias_link *); + + +static void +TcpMonitorIn(struct ip *pip, struct alias_link *link) +{ + struct tcphdr *tc; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + + switch (GetStateIn(link)) + { + case ALIAS_TCP_STATE_NOT_CONNECTED: + if (tc->th_flags & TH_SYN) + SetStateIn(link, ALIAS_TCP_STATE_CONNECTED); + break; + case ALIAS_TCP_STATE_CONNECTED: + if (tc->th_flags & TH_FIN + || tc->th_flags & TH_RST) + SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); + break; + } +} + +static void +TcpMonitorOut(struct ip *pip, struct alias_link *link) +{ + struct tcphdr *tc; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + + switch (GetStateOut(link)) + { + case ALIAS_TCP_STATE_NOT_CONNECTED: + if (tc->th_flags & TH_SYN) + SetStateOut(link, ALIAS_TCP_STATE_CONNECTED); + break; + case ALIAS_TCP_STATE_CONNECTED: + if (tc->th_flags & TH_FIN + || tc->th_flags & TH_RST) + SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); + break; + } +} + + + + + +/* Protocol Specific Packet Aliasing Routines + + IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3() + IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3() + UdpAliasIn(), UdpAliasOut() + TcpAliasIn(), TcpAliasOut() + +These routines handle protocol specific details of packet aliasing. +One may observe a certain amount of repetitive arithmetic in these +functions, the purpose of which is to compute a revised checksum +without actually summing over the entire data packet, which could be +unnecessarily time consuming. + +The purpose of the packet aliasing routines is to replace the source +address of the outgoing packet and then correctly put it back for +any incoming packets. For TCP and UDP, ports are also re-mapped. + +For ICMP echo/timestamp requests and replies, the following scheme +is used: the id number is replaced by an alias for the outgoing +packet. + +ICMP error messages are handled by looking at the IP fragment +in the data section of the message. + +For TCP and UDP protocols, a port number is chosen for an outgoing +packet, and then incoming packets are identified by IP address and +port numbers. For TCP packets, there is additional logic in the event +that sequence and ack numbers have been altered (as is the case for +FTP data port commands). + +The port numbers used by the packet aliasing module are not true +ports in the Unix sense. No sockets are actually bound to ports. +They are more correctly thought of as placeholders. + +All packets go through the aliasing mechanism, whether they come from +the gateway machine or other machines on a local area network. +*/ + + +/* Local prototypes */ +static int IcmpAliasIn1(struct ip *); +static int IcmpAliasIn2(struct ip *); +static int IcmpAliasIn3(struct ip *); +static int IcmpAliasIn (struct ip *); + +static int IcmpAliasOut1(struct ip *); +static int IcmpAliasOut2(struct ip *); +static int IcmpAliasOut3(struct ip *); +static int IcmpAliasOut (struct ip *); + +static int UdpAliasOut(struct ip *); +static int UdpAliasIn (struct ip *); + +static int TcpAliasOut(struct ip *, int); +static int TcpAliasIn (struct ip *); + + +static int +IcmpAliasIn1(struct ip *pip) +{ +/* + De-alias incoming echo and timestamp replies +*/ + struct alias_link *link; + struct icmp *ic; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + +/* Get source address from ICMP data field and restore original data */ + link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id); + if (link != NULL) + { + u_short original_id; + int accumulate; + + original_id = GetOriginalPort(link); + +/* Adjust ICMP checksum */ + accumulate = ic->icmp_id; + accumulate -= original_id; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + +/* Put original sequence number back in */ + ic->icmp_id = original_id; + +/* Put original address back into IP header */ + { + struct in_addr original_address; + + original_address = GetOriginalAddress(link); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + } + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + +static int +IcmpAliasIn2(struct ip *pip) +{ +/* + Alias incoming ICMP error messages containing + IP header and first 64 bits of datagram. +*/ + struct ip *ip; + struct icmp *ic, *ic2; + struct udphdr *ud; + struct tcphdr *tc; + struct alias_link *link; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + ip = (struct ip *) ic->icmp_data; + + ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); + tc = (struct tcphdr *) ud; + ic2 = (struct icmp *) ud; + + if (ip->ip_p == IPPROTO_UDP) + link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, + ud->uh_dport, ud->uh_sport, + IPPROTO_UDP); + else if (ip->ip_p == IPPROTO_TCP) + link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, + tc->th_dport, tc->th_sport, + IPPROTO_TCP); + else if (ip->ip_p == IPPROTO_ICMP) { + if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) + link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id); + else + link = NULL; + } else + link = NULL; + + if (link != NULL) + { + if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) + { + u_short *sptr; + int accumulate; + struct in_addr original_address; + u_short original_port; + + original_address = GetOriginalAddress(link); + original_port = GetOriginalPort(link); + +/* Adjust ICMP checksum */ + sptr = (u_short *) &(ip->ip_src); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + accumulate += ud->uh_sport; + accumulate -= original_port; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + +/* Un-alias address in IP header */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + +/* Un-alias address and port number of original IP packet +fragment contained in ICMP data section */ + ip->ip_src = original_address; + ud->uh_sport = original_port; + } + else if (pip->ip_p == IPPROTO_ICMP) + { + u_short *sptr; + int accumulate; + struct in_addr original_address; + u_short original_id; + + original_address = GetOriginalAddress(link); + original_id = GetOriginalPort(link); + +/* Adjust ICMP checksum */ + sptr = (u_short *) &(ip->ip_src); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + accumulate += ic2->icmp_id; + accumulate -= original_id; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + +/* Un-alias address in IP header */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + +/* Un-alias address of original IP packet and seqence number of + embedded icmp datagram */ + ip->ip_src = original_address; + ic2->icmp_id = original_id; + } + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + + +static int +IcmpAliasIn3(struct ip *pip) +{ + struct in_addr original_address; + + original_address = FindOriginalAddress(pip->ip_dst); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + + return PKT_ALIAS_OK; +} + + +static int +IcmpAliasIn(struct ip *pip) +{ + int iresult; + struct icmp *ic; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + + iresult = PKT_ALIAS_IGNORED; + switch (ic->icmp_type) + { + case ICMP_ECHOREPLY: + case ICMP_TSTAMPREPLY: + if (ic->icmp_code == 0) + { + iresult = IcmpAliasIn1(pip); + } + break; + case ICMP_UNREACH: + case ICMP_SOURCEQUENCH: + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + iresult = IcmpAliasIn2(pip); + break; + case ICMP_ECHO: + case ICMP_TSTAMP: + iresult = IcmpAliasIn3(pip); + break; + } + return(iresult); +} + + +static int +IcmpAliasOut1(struct ip *pip) +{ +/* + Alias ICMP echo and timestamp packets +*/ + struct alias_link *link; + struct icmp *ic; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + +/* Save overwritten data for when echo packet returns */ + link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id); + if (link != NULL) + { + u_short alias_id; + int accumulate; + + alias_id = GetAliasPort(link); + +/* Since data field is being modified, adjust ICMP checksum */ + accumulate = ic->icmp_id; + accumulate -= alias_id; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + +/* Alias sequence number */ + ic->icmp_id = alias_id; + +/* Change source address */ + { + struct in_addr alias_address; + + alias_address = GetAliasAddress(link); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + } + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + + +static int +IcmpAliasOut2(struct ip *pip) +{ +/* + Alias outgoing ICMP error messages containing + IP header and first 64 bits of datagram. +*/ + struct in_addr alias_addr; + struct ip *ip; + struct icmp *ic; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + ip = (struct ip *) ic->icmp_data; + + alias_addr = FindAliasAddress(ip->ip_src); + +/* Alias destination address in IP fragment */ + DifferentialChecksum(&ic->icmp_cksum, + (u_short *) &alias_addr, + (u_short *) &ip->ip_dst, + 2); + ip->ip_dst = alias_addr; + +/* alias source address in IP header */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_addr, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_addr; + + return PKT_ALIAS_OK; +} + + +static int +IcmpAliasOut3(struct ip *pip) +{ +/* + Handle outgoing echo and timestamp replies. The + only thing which is done in this case is to alias + the source IP address of the packet. +*/ + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(pip->ip_src); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_addr, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_addr; + + return PKT_ALIAS_OK; +} + + +static int +IcmpAliasOut(struct ip *pip) +{ + int iresult; + struct icmp *ic; + + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); + + iresult = PKT_ALIAS_IGNORED; + switch (ic->icmp_type) + { + case ICMP_ECHO: + case ICMP_TSTAMP: + if (ic->icmp_code == 0) + { + iresult = IcmpAliasOut1(pip); + } + break; + case ICMP_UNREACH: + case ICMP_SOURCEQUENCH: + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + iresult = IcmpAliasOut2(pip); + break; + case ICMP_ECHOREPLY: + case ICMP_TSTAMPREPLY: + iresult = IcmpAliasOut3(pip); + } + return(iresult); +} + +static int +UdpAliasIn(struct ip *pip) +{ + struct udphdr *ud; + struct alias_link *link; + + ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); + + link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, + ud->uh_sport, ud->uh_dport, + IPPROTO_UDP); + if (link != NULL) + { + struct in_addr alias_address; + struct in_addr original_address; + u_short alias_port; + int accumulate; + u_short *sptr; + + alias_address = GetAliasAddress(link); + original_address = GetOriginalAddress(link); + alias_port = ud->uh_dport; + ud->uh_dport = GetOriginalPort(link); + +/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ + if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) + { + AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport); + } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) + { + AliasHandleUdpNbtNS(pip, link, + &alias_address, + &alias_port, + &original_address, + &ud->uh_dport ); + } + + if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) + AliasHandleCUSeeMeIn(pip, original_address); + +/* If UDP checksum is not zero, then adjust since destination port */ +/* is being unaliased and destination port is being altered. */ + if (ud->uh_sum != 0) + { + accumulate = alias_port; + accumulate -= ud->uh_dport; + sptr = (u_short *) &alias_address; + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + ADJUST_CHECKSUM(accumulate, ud->uh_sum) + } + +/* Restore original IP address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + +static int +UdpAliasOut(struct ip *pip) +{ + struct udphdr *ud; + struct alias_link *link; + + ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); + + link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, + ud->uh_sport, ud->uh_dport, + IPPROTO_UDP); + if (link != NULL) + { + u_short alias_port; + struct in_addr alias_address; + + alias_address = GetAliasAddress(link); + alias_port = GetAliasPort(link); + + if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) + AliasHandleCUSeeMeOut(pip, link); + +/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ + if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) + { + AliasHandleUdpNbt(pip, link, &alias_address, alias_port); + } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) + { + AliasHandleUdpNbtNS(pip, link, + &pip->ip_src, + &ud->uh_sport, + &alias_address, + &alias_port); + } + +/* If UDP checksum is not zero, adjust since source port is */ +/* being aliased and source address is being altered */ + if (ud->uh_sum != 0) + { + int accumulate; + u_short *sptr; + + accumulate = ud->uh_sport; + accumulate -= alias_port; + sptr = (u_short *) &(pip->ip_src); + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &alias_address; + accumulate -= *sptr++; + accumulate -= *sptr; + ADJUST_CHECKSUM(accumulate, ud->uh_sum) + } + +/* Put alias port in UDP header */ + ud->uh_sport = alias_port; + +/* Change source address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + + + +static int +TcpAliasIn(struct ip *pip) +{ + struct tcphdr *tc; + struct alias_link *link; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + + link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, + tc->th_sport, tc->th_dport, + IPPROTO_TCP); + if (link != NULL) + { + struct in_addr alias_address; + struct in_addr original_address; + u_short alias_port; + int accumulate; + u_short *sptr; + + alias_address = GetAliasAddress(link); + original_address = GetOriginalAddress(link); + alias_port = tc->th_dport; + tc->th_dport = GetOriginalPort(link); + +/* Adjust TCP checksum since destination port is being unaliased */ +/* and destination port is being altered. */ + accumulate = alias_port; + accumulate -= tc->th_dport; + sptr = (u_short *) &alias_address; + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + +/* See if ack number needs to be modified */ + if (GetAckModified(link) == 1) + { + int delta; + + delta = GetDeltaAckIn(pip, link); + if (delta != 0) + { + sptr = (u_short *) &tc->th_ack; + accumulate += *sptr++; + accumulate += *sptr; + tc->th_ack = htonl(ntohl(tc->th_ack) - delta); + sptr = (u_short *) &tc->th_ack; + accumulate -= *sptr++; + accumulate -= *sptr; + } + } + + ADJUST_CHECKSUM(accumulate, tc->th_sum); + +/* Restore original IP address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + +/* Monitor TCP connection state */ + TcpMonitorIn(pip, link); + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + +static int +TcpAliasOut(struct ip *pip, int maxpacketsize) +{ + struct tcphdr *tc; + struct alias_link *link; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + + link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, + tc->th_sport, tc->th_dport, + IPPROTO_TCP); + if (link !=NULL) + { + struct in_addr alias_address; + u_short alias_port; + int accumulate; + u_short *sptr; + + alias_port = GetAliasPort(link); + alias_address = GetAliasAddress(link); + +/* Monitor tcp connection state */ + TcpMonitorOut(pip, link); + +/* Special processing for ftp connection */ + if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER + || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER) + AliasHandleFtpOut(pip, link, maxpacketsize); + if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 + || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2) + AliasHandleIrcOut(pip, link, maxpacketsize); + +/* Adjust TCP checksum since source port is being aliased */ +/* and source address is being altered */ + accumulate = tc->th_sport; + accumulate -= alias_port; + sptr = (u_short *) &(pip->ip_src); + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &alias_address; + accumulate -= *sptr++; + accumulate -= *sptr; + +/* Modify sequence number if necessary */ + if (GetAckModified(link) == 1) + { + int delta; + + delta = GetDeltaSeqOut(pip, link); + if (delta != 0) + { + sptr = (u_short *) &tc->th_seq; + accumulate += *sptr++; + accumulate += *sptr; + tc->th_seq = htonl(ntohl(tc->th_seq) + delta); + sptr = (u_short *) &tc->th_seq; + accumulate -= *sptr++; + accumulate -= *sptr; + } + } + + ADJUST_CHECKSUM(accumulate, tc->th_sum) + +/* Put alias address in TCP header */ + tc->th_sport = alias_port; + +/* Change source address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} + + + + +/* Fragment Handling + + FragmentIn() + FragmentOut() + +The packet aliasing module has a limited ability for handling IP +fragments. If the ICMP, TCP or UDP header is in the first fragment +received, then the id number of the IP packet is saved, and other +fragments are identified according to their ID number and IP address +they were sent from. Pointers to unresolved fragments can also be +saved and recalled when a header fragment is seen. +*/ + +/* Local prototypes */ +static int FragmentIn(struct ip *); +static int FragmentOut(struct ip *); + + +static int +FragmentIn(struct ip *pip) +{ + struct alias_link *link; + + link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id); + if (link != NULL) + { + struct in_addr original_address; + + GetFragmentAddr(link, &original_address); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_UNRESOLVED_FRAGMENT); +} + + +static int +FragmentOut(struct ip *pip) +{ + struct in_addr alias_address; + + alias_address = FindAliasAddress(pip->ip_src); + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + + return(PKT_ALIAS_OK); +} + + + + + + +/* Outside World Access + + PacketAliasSaveFragment() + PacketAliasGetFragment() + PacketAliasFragmentIn() + PacketAliasIn() + PacketAliasOut() + +(prototypes in alias.h) +*/ + + +int +PacketAliasSaveFragment(char *ptr) +{ + int iresult; + struct alias_link *link; + struct ip *pip; + + pip = (struct ip *) ptr; + link = AddFragmentPtrLink(pip->ip_src, pip->ip_id); + iresult = PKT_ALIAS_ERROR; + if (link != NULL) + { + SetFragmentPtr(link, ptr); + iresult = PKT_ALIAS_OK; + } + return(iresult); +} + + +char * +PacketAliasGetFragment(char *ptr) +{ + struct alias_link *link; + char *fptr; + struct ip *pip; + + pip = (struct ip *) ptr; + link = FindFragmentPtr(pip->ip_src, pip->ip_id); + if (link != NULL) + { + GetFragmentPtr(link, &fptr); + SetFragmentPtr(link, NULL); + SetExpire(link, 0); /* Deletes link */ + + return(fptr); + } + else + { + return(NULL); + } +} + + +void +PacketAliasFragmentIn(char *ptr, /* Points to correctly de-aliased + header fragment */ + char *ptr_fragment /* Points to fragment which must + be de-aliased */ + ) +{ + struct ip *pip; + struct ip *fpip; + + pip = (struct ip *) ptr; + fpip = (struct ip *) ptr_fragment; + + DifferentialChecksum(&fpip->ip_sum, + (u_short *) &pip->ip_dst, + (u_short *) &fpip->ip_dst, + 2); + fpip->ip_dst = pip->ip_dst; +} + + +int +PacketAliasIn(char *ptr, int maxpacketsize) +{ + struct in_addr alias_addr; + struct ip *pip; + int iresult; + + HouseKeeping(); + ClearCheckNewLink(); + pip = (struct ip *) ptr; + alias_addr = pip->ip_dst; + + /* Defense against mangled packets */ + if (ntohs(pip->ip_len) > maxpacketsize + || (pip->ip_hl<<2) > maxpacketsize) + return PKT_ALIAS_IGNORED; + + iresult = PKT_ALIAS_IGNORED; + if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 ) + { + switch (pip->ip_p) + { + case IPPROTO_ICMP: + iresult = IcmpAliasIn(pip); + break; + case IPPROTO_UDP: + iresult = UdpAliasIn(pip); + break; + case IPPROTO_TCP: + iresult = TcpAliasIn(pip); + break; + } + + if (ntohs(pip->ip_off) & IP_MF) + { + struct alias_link *link; + + link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id); + if (link != NULL) + { + iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; + SetFragmentAddr(link, pip->ip_dst); + } + else + { + iresult = PKT_ALIAS_ERROR; + } + } + } + else + { + iresult = FragmentIn(pip); + } + + return(iresult); +} + + + +/* Unregistered address ranges */ + +/* 10.0.0.0 -> 10.255.255.255 */ +#define UNREG_ADDR_A_LOWER 0x0a000000 +#define UNREG_ADDR_A_UPPER 0x0affffff + +/* 172.16.0.0 -> 172.31.255.255 */ +#define UNREG_ADDR_B_LOWER 0xac100000 +#define UNREG_ADDR_B_UPPER 0xac1fffff + +/* 192.168.0.0 -> 192.168.255.255 */ +#define UNREG_ADDR_C_LOWER 0xc0a80000 +#define UNREG_ADDR_C_UPPER 0xc0a8ffff + + + +int +PacketAliasOut(char *ptr, /* valid IP packet */ + int maxpacketsize /* How much the packet data may grow + (FTP and IRC inline changes) */ + ) +{ + int iresult; + struct in_addr addr_save; + struct ip *pip; + + HouseKeeping(); + ClearCheckNewLink(); + pip = (struct ip *) ptr; + + /* Defense against mangled packets */ + if (ntohs(pip->ip_len) > maxpacketsize + || (pip->ip_hl<<2) > maxpacketsize) + return PKT_ALIAS_IGNORED; + + addr_save = GetDefaultAliasAddress(); + if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) + { + unsigned int addr; + int iclass; + + iclass = 0; + addr = ntohl(pip->ip_src.s_addr); + if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) + iclass = 3; + else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) + iclass = 2; + else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) + iclass = 1; + + if (iclass == 0) + { + SetDefaultAliasAddress(pip->ip_src); + } + } + + iresult = PKT_ALIAS_IGNORED; + if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) + { + switch (pip->ip_p) + { + case IPPROTO_ICMP: + iresult = IcmpAliasOut(pip); + break; + case IPPROTO_UDP: + iresult = UdpAliasOut(pip); + break; + case IPPROTO_TCP: + iresult = TcpAliasOut(pip, maxpacketsize); + break; + } + } + else + { + iresult = FragmentOut(pip); + } + + SetDefaultAliasAddress(addr_save); + return(iresult); +} diff --git a/usr.sbin/ppp/libalias/alias.h b/usr.sbin/ppp/libalias/alias.h new file mode 100644 index 00000000000..fa5f17230e9 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias.h @@ -0,0 +1,173 @@ +/*lint -save -library Flexelint comment for external headers */ + +/* + Alias.h defines the outside world interfaces for the packet + aliasing software. + + This software is placed into the public domain with no restrictions + on its distribution. + + $Id: alias.h,v 1.3 1998/08/31 00:22:03 brian Exp $ +*/ + + +#ifndef _ALIAS_H_ +#define _ALIAS_H_ + +#ifndef NULL +#define NULL 0 +#endif + +/* Alias link representative (incomplete struct) */ +struct alias_link; + +/* External interfaces (API) to packet aliasing engine */ + +/* Initialization and Control */ + extern void + PacketAliasInit(void); + + extern void + PacketAliasUninit(void); + + extern void + PacketAliasSetAddress(struct in_addr); + + extern unsigned int + PacketAliasSetMode(unsigned int, unsigned int); + +#ifndef NO_FW_PUNCH + extern void + PacketAliasSetFWBase(unsigned int, unsigned int); +#endif + +/* Packet Handling */ + extern int + PacketAliasIn(char *, int maxpacketsize); + + extern int + PacketAliasOut(char *, int maxpacketsize); + +/* Port and Address Redirection */ + extern struct alias_link * + PacketAliasRedirectPort(struct in_addr, u_short, + struct in_addr, u_short, + struct in_addr, u_short, + u_char); + + extern struct alias_link * + PacketAliasRedirectAddr(struct in_addr, + struct in_addr); + + extern void + PacketAliasRedirectDelete(struct alias_link *); + +/* Fragment Handling */ + extern int + PacketAliasSaveFragment(char *); + + extern char * + PacketAliasGetFragment(char *); + + extern void + PacketAliasFragmentIn(char *, char *); + +/* Miscellaneous Functions */ + extern void + PacketAliasSetTarget(struct in_addr addr); + + extern int + PacketAliasCheckNewLink(void); + + extern u_short + PacketAliasInternetChecksum(u_short *, int); + + +/* + In version 2.2, the function names were rationalized + to all be of the form PacketAlias... These are the + old function names for backwards compatibility +*/ +extern int SaveFragmentPtr(char *); +extern char *GetNextFragmentPtr(char *); +extern void FragmentAliasIn(char *, char *); +extern void SetPacketAliasAddress(struct in_addr); +extern void InitPacketAlias(void); +extern unsigned int SetPacketAliasMode(unsigned int, unsigned int); +extern int PacketAliasIn2(char *, struct in_addr, int maxpacketsize); +extern int PacketAliasOut2(char *, struct in_addr, int maxpacketsize); +extern int +PacketAliasPermanentLink(struct in_addr, u_short, + struct in_addr, u_short, + u_short, u_char); +extern u_short InternetChecksum(u_short *, int); + +/* Obsolete constant */ +#define PKT_ALIAS_NEW_LINK 5 + +/********************** Mode flags ********************/ +/* Set these flags using SetPacketAliasMode() */ + +/* If PKT_ALIAS_LOG is set, a message will be printed to + /var/log/alias.log every time a link is created or deleted. This + is useful for debugging */ +#define PKT_ALIAS_LOG 0x01 + +/* If PKT_ALIAS_DENY_INCOMING is set, then incoming connections (e.g. + to ftp, telnet or web servers will be prevented by the aliasing + mechanism. */ +#define PKT_ALIAS_DENY_INCOMING 0x02 + +/* If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from + the same port as they originated on. This allows eg rsh to work + *99% of the time*, but _not_ 100%. (It will be slightly flakey + instead of not working at all.) This mode bit is set by + PacketAliasInit(), so it is a default mode of operation. */ +#define PKT_ALIAS_SAME_PORTS 0x04 + +/* If PKT_ALIAS_USE_SOCKETS is set, then when partially specified + links (e.g. destination port and/or address is zero), the packet + aliasing engine will attempt to allocate a socket for the aliasing + port it chooses. This will avoid interference with the host + machine. Fully specified links do not require this. This bit + is set after a call to PacketAliasInit(), so it is a default + mode of operation.*/ +#define PKT_ALIAS_USE_SOCKETS 0x08 + +/* If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with with + unregistered source addresses will be aliased (along with those + of the ppp host maching itself. Private addresses are those + in the following ranges: + + 10.0.0.0 -> 10.255.255.255 + 172.16.0.0 -> 172.31.255.255 + 192.168.0.0 -> 192.168.255.255 */ +#define PKT_ALIAS_UNREGISTERED_ONLY 0x10 + +/* If PKT_ALIAS_RESET_ON_ADDR_CHANGE is set, then the table of dynamic + aliasing links will be reset whenever PacketAliasSetAddress() + changes the default aliasing address. If the default aliasing + address is left unchanged by this functions call, then the + table of dynamic aliasing links will be left intact. This + bit is set after a call to PacketAliasInit(). */ +#define PKT_ALIAS_RESET_ON_ADDR_CHANGE 0x20 + +#ifndef NO_FW_PUNCH +/* If PKT_ALIAS_PUNCH_FW is set, active FTP and IRC DCC connections + will create a 'hole' in the firewall to allow the transfers to + work. Where (IPFW "line-numbers") the hole is created is + controlled by PacketAliasSetFWBase(base, size). The hole will be + attached to that particular alias_link, so when the link goes away + so do the hole. */ +#define PKT_ALIAS_PUNCH_FW 0x40 +#endif + +/* Return Codes */ +#define PKT_ALIAS_ERROR -1 +#define PKT_ALIAS_OK 1 +#define PKT_ALIAS_IGNORED 2 +#define PKT_ALIAS_UNRESOLVED_FRAGMENT 3 +#define PKT_ALIAS_FOUND_HEADER_FRAGMENT 4 + +#endif +/*lint -restore */ diff --git a/usr.sbin/ppp/libalias/alias_cuseeme.c b/usr.sbin/ppp/libalias/alias_cuseeme.c new file mode 100644 index 00000000000..12feaa241a1 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_cuseeme.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * with the aid of code written by + * Junichi SATOH <junichi@astec.co.jp> 1996, 1997. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: alias_cuseeme.c,v 1.1 1998/08/31 00:22:04 brian Exp $ + */ + +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> + +#include "alias_local.h" + +/* CU-SeeMe Data Header */ +struct cu_header { + u_int16_t dest_family; + u_int16_t dest_port; + u_int32_t dest_addr; + int16_t family; + u_int16_t port; + u_int32_t addr; + u_int32_t seq; + u_int16_t msg; + u_int16_t data_type; + u_int16_t packet_len; +}; + +/* Open Continue Header */ +struct oc_header { + u_int16_t client_count; /* Number of client info structs */ + u_int32_t seq_no; + char user_name[20]; + char reserved[4]; /* flags, version stuff, etc */ +}; + +/* client info structures */ +struct client_info { + u_int32_t address; /* Client address */ + char reserved[8]; /* Flags, pruning bitfield, packet counts etc */ +}; + +void +AliasHandleCUSeeMeOut(struct ip *pip, struct alias_link *link) +{ + struct udphdr *ud; + + ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); + if(ud->uh_ulen >= sizeof(struct cu_header)) { + struct cu_header *cu; + struct alias_link *cu_link; + + cu = (struct cu_header *)(ud + 1); + if (cu->addr) + cu->addr = (u_int32_t)GetAliasAddress(link).s_addr; + + cu_link = FindUdpTcpOut(pip->ip_src, GetDestAddress(link), + ud->uh_dport, 0, IPPROTO_UDP); + +#ifndef NO_FW_PUNCH + if (cu_link) + PunchFWHole(cu_link); +#endif + } +} + +void +AliasHandleCUSeeMeIn(struct ip *pip, struct in_addr original_addr) +{ + struct in_addr alias_addr; + struct udphdr *ud; + struct cu_header *cu; + struct oc_header *oc; + struct client_info *ci; + char *end; + int i; + + alias_addr.s_addr = pip->ip_dst.s_addr; + ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); + cu = (struct cu_header *)(ud + 1); + oc = (struct oc_header *)(cu + 1); + ci = (struct client_info *)(oc + 1); + end = (char *)cu + ud->uh_ulen; + + if ((char *)oc <= end) { + if(cu->dest_addr) + cu->dest_addr = (u_int32_t)original_addr.s_addr; + if(ntohs(cu->data_type) == 101) + /* Find and change our address */ + for(i = 0; (char *)(ci + 1) <= end && i < oc->client_count; i++, ci++) + if(ci->address == (u_int32_t)alias_addr.s_addr) { + ci->address = (u_int32_t)original_addr.s_addr; + break; + } + } +} diff --git a/usr.sbin/ppp/libalias/alias_db.c b/usr.sbin/ppp/libalias/alias_db.c new file mode 100644 index 00000000000..7bbb19122be --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_db.c @@ -0,0 +1,2239 @@ +/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- + Alias_db.c encapsulates all data structures used for storing + packet aliasing data. Other parts of the aliasing software + access data through functions provided in this file. + + Data storage is based on the notion of a "link", which is + established for ICMP echo/reply packets, UDP datagrams and + TCP stream connections. A link stores the original source + and destination addresses. For UDP and TCP, it also stores + source and destination port numbers, as well as an alias + port number. Links are also used to store information about + fragments. + + There is a facility for sweeping through and deleting old + links as new packets are sent through. A simple timeout is + used for ICMP and UDP links. TCP links are left alone unless + there is an incomplete connection, in which case the link + can be deleted after a certain amount of time. + + + This software is placed into the public domain with no restrictions + on its distribution. + + Initial version: August, 1996 (cjm) + + Version 1.4: September 16, 1996 (cjm) + Facility for handling incoming links added. + + Version 1.6: September 18, 1996 (cjm) + ICMP data handling simplified. + + Version 1.7: January 9, 1997 (cjm) + Fragment handling simplified. + Saves pointers for unresolved fragments. + Permits links for unspecied remote ports + or unspecified remote addresses. + Fixed bug which did not properly zero port + table entries after a link was deleted. + Cleaned up some obsolete comments. + + Version 1.8: January 14, 1997 (cjm) + Fixed data type error in StartPoint(). + (This error did not exist prior to v1.7 + and was discovered and fixed by Ari Suutari) + + Version 1.9: February 1, 1997 + Optionally, connections initiated from packet aliasing host + machine will will not have their port number aliased unless it + conflicts with an aliasing port already being used. (cjm) + + All options earlier being #ifdef'ed now are available through + a new interface, SetPacketAliasMode(). This allow run time + control (which is now available in PPP+pktAlias through the + 'alias' keyword). (ee) + + Added ability to create an alias port without + either destination address or port specified. + port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) + + Removed K&R style function headers + and general cleanup. (ee) + + Added packetAliasMode to replace compiler #defines's (ee) + + Allocates sockets for partially specified + ports if ALIAS_USE_SOCKETS defined. (cjm) + + Version 2.0: March, 1997 + SetAliasAddress() will now clean up alias links + if the aliasing address is changed. (cjm) + + PacketAliasPermanentLink() function added to support permanent + links. (J. Fortes suggested the need for this.) + Examples: + + (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port + + (192.168.0.2, port 21) <-> alias port 3604, known dest addr + unknown dest port + + These permament links allow for incoming connections to + machines on the local network. They can be given with a + user-chosen amount of specificity, with increasing specificity + meaning more security. (cjm) + + Quite a bit of rework to the basic engine. The portTable[] + array, which kept track of which ports were in use was replaced + by a table/linked list structure. (cjm) + + SetExpire() function added. (cjm) + + DeleteLink() no longer frees memory association with a pointer + to a fragment (this bug was first recognized by E. Eklund in + v1.9). + + Version 2.1: May, 1997 (cjm) + Packet aliasing engine reworked so that it can handle + multiple external addresses rather than just a single + host address. + + PacketAliasRedirectPort() and PacketAliasRedirectAddr() + added to the API. The first function is a more generalized + version of PacketAliasPermanentLink(). The second function + implements static network address translation. + + See HISTORY file for additional revisions. +*/ + + +/* System include files */ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> + +/* BSD network include files */ +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> + +#include "alias.h" +#include "alias_local.h" + + + +/* + Constants (note: constants are also defined + near relevant functions or structs) +*/ + +/* Sizes of input and output link tables */ +#define LINK_TABLE_OUT_SIZE 101 +#define LINK_TABLE_IN_SIZE 4001 + +/* Parameters used for cleanup of expired links */ +#define ALIAS_CLEANUP_INTERVAL_SECS 60 +#define ALIAS_CLEANUP_MAX_SPOKES 30 + +/* Timouts (in seconds) for different link types) */ +#define ICMP_EXPIRE_TIME 60 +#define UDP_EXPIRE_TIME 60 +#define FRAGMENT_ID_EXPIRE_TIME 10 +#define FRAGMENT_PTR_EXPIRE_TIME 30 + +/* TCP link expire time for different cases */ +/* When the link has been used and closed - minimal grace time to + allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ +#ifndef TCP_EXPIRE_DEAD +# define TCP_EXPIRE_DEAD 10 +#endif + +/* When the link has been used and closed on one side - the other side + is allowed to still send data */ +#ifndef TCP_EXPIRE_SINGLEDEAD +# define TCP_EXPIRE_SINGLEDEAD 90 +#endif + +/* When the link isn't yet up */ +#ifndef TCP_EXPIRE_INITIAL +# define TCP_EXPIRE_INITIAL 300 +#endif + +/* When the link is up */ +#ifndef TCP_EXPIRE_CONNECTED +# define TCP_EXPIRE_CONNECTED 86400 +#endif + + +/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). + These constants can be anything except zero, which indicates an + unknown port numbea. */ + +#define NO_DEST_PORT 1 +#define NO_SRC_PORT 1 + + + +/* Data Structures + + The fundamental data structure used in this program is + "struct alias_link". Whenever a TCP connection is made, + a UDP datagram is sent out, or an ICMP echo request is made, + a link record is made (if it has not already been created). + The link record is identified by the source address/port + and the destination address/port. In the case of an ICMP + echo request, the source port is treated as being equivalent + with the 16-bit id number of the ICMP packet. + + The link record also can store some auxiliary data. For + TCP connections that have had sequence and acknowledgment + modifications, data space is available to track these changes. + A state field is used to keep track in changes to the tcp + connection state. Id numbers of fragments can also be + stored in the auxiliary space. Pointers to unresolved + framgents can also be stored. + + The link records support two independent chainings. Lookup + tables for input and out tables hold the initial pointers + the link chains. On input, the lookup table indexes on alias + port and link type. On output, the lookup table indexes on + source addreess, destination address, source port, destination + port and link type. +*/ + +struct ack_data_record /* used to save changes to ack/seq numbers */ +{ + u_long ack_old; + u_long ack_new; + int delta; + int active; +}; + +struct tcp_state /* Information about tcp connection */ +{ + int in; /* State for outside -> inside */ + int out; /* State for inside -> outside */ + int index; /* Index to ack data array */ + int ack_modified; /* Indicates whether ack and seq numbers */ + /* been modified */ +}; + +#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes + saved for a modified TCP stream */ +struct tcp_dat +{ + struct tcp_state state; + struct ack_data_record ack[N_LINK_TCP_DATA]; + int fwhole; /* Which firewall record is used for this hole? */ +}; + +struct alias_link /* Main data structure */ +{ + struct in_addr src_addr; /* Address and port information */ + struct in_addr dst_addr; /* . */ + struct in_addr alias_addr; /* . */ + u_short src_port; /* . */ + u_short dst_port; /* . */ + u_short alias_port; /* . */ + + int link_type; /* Type of link: tcp, udp, icmp, frag */ + +/* values for link_type */ +#define LINK_ICMP 1 +#define LINK_UDP 2 +#define LINK_TCP 3 +#define LINK_FRAGMENT_ID 4 +#define LINK_FRAGMENT_PTR 5 +#define LINK_ADDR 6 + + int flags; /* indicates special characteristics */ + +/* flag bits */ +#define LINK_UNKNOWN_DEST_PORT 0x01 +#define LINK_UNKNOWN_DEST_ADDR 0x02 +#define LINK_PERMANENT 0x04 +#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ +#define LINK_UNFIREWALLED 0x08 + + int timestamp; /* Time link was last accessed */ + int expire_time; /* Expire time for link */ + + int sockfd; /* socket descriptor */ + + u_int start_point_out; /* Index number in output lookup table */ + u_int start_point_in; + struct alias_link *next_out; /* Linked list pointers for input and */ + struct alias_link *last_out; /* output tables */ + struct alias_link *next_in; /* . */ + struct alias_link *last_in; /* . */ + + union /* Auxiliary data */ + { + char *frag_ptr; + struct in_addr frag_addr; + struct tcp_dat *tcp; + } data; +}; + + + + + +/* Global Variables + + The global variables listed here are only accessed from + within alias_db.c and so are prefixed with the static + designation. +*/ + +int packetAliasMode; /* Mode flags */ + /* - documented in alias.h */ + +static struct in_addr aliasAddress; /* Address written onto source */ + /* field of IP packet. */ + +static struct in_addr targetAddress; /* IP address incoming packets */ + /* are sent to if no aliasing */ + /* link already exists */ + +static struct in_addr nullAddress; /* Used as a dummy parameter for */ + /* some function calls */ +static struct alias_link * +linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ + /* chains of link records. Each */ +static struct alias_link * /* link record is doubly indexed */ +linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ + /* tables. */ + +static int icmpLinkCount; /* Link statistics */ +static int udpLinkCount; +static int tcpLinkCount; +static int fragmentIdLinkCount; +static int fragmentPtrLinkCount; +static int sockCount; + +static int cleanupIndex; /* Index to chain of link table */ + /* being inspected for old links */ + +static int timeStamp; /* System time in seconds for */ + /* current packet */ + +static int lastCleanupTime; /* Last time IncrementalCleanup() */ + /* was called */ + +static int houseKeepingResidual; /* used by HouseKeeping() */ + +static int deleteAllLinks; /* If equal to zero, DeleteLink() */ + /* will not remove permanent links */ + +static FILE *monitorFile; /* File descriptor for link */ + /* statistics monitoring file */ + +static int newDefaultLink; /* Indicates if a new aliasing */ + /* link has been created after a */ + /* call to PacketAliasIn/Out(). */ + +#ifndef NO_FW_PUNCH +static int fireWallFD = -1; /* File descriptor to be able to */ + /* control firewall. Opened by */ + /* PacketAliasSetMode on first */ + /* setting the PKT_ALIAS_PUNCH_FW */ + /* flag. */ +#endif + + + + + + +/* Internal utility routines (used only in alias_db.c) + +Lookup table starting points: + StartPointIn() -- link table initial search point for + outgoing packets + StartPointOut() -- port table initial search point for + incoming packets + +Miscellaneous: + SeqDiff() -- difference between two TCP sequences + ShowAliasStats() -- send alias statistics to a monitor file +*/ + + +/* Local prototypes */ +static u_int StartPointIn(struct in_addr, u_short, int); + +static u_int StartPointOut(struct in_addr, struct in_addr, + u_short, u_short, int); + +static int SeqDiff(u_long, u_long); + +static void ShowAliasStats(void); + +#ifndef NO_FW_PUNCH +/* Firewall control */ +static void InitPunchFW(void); +static void UninitPunchFW(void); +static void ClearFWHole(struct alias_link *link); +#endif + +/* Log file control */ +static void InitPacketAliasLog(void); +static void UninitPacketAliasLog(void); + +static u_int +StartPointIn(struct in_addr alias_addr, + u_short alias_port, + int link_type) +{ + u_int n; + + n = alias_addr.s_addr; + n += alias_port; + n += link_type; + return(n % LINK_TABLE_IN_SIZE); +} + + +static u_int +StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, + u_short src_port, u_short dst_port, int link_type) +{ + u_int n; + + n = src_addr.s_addr; + n += dst_addr.s_addr; + n += src_port; + n += dst_port; + n += link_type; + + return(n % LINK_TABLE_OUT_SIZE); +} + + +static int +SeqDiff(u_long x, u_long y) +{ +/* Return the difference between two TCP sequence numbers */ + +/* + This function is encapsulated in case there are any unusual + arithmetic conditions that need to be considered. +*/ + + return (ntohl(y) - ntohl(x)); +} + + +static void +ShowAliasStats(void) +{ +/* Used for debugging */ + + if (packetAliasMode & PKT_ALIAS_LOG) + { + fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", + icmpLinkCount, + udpLinkCount, + tcpLinkCount, + fragmentIdLinkCount, + fragmentPtrLinkCount); + + fprintf(monitorFile, " / tot=%d (sock=%d)\n", + icmpLinkCount + udpLinkCount + + tcpLinkCount + + fragmentIdLinkCount + + fragmentPtrLinkCount, + sockCount); + + fflush(monitorFile); + } +} + + + + + +/* Internal routines for finding, deleting and adding links + +Port Allocation: + GetNewPort() -- find and reserve new alias port number + GetSocket() -- try to allocate a socket for a given port + +Link creation and deletion: + CleanupAliasData() - remove all link chains from lookup table + IncrementalCleanup() - look for stale links in a single chain + DeleteLink() - remove link + AddLink() - add link + ReLink() - change link + +Link search: + FindLinkOut() - find link for outgoing packets + FindLinkIn() - find link for incoming packets +*/ + +/* Local prototypes */ +static int GetNewPort(struct alias_link *, int); + +static u_short GetSocket(u_short, int *, int); + +static void CleanupAliasData(void); + +static void IncrementalCleanup(void); + +static void DeleteLink(struct alias_link *); + +static struct alias_link * +AddLink(struct in_addr, struct in_addr, struct in_addr, + u_short, u_short, int, int); + +static struct alias_link * +ReLink(struct alias_link *, + struct in_addr, struct in_addr, struct in_addr, + u_short, u_short, int, int); + +static struct alias_link * +FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); + +static struct alias_link * +FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); + + +#define ALIAS_PORT_BASE 0x08000 +#define ALIAS_PORT_MASK 0x07fff +#define GET_NEW_PORT_MAX_ATTEMPTS 20 + +#define GET_ALIAS_PORT -1 +#define GET_ALIAS_ID GET_ALIAS_PORT + +/* GetNewPort() allocates port numbers. Note that if a port number + is already in use, that does not mean that it cannot be used by + another link concurrently. This is because GetNewPort() looks for + unused triplets: (dest addr, dest port, alias port). */ + +static int +GetNewPort(struct alias_link *link, int alias_port_param) +{ + int i; + int max_trials; + u_short port_sys; + u_short port_net; + +/* + Description of alias_port_param for GetNewPort(). When + this parameter is zero or positive, it precisely specifies + the port number. GetNewPort() will return this number + without check that it is in use. + + Whis this parameter is -1, it indicates to get a randomly + selected port number. +*/ + + if (alias_port_param == GET_ALIAS_PORT) + { + /* + * The aliasing port is automatically selected + * by one of two methods below: + */ + max_trials = GET_NEW_PORT_MAX_ATTEMPTS; + + if (packetAliasMode & PKT_ALIAS_SAME_PORTS) + { + /* + * When the ALIAS_SAME_PORTS option is + * chosen, the first try will be the + * actual source port. If this is already + * in use, the remainder of the trials + * will be random. + */ + port_net = link->src_port; + port_sys = ntohs(port_net); + } + else + { + /* First trial and all subsequent are random. */ + port_sys = random() & ALIAS_PORT_MASK; + port_sys += ALIAS_PORT_BASE; + port_net = htons(port_sys); + } + } + else if (alias_port_param >= 0 && alias_port_param < 0x10000) + { + link->alias_port = (u_short) alias_port_param; + return(0); + } + else + { + fprintf(stderr, "PacketAlias/GetNewPort(): "); + fprintf(stderr, "input parameter error\n"); + return(-1); + } + + +/* Port number search */ + for (i=0; i<max_trials; i++) + { + int go_ahead; + struct alias_link *search_result; + + search_result = FindLinkIn(link->dst_addr, link->alias_addr, + link->dst_port, port_net, + link->link_type, 0); + + if (search_result == NULL) + go_ahead = 1; + else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) + && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) + go_ahead = 1; + else + go_ahead = 0; + + if (go_ahead) + { + if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) + && (link->flags & LINK_PARTIALLY_SPECIFIED)) + { + if (GetSocket(port_net, &link->sockfd, link->link_type)) + { + link->alias_port = port_net; + return(0); + } + } + else + { + link->alias_port = port_net; + return(0); + } + } + + port_sys = random() & ALIAS_PORT_MASK; + port_sys += ALIAS_PORT_BASE; + port_net = htons(port_sys); + } + + fprintf(stderr, "PacketAlias/GetnewPort(): "); + fprintf(stderr, "could not find free port\n"); + + return(-1); +} + + +static u_short +GetSocket(u_short port_net, int *sockfd, int link_type) +{ + int err; + int sock; + struct sockaddr_in sock_addr; + + if (link_type == LINK_TCP) + sock = socket(AF_INET, SOCK_STREAM, 0); + else if (link_type == LINK_UDP) + sock = socket(AF_INET, SOCK_DGRAM, 0); + else + { + fprintf(stderr, "PacketAlias/GetSocket(): "); + fprintf(stderr, "incorrect link type\n"); + return(0); + } + + if (sock < 0) + { + fprintf(stderr, "PacketAlias/GetSocket(): "); + fprintf(stderr, "socket() error %d\n", *sockfd); + return(0); + } + + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); + sock_addr.sin_port = port_net; + + err = bind(sock, + (struct sockaddr *) &sock_addr, + sizeof(sock_addr)); + if (err == 0) + { + sockCount++; + *sockfd = sock; + return(1); + } + else + { + close(sock); + return(0); + } +} + + +static void +CleanupAliasData(void) +{ + struct alias_link *link; + int i, icount; + + icount = 0; + for (i=0; i<LINK_TABLE_OUT_SIZE; i++) + { + link = linkTableOut[i]; + while (link != NULL) + { + struct alias_link *link_next; + link_next = link->next_out; + icount++; + DeleteLink(link); + link = link_next; + } + } + + cleanupIndex =0; +} + + +static void +IncrementalCleanup(void) +{ + int icount; + struct alias_link *link; + + icount = 0; + link = linkTableOut[cleanupIndex++]; + while (link != NULL) + { + int idelta; + struct alias_link *link_next; + + link_next = link->next_out; + idelta = timeStamp - link->timestamp; + switch (link->link_type) + { + case LINK_ICMP: + case LINK_UDP: + case LINK_FRAGMENT_ID: + case LINK_FRAGMENT_PTR: + if (idelta > link->expire_time) + { + DeleteLink(link); + icount++; + } + break; + case LINK_TCP: + if (idelta > link->expire_time) + { + struct tcp_dat *tcp_aux; + + tcp_aux = link->data.tcp; + if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED + || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) + { + DeleteLink(link); + icount++; + } + } + break; + } + link = link_next; + } + + if (cleanupIndex == LINK_TABLE_OUT_SIZE) + cleanupIndex = 0; +} + +void +DeleteLink(struct alias_link *link) +{ + struct alias_link *link_last; + struct alias_link *link_next; + +/* Don't do anything if the link is marked permanent */ + if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) + return; + +#ifndef NO_FW_PUNCH +/* Delete associatied firewall hole, if any */ + ClearFWHole(link); +#endif + +/* Adjust output table pointers */ + link_last = link->last_out; + link_next = link->next_out; + + if (link_last != NULL) + link_last->next_out = link_next; + else + linkTableOut[link->start_point_out] = link_next; + + if (link_next != NULL) + link_next->last_out = link_last; + +/* Adjust input table pointers */ + link_last = link->last_in; + link_next = link->next_in; + + if (link_last != NULL) + link_last->next_in = link_next; + else + linkTableIn[link->start_point_in] = link_next; + + if (link_next != NULL) + link_next->last_in = link_last; + +/* Close socket, if one has been allocated */ + if (link->sockfd != -1) + { + sockCount--; + close(link->sockfd); + } + +/* Link-type dependent cleanup */ + switch(link->link_type) + { + case LINK_ICMP: + icmpLinkCount--; + break; + case LINK_UDP: + udpLinkCount--; + break; + case LINK_TCP: + tcpLinkCount--; + if (link->data.tcp != NULL) + free(link->data.tcp); + break; + case LINK_FRAGMENT_ID: + fragmentIdLinkCount--; + break; + case LINK_FRAGMENT_PTR: + fragmentPtrLinkCount--; + if (link->data.frag_ptr != NULL) + free(link->data.frag_ptr); + break; + } + +/* Free memory */ + free(link); + +/* Write statistics, if logging enabled */ + if (packetAliasMode & PKT_ALIAS_LOG) + { + ShowAliasStats(); + } +} + + +static struct alias_link * +AddLink(struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_short src_port, + u_short dst_port, + int alias_port_param, /* if less than zero, alias */ + int link_type) /* port will be automatically */ +{ /* chosen. If greater than */ + u_int start_point; /* zero, equal to alias port */ + struct alias_link *link; + struct alias_link *first_link; + + link = malloc(sizeof(struct alias_link)); + if (link != NULL) + { + /* If either the aliasing address or source address are + equal to the default device address (equal to the + global variable aliasAddress), then set the alias + address field of the link record to zero */ + + if (src_addr.s_addr == aliasAddress.s_addr) + src_addr.s_addr = 0; + + if (alias_addr.s_addr == aliasAddress.s_addr) + alias_addr.s_addr = 0; + + /* Basic initialization */ + link->src_addr = src_addr; + link->dst_addr = dst_addr; + link->src_port = src_port; + link->alias_addr = alias_addr; + link->dst_port = dst_port; + link->link_type = link_type; + link->sockfd = -1; + link->flags = 0; + link->timestamp = timeStamp; + + /* Expiration time */ + switch (link_type) + { + case LINK_ICMP: + link->expire_time = ICMP_EXPIRE_TIME; + break; + case LINK_UDP: + link->expire_time = UDP_EXPIRE_TIME; + break; + case LINK_TCP: + link->expire_time = TCP_EXPIRE_INITIAL; + break; + case LINK_FRAGMENT_ID: + link->expire_time = FRAGMENT_ID_EXPIRE_TIME; + break; + case LINK_FRAGMENT_PTR: + link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; + break; + } + + /* Determine alias flags */ + if (dst_addr.s_addr == 0) + link->flags |= LINK_UNKNOWN_DEST_ADDR; + if (dst_port == 0) + link->flags |= LINK_UNKNOWN_DEST_PORT; + + /* Determine alias port */ + if (GetNewPort(link, alias_port_param) != 0) + { + free(link); + return(NULL); + } + + /* Set up pointers for output lookup table */ + start_point = StartPointOut(src_addr, dst_addr, + src_port, dst_port, link_type); + first_link = linkTableOut[start_point]; + + link->last_out = NULL; + link->next_out = first_link; + link->start_point_out = start_point; + + if (first_link != NULL) + first_link->last_out = link; + + linkTableOut[start_point] = link; + + /* Set up pointers for input lookup table */ + start_point = StartPointIn(alias_addr, link->alias_port, link_type); + first_link = linkTableIn[start_point]; + + link->last_in = NULL; + link->next_in = first_link; + link->start_point_in = start_point; + + if (first_link != NULL) + first_link->last_in = link; + + linkTableIn[start_point] = link; + + /* Link-type dependent initialization */ + switch(link_type) + { + struct tcp_dat *aux_tcp; + + case LINK_ICMP: + icmpLinkCount++; + break; + case LINK_UDP: + udpLinkCount++; + break; + case LINK_TCP: + aux_tcp = malloc(sizeof(struct tcp_dat)); + link->data.tcp = aux_tcp; + if (aux_tcp != NULL) + { + int i; + + tcpLinkCount++; + aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; + aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; + aux_tcp->state.index = 0; + aux_tcp->state.ack_modified = 0; + for (i=0; i<N_LINK_TCP_DATA; i++) + aux_tcp->ack[i].active = 0; + aux_tcp->fwhole = -1; + } + else + { + fprintf(stderr, "PacketAlias/AddLink: "); + fprintf(stderr, " cannot allocate auxiliary TCP data\n"); + } + break; + case LINK_FRAGMENT_ID: + fragmentIdLinkCount++; + break; + case LINK_FRAGMENT_PTR: + fragmentPtrLinkCount++; + break; + } + } + else + { + fprintf(stderr, "PacketAlias/AddLink(): "); + fprintf(stderr, "malloc() call failed.\n"); + } + + if (packetAliasMode & PKT_ALIAS_LOG) + { + ShowAliasStats(); + } + + return(link); +} + +static struct alias_link * +ReLink(struct alias_link *old_link, + struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_short src_port, + u_short dst_port, + int alias_port_param, /* if less than zero, alias */ + int link_type) /* port will be automatically */ +{ /* chosen. If greater than */ + struct alias_link *new_link; /* zero, equal to alias port */ + + new_link = AddLink(src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port_param, + link_type); +#ifndef NO_FW_PUNCH + if (new_link != NULL && + old_link->link_type == LINK_TCP && + old_link->data.tcp && + old_link->data.tcp->fwhole > 0) { + PunchFWHole(new_link); + } +#endif + DeleteLink(old_link); + return new_link; +} + +static struct alias_link * +FindLinkOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short dst_port, + int link_type) +{ + u_int i; + struct alias_link *link; + + if (src_addr.s_addr == aliasAddress.s_addr) + src_addr.s_addr = 0; + + i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); + link = linkTableOut[i]; + while (link != NULL) + { + if (link->src_addr.s_addr == src_addr.s_addr + && link->dst_addr.s_addr == dst_addr.s_addr + && link->dst_port == dst_port + && link->src_port == src_port + && link->link_type == link_type) + { + link->timestamp = timeStamp; + break; + } + link = link->next_out; + } + + return(link); +} + + +struct alias_link * +FindLinkIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short dst_port, + u_short alias_port, + int link_type, + int replace_partial_links) +{ + int flags_in; + u_int start_point; + struct alias_link *link; + struct alias_link *link_fully_specified; + struct alias_link *link_unknown_all; + struct alias_link *link_unknown_dst_addr; + struct alias_link *link_unknown_dst_port; + +/* Initialize pointers */ + link_fully_specified = NULL; + link_unknown_all = NULL; + link_unknown_dst_addr = NULL; + link_unknown_dst_port = NULL; + +/* If either the dest addr or port is unknown, the search + loop will have to know about this. */ + + flags_in = 0; + if (dst_addr.s_addr == 0) + flags_in |= LINK_UNKNOWN_DEST_ADDR; + if (dst_port == 0) + flags_in |= LINK_UNKNOWN_DEST_PORT; + +/* The following allows permanent links to be + be specified as using the default aliasing address + (i.e. device interface address) without knowing + in advance what that address is. */ + + if (alias_addr.s_addr == aliasAddress.s_addr) + alias_addr.s_addr = 0; + +/* Search loop */ + start_point = StartPointIn(alias_addr, alias_port, link_type); + link = linkTableIn[start_point]; + while (link != NULL) + { + int flags; + + flags = flags_in | link->flags; + if (!(flags & LINK_PARTIALLY_SPECIFIED)) + { + if (link->alias_addr.s_addr == alias_addr.s_addr + && link->alias_port == alias_port + && link->dst_addr.s_addr == dst_addr.s_addr + && link->dst_port == dst_port + && link->link_type == link_type) + { + link_fully_specified = link; + break; + } + } + else if ((flags & LINK_UNKNOWN_DEST_ADDR) + && (flags & LINK_UNKNOWN_DEST_PORT)) + { + if (link->alias_addr.s_addr == alias_addr.s_addr + && link->alias_port == alias_port + && link->link_type == link_type) + { + if (link_unknown_all == NULL) + link_unknown_all = link; + } + } + else if (flags & LINK_UNKNOWN_DEST_ADDR) + { + if (link->alias_addr.s_addr == alias_addr.s_addr + && link->alias_port == alias_port + && link->link_type == link_type + && link->dst_port == dst_port) + { + if (link_unknown_dst_addr == NULL) + link_unknown_dst_addr = link; + } + } + else if (flags & LINK_UNKNOWN_DEST_PORT) + { + if (link->alias_addr.s_addr == alias_addr.s_addr + && link->alias_port == alias_port + && link->link_type == link_type + && link->dst_addr.s_addr == dst_addr.s_addr) + { + if (link_unknown_dst_port == NULL) + link_unknown_dst_port = link; + } + } + link = link->next_in; + } + + + + if (link_fully_specified != NULL) + { + return link_fully_specified; + } + else if (link_unknown_dst_port != NULL) + { + return replace_partial_links + ? ReLink(link_unknown_dst_port, + link_unknown_dst_port->src_addr, dst_addr, alias_addr, + link_unknown_dst_port->src_port, dst_port, alias_port, + link_type) + : link_unknown_dst_port; + } + else if (link_unknown_dst_addr != NULL) + { + return replace_partial_links + ? ReLink(link_unknown_dst_addr, + link_unknown_dst_addr->src_addr, dst_addr, alias_addr, + link_unknown_dst_addr->src_port, dst_port, alias_port, + link_type) + : link_unknown_dst_addr; + } + else if (link_unknown_all != NULL) + { + return replace_partial_links + ? ReLink(link_unknown_all, + link_unknown_all->src_addr, dst_addr, alias_addr, + link_unknown_all->src_port, dst_port, alias_port, + link_type) + : link_unknown_all; + } + else + { + return(NULL); + } +} + + + + +/* External routines for finding/adding links + +-- "external" means outside alias_db.c, but within alias*.c -- + + FindIcmpIn(), FindIcmpOut() + FindFragmentIn1(), FindFragmentIn2() + AddFragmentPtrLink(), FindFragmentPtr() + FindUdpTcpIn(), FindUdpTcpOut() + FindOriginalAddress(), FindAliasAddress() + +(prototypes in alias_local.h) +*/ + + +struct alias_link * +FindIcmpIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short id_alias) +{ + return FindLinkIn(dst_addr, alias_addr, + NO_DEST_PORT, id_alias, + LINK_ICMP, 0); +} + + +struct alias_link * +FindIcmpOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short id) +{ + struct alias_link * link; + + link = FindLinkOut(src_addr, dst_addr, + id, NO_DEST_PORT, + LINK_ICMP); + if (link == NULL) + { + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(src_addr); + link = AddLink(src_addr, dst_addr, alias_addr, + id, NO_DEST_PORT, GET_ALIAS_ID, + LINK_ICMP); + } + + return(link); +} + + +struct alias_link * +FindFragmentIn1(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short ip_id) +{ + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, + NO_DEST_PORT, ip_id, + LINK_FRAGMENT_ID, 0); + + if (link == NULL) + { + link = AddLink(nullAddress, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, ip_id, + LINK_FRAGMENT_ID); + } + + return(link); +} + + +struct alias_link * +FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ + struct in_addr alias_addr, /* is not found. */ + u_short ip_id) +{ + return FindLinkIn(dst_addr, alias_addr, + NO_DEST_PORT, ip_id, + LINK_FRAGMENT_ID, 0); +} + + +struct alias_link * +AddFragmentPtrLink(struct in_addr dst_addr, + u_short ip_id) +{ + return AddLink(nullAddress, dst_addr, nullAddress, + NO_SRC_PORT, NO_DEST_PORT, ip_id, + LINK_FRAGMENT_PTR); +} + + +struct alias_link * +FindFragmentPtr(struct in_addr dst_addr, + u_short ip_id) +{ + return FindLinkIn(dst_addr, nullAddress, + NO_DEST_PORT, ip_id, + LINK_FRAGMENT_PTR, 0); +} + + +struct alias_link * +FindUdpTcpIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short dst_port, + u_short alias_port, + u_char proto) +{ + int link_type; + struct alias_link *link; + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return NULL; + break; + } + + link = FindLinkIn(dst_addr, alias_addr, + dst_port, alias_port, + link_type, 1); + + if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL) + { + struct in_addr target_addr; + + target_addr = FindOriginalAddress(alias_addr); + link = AddLink(target_addr, dst_addr, alias_addr, + alias_port, dst_port, alias_port, + link_type); + } + + return(link); +} + + +struct alias_link * +FindUdpTcpOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short dst_port, + u_char proto) +{ + int link_type; + struct alias_link *link; + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return NULL; + break; + } + + link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); + + if (link == NULL) + { + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(src_addr); + link = AddLink(src_addr, dst_addr, alias_addr, + src_port, dst_port, GET_ALIAS_PORT, + link_type); + } + + return(link); +} + + +struct in_addr +FindOriginalAddress(struct in_addr alias_addr) +{ + struct alias_link *link; + + link = FindLinkIn(nullAddress, alias_addr, + 0, 0, LINK_ADDR, 0); + if (link == NULL) + { + newDefaultLink = 1; + if (targetAddress.s_addr != 0) + return targetAddress; + else + return alias_addr; + } + else + { + if (link->src_addr.s_addr == 0) + return aliasAddress; + else + return link->src_addr; + } +} + + +struct in_addr +FindAliasAddress(struct in_addr original_addr) +{ + struct alias_link *link; + + link = FindLinkOut(original_addr, nullAddress, + 0, 0, LINK_ADDR); + if (link == NULL) + { + return aliasAddress; + } + else + { + if (link->alias_addr.s_addr == 0) + return aliasAddress; + else + return link->alias_addr; + } +} + + +/* External routines for getting or changing link data + (external to alias_db.c, but internal to alias*.c) + + SetFragmentData(), GetFragmentData() + SetFragmentPtr(), GetFragmentPtr() + SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() + GetOriginalAddress(), GetDestAddress(), GetAliasAddress() + GetOriginalPort(), GetAliasPort() + SetAckModified(), GetAckModified() + GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() +*/ + + +void +SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) +{ + link->data.frag_addr = src_addr; +} + + +void +GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) +{ + *src_addr = link->data.frag_addr; +} + + +void +SetFragmentPtr(struct alias_link *link, char *fptr) +{ + link->data.frag_ptr = fptr; +} + + +void +GetFragmentPtr(struct alias_link *link, char **fptr) +{ + *fptr = link->data.frag_ptr; +} + + +void +SetStateIn(struct alias_link *link, int state) +{ + /* TCP input state */ + switch (state) { + case ALIAS_TCP_STATE_DISCONNECTED: + if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { + link->expire_time = TCP_EXPIRE_DEAD; + } else { + link->expire_time = TCP_EXPIRE_SINGLEDEAD; + } + link->data.tcp->state.in = state; + break; + case ALIAS_TCP_STATE_CONNECTED: + link->expire_time = TCP_EXPIRE_CONNECTED; + /*FALLTHROUGH*/ + case ALIAS_TCP_STATE_NOT_CONNECTED: + link->data.tcp->state.in = state; + break; + default: + abort(); + } +} + + +void +SetStateOut(struct alias_link *link, int state) +{ + /* TCP output state */ + switch (state) { + case ALIAS_TCP_STATE_DISCONNECTED: + if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { + link->expire_time = TCP_EXPIRE_DEAD; + } else { + link->expire_time = TCP_EXPIRE_SINGLEDEAD; + } + link->data.tcp->state.out = state; + break; + case ALIAS_TCP_STATE_CONNECTED: + link->expire_time = TCP_EXPIRE_CONNECTED; + /*FALLTHROUGH*/ + case ALIAS_TCP_STATE_NOT_CONNECTED: + link->data.tcp->state.out = state; + break; + default: + abort(); + } +} + + +int +GetStateIn(struct alias_link *link) +{ + /* TCP input state */ + return link->data.tcp->state.in; +} + + +int +GetStateOut(struct alias_link *link) +{ + /* TCP output state */ + return link->data.tcp->state.out; +} + + +struct in_addr +GetOriginalAddress(struct alias_link *link) +{ + if (link->src_addr.s_addr == 0) + return aliasAddress; + else + return(link->src_addr); +} + + +struct in_addr +GetDestAddress(struct alias_link *link) +{ + return(link->dst_addr); +} + + +struct in_addr +GetAliasAddress(struct alias_link *link) +{ + if (link->alias_addr.s_addr == 0) + return aliasAddress; + else + return link->alias_addr; +} + + +struct in_addr +GetDefaultAliasAddress() +{ + return aliasAddress; +} + + +void +SetDefaultAliasAddress(struct in_addr alias_addr) +{ + aliasAddress = alias_addr; +} + + +u_short +GetOriginalPort(struct alias_link *link) +{ + return(link->src_port); +} + + +u_short +GetAliasPort(struct alias_link *link) +{ + return(link->alias_port); +} + +u_short +GetDestPort(struct alias_link *link) +{ + return(link->dst_port); +} + +void +SetAckModified(struct alias_link *link) +{ +/* Indicate that ack numbers have been modified in a TCP connection */ + link->data.tcp->state.ack_modified = 1; +} + + +int +GetAckModified(struct alias_link *link) +{ +/* See if ack numbers have been modified */ + return link->data.tcp->state.ack_modified; +} + + +int +GetDeltaAckIn(struct ip *pip, struct alias_link *link) +{ +/* +Find out how much the ack number has been altered for an incoming +TCP packet. To do this, a circular list is ack numbers where the TCP +packet size was altered is searched. +*/ + + int i; + struct tcphdr *tc; + int delta, ack_diff_min; + u_long ack; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + ack = tc->th_ack; + + delta = 0; + ack_diff_min = -1; + for (i=0; i<N_LINK_TCP_DATA; i++) + { + struct ack_data_record x; + + x = link->data.tcp->ack[i]; + if (x.active == 1) + { + int ack_diff; + + ack_diff = SeqDiff(x.ack_new, ack); + if (ack_diff >= 0) + { + if (ack_diff_min >= 0) + { + if (ack_diff < ack_diff_min) + { + delta = x.delta; + ack_diff_min = ack_diff; + } + } + else + { + delta = x.delta; + ack_diff_min = ack_diff; + } + } + } + } + return (delta); +} + + +int +GetDeltaSeqOut(struct ip *pip, struct alias_link *link) +{ +/* +Find out how much the seq number has been altered for an outgoing +TCP packet. To do this, a circular list is ack numbers where the TCP +packet size was altered is searched. +*/ + + int i; + struct tcphdr *tc; + int delta, seq_diff_min; + u_long seq; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + seq = tc->th_seq; + + delta = 0; + seq_diff_min = -1; + for (i=0; i<N_LINK_TCP_DATA; i++) + { + struct ack_data_record x; + + x = link->data.tcp->ack[i]; + if (x.active == 1) + { + int seq_diff; + + seq_diff = SeqDiff(x.ack_old, seq); + if (seq_diff >= 0) + { + if (seq_diff_min >= 0) + { + if (seq_diff < seq_diff_min) + { + delta = x.delta; + seq_diff_min = seq_diff; + } + } + else + { + delta = x.delta; + seq_diff_min = seq_diff; + } + } + } + } + return (delta); +} + + +void +AddSeq(struct ip *pip, struct alias_link *link, int delta) +{ +/* +When a TCP packet has been altered in length, save this +information in a circular list. If enough packets have +been altered, then this list will begin to overwrite itself. +*/ + + struct tcphdr *tc; + struct ack_data_record x; + int hlen, tlen, dlen; + int i; + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + x.ack_old = htonl(ntohl(tc->th_seq) + dlen); + x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); + x.delta = delta; + x.active = 1; + + i = link->data.tcp->state.index; + link->data.tcp->ack[i] = x; + + i++; + if (i == N_LINK_TCP_DATA) + link->data.tcp->state.index = 0; + else + link->data.tcp->state.index = i; +} + +void +SetExpire(struct alias_link *link, int expire) +{ + if (expire == 0) + { + link->flags &= ~LINK_PERMANENT; + DeleteLink(link); + } + else if (expire == -1) + { + link->flags |= LINK_PERMANENT; + } + else if (expire > 0) + { + link->expire_time = expire; + } + else + { + fprintf(stderr, "PacketAlias/SetExpire(): "); + fprintf(stderr, "error in expire parameter\n"); + } +} + +void +ClearCheckNewLink(void) +{ + newDefaultLink = 0; +} + + +/* Miscellaneous Functions + + HouseKeeping() + InitPacketAliasLog() + UninitPacketAliasLog() +*/ + +/* + Whenever an outgoing or incoming packet is handled, HouseKeeping() + is called to find and remove timed-out aliasing links. Logic exists + to sweep through the entire table and linked list structure + every 60 seconds. + + (prototype in alias_local.h) +*/ + +void +HouseKeeping(void) +{ + int i, n, n100; + struct timeval tv; + struct timezone tz; + + /* + * Save system time (seconds) in global variable timeStamp for + * use by other functions. This is done so as not to unnecessarily + * waste timeline by making system calls. + */ + gettimeofday(&tv, &tz); + timeStamp = tv.tv_sec; + + /* Compute number of spokes (output table link chains) to cover */ + n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; + n100 *= timeStamp - lastCleanupTime; + n100 /= ALIAS_CLEANUP_INTERVAL_SECS; + + n = n100/100; + + /* Handle different cases */ + if (n > ALIAS_CLEANUP_MAX_SPOKES) + { + n = ALIAS_CLEANUP_MAX_SPOKES; + lastCleanupTime = timeStamp; + houseKeepingResidual = 0; + + for (i=0; i<n; i++) + IncrementalCleanup(); + } + else if (n > 0) + { + lastCleanupTime = timeStamp; + houseKeepingResidual = n100 - 100*n; + + for (i=0; i<n; i++) + IncrementalCleanup(); + } + else if (n < 0) + { + fprintf(stderr, "PacketAlias/HouseKeeping(): "); + fprintf(stderr, "something unexpected in time values\n"); + lastCleanupTime = timeStamp; + houseKeepingResidual = 0; + } +} + + +/* Init the log file and enable logging */ +static void +InitPacketAliasLog(void) +{ + if ((~packetAliasMode & PKT_ALIAS_LOG) + && (monitorFile = fopen("/var/log/alias.log", "w"))) + { + packetAliasMode |= PKT_ALIAS_LOG; + fprintf(monitorFile, + "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); + } +} + + +/* Close the log-file and disable logging. */ +static void +UninitPacketAliasLog(void) +{ + if( monitorFile ) + fclose(monitorFile); + packetAliasMode &= ~PKT_ALIAS_LOG; +} + + + + + + +/* Outside world interfaces + +-- "outside world" means other than alias*.c routines -- + + PacketAliasRedirectPort() + PacketAliasRedirectAddr() + PacketAliasRedirectDelete() + PacketAliasSetAddress() + PacketAliasInit() + PacketAliasUninit() + PacketAliasSetMode() + +(prototypes in alias.h) +*/ + +/* Redirection from a specific public addr:port to a + a private addr:port */ +struct alias_link * +PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, + struct in_addr dst_addr, u_short dst_port, + struct in_addr alias_addr, u_short alias_port, + u_char proto) +{ + int link_type; + struct alias_link *link; + + switch(proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + fprintf(stderr, "PacketAliasRedirectPort(): "); + fprintf(stderr, "only TCP and UDP protocols allowed\n"); + return NULL; + } + + link = AddLink(src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); + + if (link != NULL) + { + link->flags |= LINK_PERMANENT; + } + else + { + fprintf(stderr, "PacketAliasRedirectPort(): " + "call to AddLink() failed\n"); + } + + return link; +} + + +/* Static address translation */ +struct alias_link * +PacketAliasRedirectAddr(struct in_addr src_addr, + struct in_addr alias_addr) +{ + struct alias_link *link; + + link = AddLink(src_addr, nullAddress, alias_addr, + 0, 0, 0, + LINK_ADDR); + + if (link != NULL) + { + link->flags |= LINK_PERMANENT; + } + else + { + fprintf(stderr, "PacketAliasRedirectAddr(): " + "call to AddLink() failed\n"); + } + + return link; +} + + +void +PacketAliasRedirectDelete(struct alias_link *link) +{ +/* This is a dangerous function to put in the API, + because an invalid pointer can crash the program. */ + + deleteAllLinks = 1; + DeleteLink(link); + deleteAllLinks = 0; +} + + +void +PacketAliasSetAddress(struct in_addr addr) +{ + if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE + && aliasAddress.s_addr != addr.s_addr) + CleanupAliasData(); + + aliasAddress = addr; +} + + +void +PacketAliasSetTarget(struct in_addr target_addr) +{ + targetAddress = target_addr; +} + + +void +PacketAliasInit(void) +{ + int i; + struct timeval tv; + struct timezone tz; + static int firstCall = 1; + + if (firstCall == 1) + { + gettimeofday(&tv, &tz); + timeStamp = tv.tv_sec; + lastCleanupTime = tv.tv_sec; + houseKeepingResidual = 0; + + for (i=0; i<LINK_TABLE_OUT_SIZE; i++) + linkTableOut[i] = NULL; + for (i=0; i<LINK_TABLE_IN_SIZE; i++) + linkTableIn[i] = NULL; + + atexit(PacketAliasUninit); + firstCall = 0; + } + else + { + deleteAllLinks = 1; + CleanupAliasData(); + deleteAllLinks = 0; + } + + aliasAddress.s_addr = 0; + targetAddress.s_addr = 0; + + icmpLinkCount = 0; + udpLinkCount = 0; + tcpLinkCount = 0; + fragmentIdLinkCount = 0; + fragmentPtrLinkCount = 0; + sockCount = 0; + + cleanupIndex =0; + + packetAliasMode = PKT_ALIAS_SAME_PORTS + | PKT_ALIAS_USE_SOCKETS + | PKT_ALIAS_RESET_ON_ADDR_CHANGE; +} + +void +PacketAliasUninit(void) { + deleteAllLinks = 1; + CleanupAliasData(); + deleteAllLinks = 0; + UninitPacketAliasLog(); +#ifndef NO_FW_PUNCH + UninitPunchFW(); +#endif +} + + +/* Change mode for some operations */ +unsigned int +PacketAliasSetMode( + unsigned int flags, /* Which state to bring flags to */ + unsigned int mask /* Mask of which flags to affect (use 0 to do a + probe for flag values) */ +) +{ +/* Enable logging? */ + if (flags & mask & PKT_ALIAS_LOG) + { + InitPacketAliasLog(); /* Do the enable */ + } else +/* _Disable_ logging? */ + if (~flags & mask & PKT_ALIAS_LOG) { + UninitPacketAliasLog(); + } + +#ifndef NO_FW_PUNCH +/* Start punching holes in the firewall? */ + if (flags & mask & PKT_ALIAS_PUNCH_FW) { + InitPunchFW(); + } else +/* Stop punching holes in the firewall? */ + if (~flags & mask & PKT_ALIAS_PUNCH_FW) { + UninitPunchFW(); + } +#endif + +/* Other flags can be set/cleared without special action */ + packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); + return packetAliasMode; +} + + +int +PacketAliasCheckNewLink(void) +{ + return newDefaultLink; +} + + +#ifndef NO_FW_PUNCH + +/***************** + Code to support firewall punching. This shouldn't really be in this + file, but making variables global is evil too. + ****************/ + +/* Firewall include files */ +#include <sys/queue.h> +#include <net/if.h> +#include <netinet/ip_fw.h> +#include <string.h> +#include <err.h> + +static void ClearAllFWHoles(void); + +static int fireWallBaseNum; /* The first firewall entry free for our use */ +static int fireWallNumNums; /* How many entries can we use? */ +static int fireWallActiveNum; /* Which entry did we last use? */ +static char *fireWallField; /* bool array for entries */ + +#define fw_setfield(field, num) \ +do { \ + (field)[num] = 1; \ +} /*lint -save -e717 */ while(0) /*lint -restore */ +#define fw_clrfield(field, num) \ +do { \ + (field)[num] = 0; \ +} /*lint -save -e717 */ while(0) /*lint -restore */ +#define fw_tstfield(field, num) ((field)[num]) + +void +PacketAliasSetFWBase(unsigned int base, unsigned int num) { + fireWallBaseNum = base; + fireWallNumNums = num; +} + +static void +InitPunchFW(void) { + fireWallField = malloc(fireWallNumNums); + if (fireWallField) { + memset(fireWallField, 0, fireWallNumNums); + if (fireWallFD < 0) { + fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + } + ClearAllFWHoles(); + fireWallActiveNum = fireWallBaseNum; + } +} + +static void +UninitPunchFW(void) { + ClearAllFWHoles(); + if (fireWallFD >= 0) + close(fireWallFD); + fireWallFD = -1; + if (fireWallField) + free(fireWallField); + fireWallField = NULL; + packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; +} + +/* Make a certain link go through the firewall */ +void +PunchFWHole(struct alias_link *link) { + int r; /* Result code */ + struct ip_fw rule; /* On-the-fly built rule */ + int fwhole; /* Where to punch hole */ + +/* Don't do anything unless we are asked to */ + if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || + fireWallFD < 0 || + link->link_type != LINK_TCP || + !link->data.tcp) + return; + + memset(&rule, 0, sizeof rule); + +/** Build rule **/ + + /* Find empty slot */ + for (fwhole = fireWallActiveNum; + fwhole < fireWallBaseNum + fireWallNumNums && + fw_tstfield(fireWallField, fwhole); + fwhole++) + ; + if (fwhole >= fireWallBaseNum + fireWallNumNums || + fw_tstfield(fireWallField, fwhole)) { + for (fwhole = fireWallBaseNum; + fwhole < fireWallActiveNum && + fw_tstfield(fireWallField, fwhole); + fwhole++) + ; + if (fwhole == fireWallActiveNum) { + /* No rule point empty - we can't punch more holes. */ + fireWallActiveNum = fireWallBaseNum; + fprintf(stderr, "libalias: Unable to create firewall hole!\n"); + return; + } + } + /* Start next search at next position */ + fireWallActiveNum = fwhole+1; + + /* Build generic part of the two rules */ + rule.fw_number = fwhole; + rule.fw_nports = 1; /* Number of source ports; dest ports follow */ + rule.fw_flg = IP_FW_F_ACCEPT; + rule.fw_prot = IPPROTO_TCP; + rule.fw_smsk.s_addr = INADDR_BROADCAST; + rule.fw_dmsk.s_addr = INADDR_BROADCAST; + + /* Build and apply specific part of the rules */ + rule.fw_src = GetOriginalAddress(link); + rule.fw_dst = GetDestAddress(link); + rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); + rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); + + /* Skip non-bound links - XXX should not be strictly necessary, + but seems to leave hole if not done. Leak of non-bound links? + (Code should be left even if the problem is fixed - it is a + clear optimization) */ + if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { + r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); + if (r) + err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); + rule.fw_src = GetDestAddress(link); + rule.fw_dst = GetOriginalAddress(link); + rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); + rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); + r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); + if (r) + err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); + } +/* Indicate hole applied */ + link->data.tcp->fwhole = fwhole; + fw_setfield(fireWallField, fwhole); +} + +/* Remove a hole in a firewall associated with a particular alias + link. Calling this too often is harmless. */ +static void +ClearFWHole(struct alias_link *link) { + if (link->link_type == LINK_TCP && link->data.tcp) { + int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ + struct ip_fw rule; + + if (fwhole < 0) + return; + + memset(&rule, 0, sizeof rule); + rule.fw_number = fwhole; + while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) + ; + fw_clrfield(fireWallField, fwhole); + link->data.tcp->fwhole = -1; + } +} + +/* Clear out the entire range dedicated to firewall holes. */ +static void +ClearAllFWHoles(void) { + struct ip_fw rule; /* On-the-fly built rule */ + int i; + + if (fireWallFD < 0) + return; + + memset(&rule, 0, sizeof rule); + for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { + rule.fw_number = i; + while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) + ; + } + memset(fireWallField, 0, fireWallNumNums); +} +#endif diff --git a/usr.sbin/ppp/libalias/alias_ftp.c b/usr.sbin/ppp/libalias/alias_ftp.c new file mode 100644 index 00000000000..c6d449d0572 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_ftp.c @@ -0,0 +1,227 @@ +/* + Alias_ftp.c performs special processing for FTP sessions under + TCP. Specifically, when a PORT command from the client side + is sent, it is intercepted and modified. The address is changed + to the gateway machine and an aliasing port is used. + + For this routine to work, the PORT command must fit entirely + into a single TCP packet. This is typically the case, but exceptions + can easily be envisioned under the actual specifications. + + Probably the most troubling aspect of the approach taken here is + that the new PORT command will typically be a different length, and + this causes a certain amount of bookkeeping to keep track of the + changes of sequence and acknowledgment numbers, since the client + machine is totally unaware of the modification to the TCP stream. + + + This software is placed into the public domain with no restrictions + on its distribution. + + Initial version: August, 1996 (cjm) + + Version 1.6 + Brian Somers and Martin Renters identified an IP checksum + error for modified IP packets. + + Version 1.7: January 9, 1996 (cjm) + Differental checksum computation for change + in IP packet length. + + Version 2.1: May, 1997 (cjm) + Very minor changes to conform with + local/global/function naming conventions + withing the packet alising module. + + See HISTORY file for record of revisions. +*/ + +/* Includes */ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include "alias_local.h" + +static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int); + + + +void +AliasHandleFtpOut( +struct ip *pip, /* IP packet to examine/patch */ +struct alias_link *link, /* The link to go through (aliased port) */ +int maxpacketsize /* The maximum size this packet can grow to (including headers) */) +{ + int hlen, tlen, dlen; + struct in_addr true_addr; + u_short true_port; + char *sptr; + struct tcphdr *tc; + +/* Calculate data length of TCP packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + +/* Return is data length is too long or too short */ + if (dlen<10 || dlen>80) + return; + +/* Place string pointer and beginning of data */ + sptr = (char *) pip; + sptr += hlen; + +/* Parse through string using state diagram method */ + { + char ch, zero; + int i, state; + u_long a1, a2, a3, a4; + u_short p1, p2; + + a1=0; a2=0; a3=0; a4=0; p1=0; p2=0; + zero = '0'; + state=-4; + for (i=0; i<dlen; i++) + { + ch = sptr[i]; + switch (state) + { + case -4: if (ch == 'P') state=-3; else return; break; + case -3: if (ch == 'O') state=-2; else return; break; + case -2: if (ch == 'R') state=-1; else return; break; + case -1: if (ch == 'T') state= 0; else return; break; + + case 0 : + if (isdigit(ch)) {a1=ch-zero; state=1 ;} break; + case 1 : + if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break; + case 2 : + if (isdigit(ch)) {a2=ch-zero; state=3 ;} break; + case 3 : + if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break; + case 4 : + if (isdigit(ch)) {a3=ch-zero; state=5 ;} break; + case 5 : + if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break; + case 6 : + if (isdigit(ch)) {a4=ch-zero; state=7 ;} break; + case 7 : + if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break; + case 8 : + if (isdigit(ch)) {p1=ch-zero; state=9 ;} break; + case 9 : + if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break; + case 10: + if (isdigit(ch)) {p2=ch-zero; state=11;} break; + case 11: + if (isdigit(ch)) p2=10*p2+ch-zero; break; + } + } + + if (state == 11) + { + true_port = htons((p1<<8) + p2); + true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4); + NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize); + } + } +} + +static void +NewFtpPortCommand(struct ip *pip, + struct alias_link *link, + struct in_addr true_addr, + u_short true_port, + int maxpacketsize) +{ + struct alias_link *ftp_link; + +/* Establish link to address and port found in PORT command */ + ftp_link = FindUdpTcpOut(true_addr, GetDestAddress(link), + true_port, 0, IPPROTO_TCP); + + if (ftp_link != NULL) + { + int slen, hlen, tlen, dlen; + struct tcphdr *tc; + +#ifndef NO_FW_PUNCH +/* Punch hole in firewall */ + PunchFWHole(ftp_link); +#endif + +/* Calculate data length of TCP packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + +/* Create new PORT command */ + { + char stemp[80]; + char *sptr; + u_short alias_port; + u_char *ptr; + int a1, a2, a3, a4, p1, p2; + struct in_addr alias_address; + +/* Decompose alias address into quad format */ + alias_address = GetAliasAddress(link); + ptr = (u_char *) &alias_address.s_addr; + a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; + +/* Decompose alias port into pair format */ + alias_port = GetAliasPort(ftp_link); + ptr = (char *) &alias_port; + p1 = *ptr++; p2=*ptr; + +/* Generate command string */ + sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", + a1,a2,a3,a4,p1,p2); + +/* Save string length for IP header modification */ + slen = strlen(stemp); + +/* Copy into IP packet */ + sptr = (char *) pip; sptr += hlen; + strncpy(sptr, stemp, maxpacketsize-hlen); + } + +/* Save information regarding modified seq and ack numbers */ + { + int delta; + + SetAckModified(link); + delta = GetDeltaSeqOut(pip, link); + AddSeq(pip, link, delta+slen-dlen); + } + +/* Revise IP header */ + { + u_short new_len; + + new_len = htons(hlen + slen); + DifferentialChecksum(&pip->ip_sum, + &new_len, + &pip->ip_len, + 1); + pip->ip_len = new_len; + } + +/* Compute TCP checksum for revised packet */ + tc->th_sum = 0; + tc->th_sum = TcpChecksum(pip); + } + else + { + fprintf(stderr, + "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n"); + } +} diff --git a/usr.sbin/ppp/libalias/alias_irc.c b/usr.sbin/ppp/libalias/alias_irc.c new file mode 100644 index 00000000000..910e9343404 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_irc.c @@ -0,0 +1,316 @@ +/* Alias_irc.c intercepts packages contain IRC CTCP commands, and + changes DCC commands to export a port on the aliasing host instead + of an aliased host. + + For this routine to work, the DCC command must fit entirely into a + single TCP packet. This will usually happen, but is not + guaranteed. + + The interception is likely to change the length of the packet. + The handling of this is copied more-or-less verbatim from + ftp_alias.c + + This software is placed into the public domain with no restrictions + on its distribution. + + Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29 + + Version 2.1: May, 1997 (cjm) + Very minor changes to conform with + local/global/function naming conventions + withing the packet alising module. +*/ + +/* Includes */ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <limits.h> + +#include "alias_local.h" + +/* Local defines */ +#define DBprintf(a) + + +void +AliasHandleIrcOut(struct ip *pip, /* IP packet to examine */ + struct alias_link *link, /* Which link are we on? */ + int maxsize /* Maximum size of IP packet including headers */ + ) +{ + int hlen, tlen, dlen; + struct in_addr true_addr; + u_short true_port; + char *sptr; + struct tcphdr *tc; + int i; /* Iterator through the source */ + +/* Calculate data length of TCP packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + /* Return if data length is too short - assume an entire PRIVMSG in each packet. */ + if (dlen<sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a")-1) + return; + +/* Place string pointer at beginning of data */ + sptr = (char *) pip; + sptr += hlen; + maxsize -= hlen; /* We're interested in maximum size of data, not packet */ + + /* Search for a CTCP command [Note 1] */ + for( i=0; i<dlen; i++ ) { + if(sptr[i]=='\001') + goto lFOUND_CTCP; + } + return; /* No CTCP commands in */ + /* Handle CTCP commands - the buffer may have to be copied */ +lFOUND_CTCP: + { + char newpacket[65536]; /* Estimate of maximum packet size :) */ + int copyat = i; /* Same */ + int iCopy = 0; /* How much data have we written to copy-back string? */ + unsigned long org_addr; /* Original IP address */ + unsigned short org_port; /* Original source port address */ + lCTCP_START: + if( i >= dlen || iCopy >= sizeof(newpacket) ) + goto lPACKET_DONE; + newpacket[iCopy++] = sptr[i++]; /* Copy the CTCP start character */ + /* Start of a CTCP */ + if( i+4 >= dlen ) /* Too short for DCC */ + goto lBAD_CTCP; + if( sptr[i+0] != 'D' ) + goto lBAD_CTCP; + if( sptr[i+1] != 'C' ) + goto lBAD_CTCP; + if( sptr[i+2] != 'C' ) + goto lBAD_CTCP; + if( sptr[i+3] != ' ' ) + goto lBAD_CTCP; + /* We have a DCC command - handle it! */ + i+= 4; /* Skip "DCC " */ + if( iCopy+4 > sizeof(newpacket) ) + goto lPACKET_DONE; + newpacket[iCopy++] = 'D'; + newpacket[iCopy++] = 'C'; + newpacket[iCopy++] = 'C'; + newpacket[iCopy++] = ' '; + + DBprintf(("Found DCC\n")); + /* Skip any extra spaces (should not occur according to + protocol, but DCC breaks CTCP protocol anyway */ + while(sptr[i] == ' ') { + if( ++i >= dlen) { + DBprintf(("DCC packet terminated in just spaces\n")); + goto lPACKET_DONE; + } + } + + DBprintf(("Transferring command...\n")); + while(sptr[i] != ' ') { + newpacket[iCopy++] = sptr[i]; + if( ++i >= dlen || iCopy >= sizeof(newpacket) ) { + DBprintf(("DCC packet terminated during command\n")); + goto lPACKET_DONE; + } + } + /* Copy _one_ space */ + if( i+1 < dlen && iCopy < sizeof(newpacket) ) + newpacket[iCopy++] = sptr[i++]; + + DBprintf(("Done command - removing spaces\n")); + /* Skip any extra spaces (should not occur according to + protocol, but DCC breaks CTCP protocol anyway */ + while(sptr[i] == ' ') { + if( ++i >= dlen ) { + DBprintf(("DCC packet terminated in just spaces (post-command)\n")); + goto lPACKET_DONE; + } + } + + DBprintf(("Transferring filename...\n")); + while(sptr[i] != ' ') { + newpacket[iCopy++] = sptr[i]; + if( ++i >= dlen || iCopy >= sizeof(newpacket) ) { + DBprintf(("DCC packet terminated during filename\n")); + goto lPACKET_DONE; + } + } + /* Copy _one_ space */ + if( i+1 < dlen && iCopy < sizeof(newpacket) ) + newpacket[iCopy++] = sptr[i++]; + + DBprintf(("Done filename - removing spaces\n")); + /* Skip any extra spaces (should not occur according to + protocol, but DCC breaks CTCP protocol anyway */ + while(sptr[i] == ' ') { + if( ++i >= dlen ) { + DBprintf(("DCC packet terminated in just spaces (post-filename)\n")); + goto lPACKET_DONE; + } + } + + DBprintf(("Fetching IP address\n")); + /* Fetch IP address */ + org_addr = 0; + while(i<dlen && isdigit(sptr[i])) { + if( org_addr > ULONG_MAX/10UL ) { /* Terminate on overflow */ + DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i])); + goto lBAD_CTCP; + } + org_addr *= 10; + org_addr += sptr[i++]-'0'; + } + DBprintf(("Skipping space\n")); + if( i+1 >= dlen || sptr[i] != ' ' ) { + DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i+1, dlen, sptr[i])); + goto lBAD_CTCP; + } + /* Skip any extra spaces (should not occur according to + protocol, but DCC breaks CTCP protocol anyway, so we might + as well play it safe */ + while(sptr[i] == ' ') { + if( ++i >= dlen ) { + DBprintf(("Packet failure - space overflow.\n")); + goto lPACKET_DONE; + } + } + DBprintf(("Fetching port number\n")); + /* Fetch source port */ + org_port = 0; + while(i<dlen && isdigit(sptr[i])) { + if( org_port > 6554 ) { /* Terminate on overflow (65536/10 rounded up*/ + DBprintf(("DCC: port number overflow\n")); + goto lBAD_CTCP; + } + org_port *= 10; + org_port += sptr[i++]-'0'; + } + /* Skip illegal addresses (or early termination) */ + if( i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ') ) { + DBprintf(("Bad port termination\n")); + goto lBAD_CTCP; + } + DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port)); + + /* We've got the address and port - now alias it */ + { + struct alias_link *dcc_link; + struct in_addr destaddr; + + + true_port = htons(org_port); + true_addr.s_addr = htonl(org_addr); + destaddr.s_addr = 0; + + /* Steal the FTP_DATA_PORT - it doesn't really matter, and this + would probably allow it through at least _some_ + firewalls. */ + dcc_link = FindUdpTcpOut (true_addr, + destaddr, + true_port, + 0, IPPROTO_TCP); + DBprintf(("Got a DCC link\n")); + if ( dcc_link ) { + struct in_addr alias_address; /* Address from aliasing */ + u_short alias_port; /* Port given by aliasing */ + +#ifndef NO_FW_PUNCH + /* Generate firewall hole as appropriate */ + PunchFWHole(dcc_link); +#endif + + alias_address = GetAliasAddress(link); + iCopy += snprintf(&newpacket[iCopy], + sizeof(newpacket)-iCopy, + "%lu ", (u_long)htonl(alias_address.s_addr)); + if( iCopy >= sizeof(newpacket) ) { /* Truncated/fit exactly - bad news */ + DBprintf(("DCC constructed packet overflow.\n")); + goto lBAD_CTCP; + } + alias_port = GetAliasPort(dcc_link); + iCopy += snprintf(&newpacket[iCopy], + sizeof(newpacket)-iCopy, + "%u", htons(alias_port) ); + /* Done - truncated cases will be taken care of by lBAD_CTCP */ + DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port)); + } + } + /* An uninteresting CTCP - state entered right after '\001' has + been pushed. Also used to copy the rest of a DCC, after IP + address and port has been handled */ + lBAD_CTCP: + for(; i<dlen && iCopy<sizeof(newpacket); i++,iCopy++) { + newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */ + if(sptr[i] == '\001') { + goto lNORMAL_TEXT; + } + } + goto lPACKET_DONE; + /* Normal text */ + lNORMAL_TEXT: + for(; i<dlen && iCopy<sizeof(newpacket); i++,iCopy++) { + newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */ + if(sptr[i] == '\001') { + goto lCTCP_START; + } + } + /* Handle the end of a packet */ + lPACKET_DONE: + iCopy = iCopy > maxsize-copyat ? maxsize-copyat : iCopy; + memcpy(sptr+copyat, newpacket, iCopy); + +/* Save information regarding modified seq and ack numbers */ + { + int delta; + + SetAckModified(link); + delta = GetDeltaSeqOut(pip, link); + AddSeq(pip, link, delta+copyat+iCopy-dlen); + } + + /* Revise IP header */ + { + u_short new_len; + + new_len = htons(hlen + iCopy + copyat); + DifferentialChecksum(&pip->ip_sum, + &new_len, + &pip->ip_len, + 1); + pip->ip_len = new_len; + } + + /* Compute TCP checksum for revised packet */ + tc->th_sum = 0; + tc->th_sum = TcpChecksum(pip); + return; + } +} + +/* Notes: + [Note 1] + The initial search will most often fail; it could be replaced with a 32-bit specific search. + Such a search would be done for 32-bit unsigned value V: + V ^= 0x01010101; (Search is for null bytes) + if( ((V-0x01010101)^V) & 0x80808080 ) { + (found a null bytes which was a 01 byte) + } + To assert that the processor is 32-bits, do + extern int ircdccar[32]; (32 bits) + extern int ircdccar[CHAR_BIT*sizeof(unsigned int)]; + which will generate a type-error on all but 32-bit machines. + + [Note 2] This routine really ought to be replaced with one that + creates a transparent proxy on the aliasing host, to allow arbitary + changes in the TCP stream. This should not be too difficult given + this base; I (ee) will try to do this some time later. + */ diff --git a/usr.sbin/ppp/libalias/alias_local.h b/usr.sbin/ppp/libalias/alias_local.h new file mode 100644 index 00000000000..0e94a64b281 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_local.h @@ -0,0 +1,107 @@ +/* -*- mode: c; tab-width: 3; c-basic-offset: 3; -*- + Alias_local.h contains the function prototypes for alias.c, + alias_db.c, alias_util.c and alias_ftp.c, alias_irc.c (as well + as any future add-ons). It is intended to be used only within + the aliasing software. Outside world interfaces are defined + in alias.h + + This software is placed into the public domain with no restrictions + on its distribution. + + Initial version: August, 1996 (cjm) + + <updated several times by original author and Eivind Eiklund> +*/ +#ifndef ALIAS_LOCAL_H +#define ALIAS_LOCAL_H + +extern int packetAliasMode; + +struct alias_link; + +/* General utilities */ +u_short IpChecksum(struct ip *); +u_short TcpChecksum(struct ip *); +void DifferentialChecksum(u_short *, u_short *, u_short *, int); + +/* Internal data access */ +struct alias_link * +FindIcmpIn(struct in_addr, struct in_addr, u_short); + +struct alias_link * +FindIcmpOut(struct in_addr, struct in_addr, u_short); + +struct alias_link * +FindFragmentIn1(struct in_addr, struct in_addr, u_short); + +struct alias_link * +FindFragmentIn2(struct in_addr, struct in_addr, u_short); + +struct alias_link * +AddFragmentPtrLink(struct in_addr, u_short); + +struct alias_link * +FindFragmentPtr(struct in_addr, u_short); + +struct alias_link * +FindUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char); + +struct alias_link * +FindUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char); + +struct in_addr +FindOriginalAddress(struct in_addr); + +struct in_addr +FindAliasAddress(struct in_addr); + +/* External data access/modification */ +void GetFragmentAddr(struct alias_link *, struct in_addr *); +void SetFragmentAddr(struct alias_link *, struct in_addr); +void GetFragmentPtr(struct alias_link *, char **); +void SetFragmentPtr(struct alias_link *, char *); +void SetStateIn(struct alias_link *, int); +void SetStateOut(struct alias_link *, int); +int GetStateIn(struct alias_link *); +int GetStateOut(struct alias_link *); +struct in_addr GetOriginalAddress(struct alias_link *); +struct in_addr GetDestAddress(struct alias_link *); +struct in_addr GetAliasAddress(struct alias_link *); +struct in_addr GetDefaultAliasAddress(void); +void SetDefaultAliasAddress(struct in_addr); +u_short GetOriginalPort(struct alias_link *); +u_short GetAliasPort(struct alias_link *); +void SetAckModified(struct alias_link *); +int GetAckModified(struct alias_link *); +int GetDeltaAckIn(struct ip *, struct alias_link *); +int GetDeltaSeqOut(struct ip *, struct alias_link *); +void AddSeq(struct ip *, struct alias_link *, int); +void SetExpire(struct alias_link *, int); +void ClearCheckNewLink(void); +#ifndef NO_FW_PUNCH +void PunchFWHole(struct alias_link *); +#endif + + +/* Housekeeping function */ +void HouseKeeping(void); + +/* Tcp specfic routines */ +/*lint -save -library Suppress flexelint warnings */ +void AliasHandleFtpOut(struct ip *, struct alias_link *, int); +void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize ); +void AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short); +void AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *); +void AliasHandleCUSeeMeOut(struct ip *, struct alias_link *); +void AliasHandleCUSeeMeIn(struct ip *, struct in_addr); + + + +enum alias_tcp_state { + ALIAS_TCP_STATE_NOT_CONNECTED, + ALIAS_TCP_STATE_CONNECTED, + ALIAS_TCP_STATE_DISCONNECTED +}; + +/*lint -restore */ +#endif /* defined(ALIAS_LOCAL_H) */ diff --git a/usr.sbin/ppp/libalias/alias_nbt.c b/usr.sbin/ppp/libalias/alias_nbt.c new file mode 100644 index 00000000000..e204758b3ea --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_nbt.c @@ -0,0 +1,576 @@ +/* + * Written by Atsushi Murai <amurai@spec.co.jp> + * + * Copyright (C) 1998, System Planning and Engineering Co. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the System Planning and Engineering Co. The name of the + * SPEC may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: alias_nbt.c,v 1.1 1998/08/31 00:22:10 brian Exp $ + * + * TODO: + * oClean up. + * oConsidering for word alignment for other platform. + */ +/* + alias_nbt.c performs special processing for NetBios over TCP/IP + sessions by UDP. + + Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) + + See HISTORY file for record of revisions. +*/ + +/* Includes */ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> + +#include "alias_local.h" + +#define ADJUST_CHECKSUM(acc, cksum) { \ + acc += cksum; \ + if (acc < 0) \ + { \ + acc = -acc; \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) ~acc; \ + } \ + else \ + { \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) acc; \ + } \ +} + +typedef struct { + struct in_addr oldaddr; + u_short oldport; + struct in_addr newaddr; + u_short newport; + u_short *uh_sum; +} NBTArguments; + +typedef struct { + unsigned char type; + unsigned char flags; + u_short id; + struct in_addr source_ip; + u_short source_port; + u_short len; + u_short offset; +} NbtDataHeader; + +#define OpQuery 0 +#define OpUnknown 4 +#define OpRegist 5 +#define OpRelease 6 +#define OpWACK 7 +#define OpRefresh 8 +typedef struct { + u_short nametrid; + u_short dir:1, opcode:4, nmflags:7, rcode:4; + u_short qdcount; + u_short ancount; + u_short nscount; + u_short arcount; +} NbtNSHeader; + +#define FMT_ERR 0x1 +#define SRV_ERR 0x2 +#define IMP_ERR 0x4 +#define RFS_ERR 0x5 +#define ACT_ERR 0x6 +#define CFT_ERR 0x7 + +/******************************************************************* + * copy an IP address from one buffer to another * + *******************************************************************/ +void putip(void *dest,void *src) +{ + memcpy(dest,src,4); +} + +void PrintRcode( u_char rcode ) { + + switch (rcode) { + case FMT_ERR: + printf("\nFormat Error."); + case SRV_ERR: + printf("\nSever failure."); + case IMP_ERR: + printf("\nUnsupported request error.\n"); + case RFS_ERR: + printf("\nRefused error.\n"); + case ACT_ERR: + printf("\nActive error.\n"); + case CFT_ERR: + printf("\nName in conflict error.\n"); + default: + printf("\n???=%0x\n", rcode ); + + } +} + + +/* Handling Name field */ +u_char *AliasHandleName ( u_char *p ) { + + u_char *s; + u_char c; + int compress; + + /* Following length field */ + if (*p & 0xc0 ) { + p = p + 2; + return ((u_char *)p); + } + while ( ( *p & 0x3f) != 0x00 ) { + s = p + 1; + if ( *p == 0x20 ) + compress = 1; + else + compress = 0; + + /* Get next length field */ + p = (u_char *)(p + (*p & 0x3f) + 1); +#ifdef DEBUG + printf(":"); +#endif + while (s < p) { + if ( compress == 1 ) { + c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11)); +#ifdef DEBUG + if (isprint( c ) ) + printf("%c", c ); + else + printf("<0x%02x>", c ); +#endif + s +=2; + } else { +#ifdef DEBUG + printf("%c", *s); +#endif + s++; + } + } +#ifdef DEBUG + printf(":"); +#endif + fflush(stdout); + } + + /* Set up to out of Name field */ + p++; + return ((u_char *)p); +} + +/* + * NetBios Datagram Handler (IP/UDP) + */ +#define DGM_DIRECT_UNIQ 0x10 +#define DGM_DIRECT_GROUP 0x11 +#define DGM_BROADCAST 0x12 +#define DGM_ERROR 0x13 +#define DGM_QUERY 0x14 +#define DGM_POSITIVE_RES 0x15 +#define DGM_NEGATIVE_RES 0x16 + +void AliasHandleUdpNbt( + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *link, + struct in_addr *alias_address, + u_short alias_port ) +{ + struct udphdr * uh; + NbtDataHeader *ndh; + u_char *p; + + /* Calculate data length of UDP packet */ + uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); + ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr))); +#ifdef DEBUG + printf("\nType=%02x,", ndh->type ); +#endif + switch ( ndh->type ) { + case DGM_DIRECT_UNIQ: + case DGM_DIRECT_GROUP: + case DGM_BROADCAST: + p = (u_char *)ndh + 14; + p = AliasHandleName ( p ); /* Source Name */ + p = AliasHandleName ( p ); /* Destination Name */ + break; + case DGM_ERROR: + p = (u_char *)ndh + 11; + break; + case DGM_QUERY: + case DGM_POSITIVE_RES: + case DGM_NEGATIVE_RES: + p = (u_char *)ndh + 10; + p = AliasHandleName ( p ); /* Destination Name */ + break; + } +#ifdef DEBUG + printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); +#endif + /* Doing a IP address and Port number Translation */ + if ( uh->uh_sum != 0 ) { + int acc; + u_short *sptr; + acc = ndh->source_port; + acc -= alias_port; + sptr = (u_short *) &(ndh->source_ip); + acc += *sptr++; + acc += *sptr; + sptr = (u_short *) alias_address; + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, uh->uh_sum) + } + ndh->source_ip = *alias_address; + ndh->source_port = alias_port; +#ifdef DEBUG + printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); + fflush(stdout); +#endif +} +/* Question Section */ +#define QS_TYPE_NB 0x0020 +#define QS_TYPE_NBSTAT 0x0021 +#define QS_CLAS_IN 0x0001 +typedef struct { + u_short type; /* The type of Request */ + u_short class; /* The class of Request */ +} NBTNsQuestion; + +u_char *AliasHandleQuestion(u_short count, + NBTNsQuestion *q, + NBTArguments *nbtarg) +{ + + while ( count != 0 ) { + /* Name Filed */ + q = (NBTNsQuestion *)AliasHandleName((u_char *)q ); + + /* Type and Class filed */ + switch ( ntohs(q->type) ) { + case QS_TYPE_NB: + case QS_TYPE_NBSTAT: + q= q+1; + break; + default: + printf("\nUnknown Type on Question %0x\n", ntohs(q->type) ); + break; + } + count--; + } + + /* Set up to out of Question Section */ + return ((u_char *)q); +} + +/* Resource Record */ +#define RR_TYPE_A 0x0001 +#define RR_TYPE_NS 0x0002 +#define RR_TYPE_NULL 0x000a +#define RR_TYPE_NB 0x0020 +#define RR_TYPE_NBSTAT 0x0021 +#define RR_CLAS_IN 0x0001 +#define SizeOfNsResource 8 +typedef struct { + u_short type; + u_short class; + unsigned int ttl; + u_short rdlen; +} NBTNsResource; + +#define SizeOfNsRNB 6 +typedef struct { + u_short g:1, ont:2, resv:13; + struct in_addr addr; +} NBTNsRNB; + +u_char *AliasHandleResourceNB( NBTNsResource *q, + NBTArguments *nbtarg) +{ + NBTNsRNB *nb; + u_short bcount; + + /* Check out a length */ + bcount = ntohs(q->rdlen); + + /* Forward to Resource NB position */ + nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource); + + /* Processing all in_addr array */ +#ifdef DEBUG + printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); + printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount); +#endif + while ( bcount != 0 ) { +#ifdef DEBUG + printf("<%s>", inet_ntoa(nb->addr) ); +#endif + if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) { + if ( *nbtarg->uh_sum != 0 ) { + int acc; + u_short *sptr; + + sptr = (u_short *) &(nb->addr); + acc = *sptr++; + acc += *sptr; + sptr = (u_short *) &(nbtarg->newaddr); + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) + } + + nb->addr = nbtarg->newaddr; +#ifdef DEBUG + printf("O"); +#endif + } +#ifdef DEBUG + else { + printf("."); + } +#endif + nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB); + bcount -= SizeOfNsRNB; + } + + return ((u_char *)nb); +} + +#define SizeOfResourceA 6 +typedef struct { + struct in_addr addr; +} NBTNsResourceA; + +u_char *AliasHandleResourceA( NBTNsResource *q, + NBTArguments *nbtarg) +{ + NBTNsResourceA *a; + u_short bcount; + + /* Forward to Resource A position */ + a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) ); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Processing all in_addr array */ +#ifdef DEBUG + printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); + printf("->%s]",inet_ntoa(nbtarg->newaddr )); +#endif + while ( bcount != 0 ) { +#ifdef DEBUG + printf("..%s", inet_ntoa(a->addr) ); +#endif + if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) { + if ( *nbtarg->uh_sum != 0 ) { + int acc; + u_short *sptr; + + sptr = (u_short *) &(a->addr); /* Old */ + acc = *sptr++; + acc += *sptr; + sptr = (u_short *) &nbtarg->newaddr; /* New */ + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) + } + + a->addr = nbtarg->newaddr; + } + a++; /*XXXX*/ + bcount -= SizeOfResourceA; + } + return ((u_char *)a); +} + +typedef struct { + u_short opcode:4, flags:8, resv:4; +} NBTNsResourceNULL; + +u_char *AliasHandleResourceNULL( NBTNsResource *q, + NBTArguments *nbtarg) +{ + NBTNsResourceNULL *n; + u_short bcount; + + /* Forward to Resource NULL position */ + n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Processing all in_addr array */ + while ( bcount != 0 ) { + n++; + bcount -= sizeof(NBTNsResourceNULL); + } + + return ((u_char *)n); +} + +u_char *AliasHandleResourceNS( NBTNsResource *q, + NBTArguments *nbtarg) +{ + NBTNsResourceNULL *n; + u_short bcount; + + /* Forward to Resource NULL position */ + n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Resource Record Name Filed */ + q = (NBTNsResource *)AliasHandleName( (u_char *)n ); /* XXX */ + + return ((u_char *)n + bcount); +} + +typedef struct { + u_short numnames; +} NBTNsResourceNBSTAT; + +u_char *AliasHandleResourceNBSTAT( NBTNsResource *q, + NBTArguments *nbtarg) +{ + NBTNsResourceNBSTAT *n; + u_short bcount; + + /* Forward to Resource NBSTAT position */ + n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) ); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + return ((u_char *)n + bcount); +} + +u_char *AliasHandleResource(u_short count, + NBTNsResource *q, + NBTArguments *nbtarg) +{ + while ( count != 0 ) { + /* Resource Record Name Filed */ + q = (NBTNsResource *)AliasHandleName( (u_char *)q ); +#ifdef DEBUG + printf("type=%02x, count=%d\n", ntohs(q->type), count ); +#endif + + /* Type and Class filed */ + switch ( ntohs(q->type) ) { + case RR_TYPE_NB: + q = (NBTNsResource *)AliasHandleResourceNB( q, nbtarg ); + break; + case RR_TYPE_A: + q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg ); + break; + case RR_TYPE_NS: + q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg ); + break; + case RR_TYPE_NULL: + q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg ); + break; + case RR_TYPE_NBSTAT: + q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg ); + break; + default: printf("\nUnknown Type of Resource %0x\n", + ntohs(q->type) ); + break; + } + count--; + } + fflush(stdout); + return ((u_char *)q); +} + +void AliasHandleUdpNbtNS( + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *link, + struct in_addr *alias_address, + u_short *alias_port, + struct in_addr *original_address, + u_short *original_port ) +{ + struct udphdr * uh; + NbtNSHeader * nsh; + u_short dlen; + u_char * p; + NBTArguments nbtarg; + + /* Set up Common Parameter */ + nbtarg.oldaddr = *alias_address; + nbtarg.oldport = *alias_port; + nbtarg.newaddr = *original_address; + nbtarg.newport = *original_port; + + /* Calculate data length of UDP packet */ + uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); + nbtarg.uh_sum = &(uh->uh_sum); + dlen = ntohs( uh->uh_ulen ); + nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr))); + p = (u_char *)(nsh + 1); + +#ifdef DEBUG + printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x, an=%04x, ns=%04x, ar=%04x, [%d]-->", + nsh->dir ? "Response": "Request", + nsh->nametrid, + nsh->opcode, + nsh->nmflags, + nsh->rcode, + ntohs(nsh->qdcount), + ntohs(nsh->ancount), + ntohs(nsh->nscount), + ntohs(nsh->arcount), + (u_char *)p -(u_char *)nsh); +#endif + + /* Question Entries */ + if (ntohs(nsh->qdcount) !=0 ) { + p = AliasHandleQuestion(ntohs(nsh->qdcount), (NBTNsQuestion *)p, &nbtarg ); + } + + /* Answer Resource Records */ + if (ntohs(nsh->ancount) !=0 ) { + p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg ); + } + + /* Authority Resource Recodrs */ + if (ntohs(nsh->nscount) !=0 ) { + p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg ); + } + + /* Additional Resource Recodrs */ + if (ntohs(nsh->arcount) !=0 ) { + p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg ); + } + +#ifdef DEBUG + PrintRcode(nsh->rcode); +#endif + return; +} diff --git a/usr.sbin/ppp/libalias/alias_old.c b/usr.sbin/ppp/libalias/alias_old.c new file mode 100644 index 00000000000..3f634d44841 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_old.c @@ -0,0 +1,77 @@ +/* + This file can be considered a junk pile of old functions that + are either obsolete or have had their names changed. In the + transition from alias2.1 to alias2.2, all the function names + were rationalized so that they began with "PacketAlias..." + + These functions are included for backwards compatibility. +*/ + +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include "alias.h" +#include "alias_local.h" + +void +InitPacketAlias(void) +{ + PacketAliasInit(); +} + +void +SetPacketAliasAddress(struct in_addr addr) +{ + PacketAliasSetAddress(addr); +} + +unsigned int +SetPacketAliasMode(unsigned int flags, unsigned int mask) +{ + return PacketAliasSetMode(flags, mask); +} + +int +PacketAliasPermanentLink(struct in_addr src_addr, u_short src_port, + struct in_addr dst_addr, u_short dst_port, + u_short alias_port, u_char proto) +{ + struct alias_link *link; + struct in_addr null_address; + + null_address.s_addr = 0; + link = PacketAliasRedirectPort(src_addr, src_port, + dst_addr, dst_port, + null_address, alias_port, + proto); + + if (link == NULL) + return -1; + else + return 0; +} + +int +SaveFragmentPtr(char *ptr) +{ + return PacketAliasSaveFragment(ptr); +} + +char * +GetNextFragmentPtr(char *ptr) +{ + return PacketAliasGetFragment(ptr); +} + +void +FragmentAliasIn(char *header, char *fragment) +{ + PacketAliasFragmentIn(header, fragment); +} + +u_short +InternetChecksum(u_short *ptr, int len) +{ + return PacketAliasInternetChecksum(ptr, len); +} diff --git a/usr.sbin/ppp/libalias/alias_util.c b/usr.sbin/ppp/libalias/alias_util.c new file mode 100644 index 00000000000..fe076531201 --- /dev/null +++ b/usr.sbin/ppp/libalias/alias_util.c @@ -0,0 +1,137 @@ +/* + Alias_util.h contains general utilities used by other functions + in the packet aliasing module. At the moment, there are functions + for computing IP header and TCP packet checksums. + + The checksum routines are based upon example code in a Unix networking + text written by Stevens (sorry, I can't remember the title -- but + at least this is a good author). + + Initial Version: August, 1996 (cjm) + + Version 1.7: January 9, 1997 + Added differential checksum update function. +*/ + +/* +Note: the checksum routines assume that the actual checksum word has +been zeroed out. If the checksum workd is filled with the proper value, +then these routines will give a result of zero (useful for testing +purposes); +*/ + +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include "alias.h" +#include "alias_local.h" + +u_short +PacketAliasInternetChecksum(u_short *ptr, int nbytes) +{ + int sum, oddbyte; + + sum = 0; + while (nbytes > 1) + { + sum += *ptr++; + nbytes -= 2; + } + if (nbytes == 1) + { + oddbyte = 0; + *((u_char *) &oddbyte) = *(u_char *) ptr; + sum += oddbyte; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return(~sum); +} + +u_short +IpChecksum(struct ip *pip) +{ + return( PacketAliasInternetChecksum((u_short *) pip, + (pip->ip_hl << 2)) ); + +} + +u_short +TcpChecksum(struct ip *pip) +{ + u_short *ptr; + struct tcphdr *tc; + int nhdr, ntcp, nbytes; + int sum, oddbyte; + + nhdr = pip->ip_hl << 2; + ntcp = ntohs(pip->ip_len) - nhdr; + + tc = (struct tcphdr *) ((char *) pip + nhdr); + ptr = (u_short *) tc; + +/* Add up TCP header and data */ + nbytes = ntcp; + sum = 0; + while (nbytes > 1) + { + sum += *ptr++; + nbytes -= 2; + } + if (nbytes == 1) + { + oddbyte = 0; + *((u_char *) &oddbyte) = *(u_char *) ptr; + sum += oddbyte; + } + +/* "Pseudo-header" data */ + ptr = (u_short *) &(pip->ip_dst); + sum += *ptr++; + sum += *ptr; + ptr = (u_short *) &(pip->ip_src); + sum += *ptr++; + sum += *ptr; + sum += htons((u_short) ntcp); + sum += htons((u_short) pip->ip_p); + +/* Roll over carry bits */ + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + +/* Return checksum */ + return((u_short) ~sum); +} + + +void +DifferentialChecksum(u_short *cksum, u_short *new, u_short *old, int n) +{ + int i; + int accumulate; + + accumulate = *cksum; + for (i=0; i<n; i++) + { + accumulate -= *new++; + accumulate += *old++; + } + + if (accumulate < 0) + { + accumulate = -accumulate; + accumulate = (accumulate >> 16) + (accumulate & 0xffff); + accumulate += accumulate >> 16; + *cksum = (u_short) ~accumulate; + } + else + { + accumulate = (accumulate >> 16) + (accumulate & 0xffff); + accumulate += accumulate >> 16; + *cksum = (u_short) accumulate; + } +} + diff --git a/usr.sbin/ppp/libalias/libalias.3 b/usr.sbin/ppp/libalias/libalias.3 new file mode 100644 index 00000000000..b3fcc912945 --- /dev/null +++ b/usr.sbin/ppp/libalias/libalias.3 @@ -0,0 +1,768 @@ +.Dd July, 1997 +.Dt "libalias" 3 +.Os +.Sh NAME +.Nm "libalias" +Packet Aliasing Library. A collection of +functions for aliasing and de-aliasing +of IP packets, intended for masquerading and +network address translation (NAT). + +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <netinet/in.h> +.Fd #include <alias.h> + +Function prototypes are given in the main body +of the text. + +.Sh CONTENTS +.Bd -literal -offset left +1. Introduction +2. Initialization and Control + 2.1 PacketAliasInit() + 2.2 PacketAliasUninit() + 2.3 PacketAliasSetAddress() + 2.4 PacketAliasSetMode() + 2.5 PacketAliasSetFWBase() +3. Packet Handling + 3.1 PacketAliasOut() + 3.2 PacketAliasIn() +4. Port and Address Redirection + 4.1 PacketAliasRedirectPort() + 4.2 PacketAliasRedirectAddr() + 4.3 PacketAliasRedirectDelete() +5. Fragment Handling + 5.1 PacketAliasSaveFragment() + 5.2 PacketAliasGetFragment() + 5.3 PacketAliasFragmentIn() +6. Miscellaneous Functions + 6.1 PacketAliasSetTarget() + 6.2 PacketAliasCheckNewLink() + 6.3 PacketAliasInternetChecksum() +7. Authors +8. Acknowledgments + +Appendix A: Conceptual Background + A.1 Aliasing Links + A.2 Static and Dynamic Links + A.3 Partially Specified Links + A.4 Dynamic Link Creation +.Ed + +.Sh 1. Introduction +This library is a moderately portable +set of functions designed to assist +in the process of IP masquerading and +network address translation. Outgoing +packets from a local network with +unregistered IP addresses can be aliased +to appear as if they came from an +accessible IP address. Incoming packets +are then de-aliased so that they are sent +to the correct machine on the local network. + +A certain amount of flexibility is built +into the packet aliasing engine. In +the simplest mode of operation, a +many-to-one address mapping takes place +between local network and the packet +aliasing host. This is known as IP +masquerading. In addition, one-to-one +mappings between local and public addresses +can also be implemented, which is known as +static NAT. In between these extremes, +different groups of private addresses +can be linked to different public addresses, +comprising several distinct many-to-one +mappings. Also, a given public address +and port can be statically redirected to +a private address/port. + +The packet aliasing engine was designed +to operate in user space outside of the +kernel, without any access to private +kernel data structure, but the source code +can also be ported to a kernel environment. + +.Sh 2. Initialization and Control +Two specific functions, PacketAliasInit() +and PacketAliasSetAddress(), must always be +called before any packet handling may be +performed. In addition, the operating mode +of the packet aliasing engine can be customized +by calling PacketAliasSetMode(). +.Ss 2.1 PacketAliasInit() + +.Ft void +.Fn PacketAliasInit "void" + +This function has no argument or return +value and is used to initialize internal +data structures. The following mode bits +are always set after calling +PacketAliasInit(). See section 2.3 for +the meaning of these mode bits. +.Bd -literal -offset indent + PKT_ALIAS_USE_SAME_PORTS + PKT_ALIAS_USE_SOCKETS + PKT_ALIAS_RESET_ON_ADDR_CHANGE + +.Ed +This function will always return the packet +aliasing engine to the same initial state. +PacketAliasSetAddress() must be called afterwards, +and any desired changes from the default mode +bits listed above require a call to +PacketAliasSetMode(). + +It is mandatory that this function be called +at the beginning of a program prior to any +packet handling. +.Ss 2.2 PacketAliasUninit() + +.Ft void +.Fn PacketAliasUninit "void" + +This function has no argument or return +value and is used to clear any resources +attached to internal data structures. + +This functions should be called when a +program stop using the aliasing engine; +it do, among other things, clear out any +firewall holes. To provide backwards +compatibility and extra security, it is +added to the atexit() chain by +PacketAliasInit(). Calling it multiple +times is harmless. +.Ss 2.3 PacketAliasSetAddress() + +.Ft void +.Fn PacketAliasSetAddress "struct in_addr addr" + +This function sets the source address to which +outgoing packets from the local area network +are aliased. All outgoing packets are remapped +to this address unless overridden by a static +address mapping established by +PacketAliasRedirectAddr(). + +If the PKT_ALIAS_RESET_ON_ADDR_CHANGE mode bit +is set (the default mode of operation), then +the internal aliasing link tables will be reset +any time the aliasing address changes, as if +PacketAliasReset() were called. This is useful +for interfaces such as ppp where the IP +address may or may not change on successive +dial-up attempts. + +If the PKT_ALIAS_RESET_ON_ADDR_CHANGE mode bit +is set to zero, this function can also be used to +dynamically change the aliasing address on a +packet to packet basis (it is a low overhead +call). + +It is mandatory that this function be called +prior to any packet handling. +.Ss 2.4 PacketAliasSetMode() + +.Ft unsigned int +.Fn PacketAliasSetMode "unsigned int mode" "unsigned int mask" + +This function sets or clears mode bits +according to the value of +.Em mode . +Only bits marked in +.Em mask +are affected. The following mode bits are +defined in alias.h: +.Bl -hang -offset left +.It PKT_ALIAS_LOG. +Enables logging /var/log/alias.log. The log file +shows total numbers of links (icmp, tcp, udp) each +time an aliasing link is created or deleted. Mainly +useful for debugging when the log file is viewed +continuously with "tail -f". +.It PKT_ALIAS_DENY_INCOMING. +If this mode bit is set, all incoming packets +associated with new TCP connections or new +UDP transactions will be marked for being +ignored (PacketAliasIn() return code +PKT_ALIAS_IGNORED) by the calling program. +Response packets to connections or transactions +initiated from the packet aliasing host or +local network will be unaffected. This mode +bit is useful for implementing a one-way firewall. +.It PKT_ALIAS_SAME_PORTS. +If this mode bit is set, the packet aliasing +engine will attempt to leave the alias port +numbers unchanged from the actual local port +number. This can be done as long as the +quintuple (proto, alias addr, alias port, +remote addr, remote port) is unique. If a +conflict exists, an new aliasing port number is +chosen even if this mode bit is set. +.It PKT_ALIAS_USE_SOCKETS. +This bit should be set when the the packet +aliasing host originates network traffic as +well as forwards it. When the packet aliasing +host is waiting for a connection from an +unknown host address or unknown port number +(e.g. an FTP data connection), this mode bit +specifies that a socket be allocated as a place +holder to prevent port conflicts. Once a +connection is established, usually within a +minute or so, the socket is closed. +.It PKT_ALIAS_UNREGISTERED_ONLY. +If this mode bit is set, traffic on the +local network which does not originate from +unregistered address spaces will be ignored. +Standard Class A, B and C unregistered addresses +are: +.Bd -literal -offset indent + 10.0.0.0 -> 10.255.255.255 (Class A subnet) + 172.16.0.0 -> 172.31.255.255 (Class B subnets) + 192.168.0.0 -> 192.168.255.255 (Class C subnets) + +.Ed +This option is useful in the case that +packet aliasing host has both registered and +unregistered subnets on different interfaces. +The registered subnet is fully accessible to +the outside world, so traffic from it doesn't +need to be passed through the packet aliasing +engine. +.It PKT_ALIAS_RESET_ON_ADDR_CHANGE. +When this mode bit is set and +PacketAliasSetAddress() is called to change +the aliasing address, the internal link table +of the packet aliasing engine will be cleared. +This operating mode is useful for ppp links +where the interface address can sometimes +change or remain the same between dial-ups. +If this mode bit is not set, it the link table +will never be reset in the event of an +address change. +.It PKT_ALIAS_PUNCH_FW. +This option make libalias `punch holes' in an +ipfw based firewall for FTP/IRC DCC connections. +The holes punched are bound by from/to IP address +and port; it will not be possible to use a hole +for another connection. A hole is removed when +the connection that use it die. To cater for +unexpected death of a program using libalias (e.g +kill -9), changing the state of the flag will +clear the entire ipfw range allocated for holes. +This will also happen on the initial call to +PacketAliasSetFWBase(). This call must happen +prior to setting this flag. + +.El + +.Ss 2.5 PacketAliasSetFWBase() + +.Ft void +.Fn PacketAliasSetFWBase "unsigned int base" "unsigned int num" + +Set IPFW range allocated for punching firewall holes (with the +PKT_ALIAS_PUNCH_FW flag). The range will be cleared for all rules on +initialization. + +.Sh 3. Packet Handling +The packet handling functions are used to +modify incoming (remote->local) and outgoing +(local->remote) packets. The calling program +is responsible for receiving and sending +packets via network interfaces. + +Along with PacketAliasInit() and PacketAliasSetAddress(), +the two packet handling functions, PacketAliasIn() +and PacketAliasOut(), comprise minimal set of functions +needed for a basic IP masquerading implementation. +.Ss 3.1 PacketAliasIn() + +.Ft int +.Fn PacketAliasIn "char *buffer" "int maxpacketsize" + +An incoming packet coming from a remote machine to +the local network is de-aliased by this function. +The IP packet is pointed to by +.Em buffer , +and +.Em maxpacketsize +indicates the size of the data structure containing +the packet and should be at least as large as the +actual packet size. + +Return codes: +.Bl -hang -offset left +.It PKT_ALIAS_ERROR. +An internal error within the packet aliasing +engine occurred. +.It PKT_ALIAS_OK. +The packet aliasing process was successful. +.It PKT_ALIAS_IGNORED. +The packet was ignored and not de-aliased. +This can happen if the protocal is unrecognized, +possibly an ICMP message type is not handled or +if incoming packets for new connections are being +ignored (see PKT_ALIAS_DENY_INCOMING in section +2.2). +.It PKT_ALIAS_UNRESOLVED_FRAGMENT. +This is returned when a fragment cannot be +resolved because the header fragment has not +been sent yet. In this situation, fragments +must be saved with PacketAliasSaveFragment() +until a header fragment is found. +.It PKT_ALIAS_FOUND_HEADER_FRAGMENT. +The packet aliasing process was successful, +and a header fragment was found. This is a +signal to retrieve any unresolved fragments +with PacketAliasGetFragment() and de-alias +them with PacketAliasFragmentIn(). +.El +.Ss 3.2 PacketAliasOut() + +.Ft int +.Fn PacketAliasIn "char *buffer" "int maxpacketsize" + +An outgoing packet coming from the local network +to a remote machine is aliased by this function. +The IP packet is pointed to by +.Em buffer r, +and +.Em maxpacketsize +indicates the maximum packet size permissible +should the packet length be changed. IP encoding +protocols place address and port information in +the encapsulated data stream which have to be +modified and can account for changes in packet +length. Well known examples of such protocols +are FTP and IRC DCC. + +Return codes: +.Bl -hang -offset left +.It PKT_ALIAS_ERROR. +An internal error within the packet aliasing +engine occurred. +.It PKT_ALIAS_OK. +The packet aliasing process was successful. +.It PKT_ALIAS_IGNORED. +The packet was ignored and not de-aliased. +This can happen if the protocal is unrecognized, +or possibly an ICMP message type is not handled. +.El + +.Sh 4. Port and Address Redirection +The functions described in this section allow machines +on the local network to be accessible in some degree +to new incoming connections from the external network. +Individual ports can be re-mapped or static network +address translations can be designated. +.Ss 4.1 PacketAliasRedirectPort() + +.Ft struct alias_link * +.Fo PacketAliasRedirectPort +.Fa "struct in_addr local_addr" +.Fa "u_short local_port" +.Fa "struct in_addr remote_addr" +.Fa "u_short remote_port" +.Fa "struct in_addr alias_addr" +.Fa "u_short alias_port" +.Fa "u_char proto" +.Fc + +This function specifies that traffic from a +given remote address/port to an alias address/port +be redirected to a specified local address/port. +The parameter +.Em proto +can be either IPPROTO_TCP or IPPROTO_UDP, as +defined in <netinet/in.h>. + +If +.Em local_addr +or +.Em alias_addr +is zero, this indicates that the packet aliasing +address as established by PacketAliasSetAddress() +is to be used. Even if PacketAliasAddress() is +called to change the address after PacketAliasRedirectPort() +is called, a zero reference will track this change. + +If +.Em remote_addr +is zero, this indicates to redirect packets from +any remote address. Likewise, if +.Em remote_port +is zero, this indicates to redirect packets originating +from any remote port number. Almost always, the remote +port specification will be zero, but non-zero remote +addresses can be sometimes be useful for firewalling. +If two calls to PacketAliasRedirectPort() overlap in +their address/port specifications, then the most recent +call will have precedence. + +This function returns a pointer which can subsequently +be used by PacketAliasRedirectDelete(). If NULL is +returned, then the function call did not complete +successfully. + +All port numbers are in network address byte order, +so it is necessary to use htons() to convert these +parameters from internally readable numbers to +network byte order. Addresses are also in network +byte order, which is implicit in the use of the +.Em struct in_addr +data type. +.Ss 4.2 PacketAliasRedirectAddr() + +.Ft struct alias_link * +.Fo PacketAliasRedirectAddr +.Fa "struct in_addr local_addr" +.Fa "struct in_addr alias_addr" +.Fc + +This function desgnates that all incoming +traffic to +.Em alias_addr +be redirected to +.Em local_addr. +Similarly, all outgoing traffic from +.Em local_addr +is aliased to +.Em alias_addr . + +If +.Em local_addr +or +.Em alias_addr +is zero, this indicates that the packet aliasing +address as established by PacketAliasSetAddress() +is to be used. Even if PacketAliasAddress() is +called to change the address after PacketAliasRedirectAddr() +is called, a zero reference will track this change. + +If subsequent calls to PacketAliasRedirectAddr() +use the same aliasing address, all new incoming +traffic to this aliasing address will be redirected +to the local address made in the last function call, +but new traffic all of the local machines designated +in the several function calls will be aliased to +the same address. Consider the following example: +.Bd -literal -offset left + PacketAliasRedirectAddr(inet_aton("192.168.0.2"), + inet_aton("141.221.254.101")); + PacketAliasRedirectAddr(inet_aton("192.168.0.3"), + inet_aton("141.221.254.101")); + PacketAliasRedirectAddr(inet_aton("192.168.0.4"), + inet_aton("141.221.254.101")); +.Ed + +Any outgoing connections such as telnet or ftp +from 192.168.0.2, 102.168.0.3, 192.168.0.4 will +appear to come from 141.221.254.101. Any incoming +connections to 141.221.254.101 will be directed +to 192.168.0.4. + +Any calls to PacketAliasRedirectPort() will +have precedence over address mappings designated +by PacketAliasRedirectAddr(). + +This function returns a pointer which can subsequently +be used by PacketAliasRedirectDelete(). If NULL is +returned, then the function call did not complete +successfully. +.Ss 4.3 PacketAliasRedirectDelete() + +.Ft void +.Fn PacketAliasRedirectDelete "struct alias_link *ptr" + +This function will delete a specific static redirect +rule entered by PacketAliasRedirectPort() or +PacketAliasRedirectAddr(). The parameter +.Em ptr +is the pointer returned by either of the redirection +functions. If an invalid pointer is passed to +PacketAliasRedirectDelete(), then a program crash +or unpredictable operation could result, so it is +necessary to be careful using this function. + +.Sh 5. Fragment Handling +The functions in this section are used to deal with +incoming fragments. + +Outgoing fragments are handled within PacketAliasOut() +by changing the address according to any +applicable mapping set by PacketAliasRedirectAddress(), +or the default aliasing address set by +PacketAliasSetAddress(). + +Incoming fragments are handled in one of two ways. +If the header of a fragmented IP packet has already +been seen, then all subsequent fragments will be +re-mapped in the same manner the header fragment +was. Fragments which arrive before the header +are saved and then retrieved once the header fragment +has been resolved. +.Ss 5.1 PacketAliasSaveFragment() + +.Ft int +.Fn PacketAliasSaveFragment "char *ptr" + +When PacketAliasIn() returns +PKT_ALIAS_UNRESOLVED_FRAGMENT, this +function can be used to save the pointer to +the unresolved fragment. + +It is implicitly assumed that +.Em ptr +points to a block of memory allocated by +malloc(). If the fragment is never +resolved, the packet aliasing engine will +automatically free the memory after a +timeout period. [Eventually this function +should be modified so that a callback +function for freeing memory is passed as +an argument.] + +This function returns PKT_ALIAS_OK if it +was successful and PKT_ALIAS_ERROR if there +was an error. +.Ss 5.2 PacketAliasGetNextFragment() + +.Ft char * +.Fn PacketAliasGetFragment "char *buffer" + +This function can be used to retrieve fragment +pointers saved by PacketAliasSaveFragment(). +The IP header fragment pointed to by +Em buffer +is the header fragment indicated when +PacketAliasIn() returns PKT_ALIAS_FOUND_HEADER_FRAGMENT. +Once a a fragment pointer is retrieved, it +becomes the calling program's responsibility +to free the dynamically allocated memory for +the fragment. + +PacketAliasGetFragment() can be called +sequentially until there are no more fragments +available, at which time it returns NULL. +.Ss 5.3 PacketAliasFragmentIn() + +.Ft void +.Fn PacketAliasFragmentIn "char *header" "char *fragment" + +When a fragment is retrieved with +PacketAliasGetFragment(), it can then be +de-aliased with a call to PacketAliasFragmentIn(). +.Em header +is the pointer to a header fragment used as a +template, and +.Em fragment +is the pointer to the packet to be de-aliased. + +.Sh 6. Miscellaneous Functions + +.Ss 6.1 PacketAliasSetTarget() + +.Ft void +.Fn PacketAliasSetTarget "struct in_addr addr" + +When an incoming packet not associated with +any pre-existing aliasing link arrives at the +host machine, it will be sent to the address +indicated by a call to PacketAliasSetTarget(). + +If this function is not called, or is called +with a zero address argument, then all new +incoming packets go to the address set by +PacketAliasSetAddress. +.Ss 6.2 PacketAliasCheckNewLink() + +.Ft int +.Fn PacketAliasCheckNewLink "void" + +This function returns a non-zero value when +a new aliasing link is created. In circumstances +where incoming traffic is being sequentially +sent to different local servers, this function +can be used to trigger when PacketAliasSetTarget() +is called to change the default target address. +.Ss 6.3 PacketAliasInternetChecksum() + +.Ft u_short +.Fn PacketAliasInternetChecksum "u_short *buffer" "int nbytes" + +This is a utility function that does not seem +to be available elswhere and is included as a +convenience. It computes the internet checksum, +which is used in both IP and protocol-specific +headers (TCP, UDP, ICMP). + +.Em buffer +points to the data block to be checksummed, and +.Em nbytes +is the number of bytes. The 16-bit checksum +field should be zeroed before computing the checksum. + +Checksums can also be verified by operating on a block +of data including its checksum. If the checksum is +valid, PacketAliasInternetChecksum() will return zero. + +.Sh 7. Authors +Charles Mott (cmott@srv.net), versions 1.0 - 1.8, 2.0 - 2.4. + +Eivind Eklund (eivind@freebsd.org), versions 1.8b, 1.9 and +2.5. Added IRC DCC support as well as contributing a number of +architectural improvements; added the firewall bypass +for FTP/IRC DCC. + +.Sh 8. Acknowledgments + +Listed below, in approximate chronological +order, are individuals who have provided +valuable comments and/or debugging assistance. + +.Bl -inset -compact -offset left +.It Gary Roberts +.It Tom Torrance +.It Reto Burkhalter +.It Martin Renters +.It Brian Somers +.It Paul Traina +.It Ari Suutari +.It Dave Remien +.It J. Fortes +.It Andrzej Bialeki +.It Gordon Burditt +.El + +.Sh Appendix: Conceptual Background +This appendix is intended for those who +are planning to modify the source code or want +to create somewhat esoteric applications using +the packet aliasing functions. + +The conceptual framework under which the +packet aliasing engine operates is described here. +Central to the discussion is the idea of an +"aliasing link" which describes the relationship +for a given packet transaction between the local +machine, aliased identity and remote machine. It +is discussed how such links come into existence +and are destroyed. +.Ss A.1 Aliasing Links +There is a notion of an "aliasing link", +which is 7-tuple describing a specific +translation: +.Bd -literal -offset indent +(local addr, local port, alias addr, alias port, + remote addr, remote port, protocol) +.Ed + +Outgoing packets have the local address and +port number replaced with the alias address +and port number. Incoming packets undergo the +reverse process. The packet aliasing engine +attempts to match packets against an internal +table of aliasing links to determine how to +modify a given IP packet. Both the IP +header and protocol dependent headers are +modified as necessary. Aliasing links are +created and deleted as necessary according +to network traffic. + +Protocols can be TCP, UDP or even ICMP in +certain circumstances. (Some types of ICMP +packets can be aliased according to sequence +or id number which acts as an equivalent port +number for identifying how individual packets +should be handled.) + +Each aliasing link must have a unique +combination of the following five quantities: +alias address/port, remote address/port +and protocol. This ensures that several +machines on a local network can share the +same aliased IP address. In cases where +conflicts might arise, the aliasing port +is chosen so that uniqueness is maintained. +.Ss A.2 Static and Dynamic Links +Aliasing links can either be static or dynamic. +Static links persist indefinitely and represent +fixed rules for translating IP packets. Dynamic +links come into existence for a specific TCP +connection or UDP transaction or ICMP echo +sequence. For the case of TCP, the connection +can be monitored to see when the associated +aliasing link should be deleted. Aliasing links +for UDP transactions (and ICMP echo and timestamp +requests) work on a simple timeout rule. When +no activity is observed on a dynamic link for +a certain amount of time it is automatically +deleted. Timeout rules also apply to TCP +connections which do not open or close +properly. +.Ss A.3 Partially Specified Aliasing Links +Aliasing links can be partially specified, +meaning that the remote address and/or remote +ports are unknown. In this case, when a packet +matching the incomplete specification is found, +a fully specified dynamic link is created. If +the original partially specified link is dynamic, +it will be deleted after the fully specified link +is created, otherwise it will persist. + +For instance, a partially specified link might +be +.Bd -literal -offset indent +(192.168.0.4, 23, 204.228.203.215, 8066, 0, 0, tcp) +.Ed + +The zeros denote unspecified components for +the remote address and port. If this link were +static it would have the effect of redirecting +all incoming traffic from port 8066 of +204.228.203.215 to port 23 (telnet) of machine +192.168.0.4 on the local network. Each +individual telnet connection would initiate +the creation of a distinct dynamic link. +.Ss A.4 Dynamic Link Creation +In addition to aliasing links, there are +also address mappings that can be stored +within the internal data table of the packet +aliasing mechanism. +.Bd -literal -offset indent +(local addr, alias addr) +.Ed + +Address mappings are searched when creating +new dynamic links. + +All outgoing packets from the local network +automatically create a dynamic link if +they do not match an already existing fully +specified link. If an address mapping exists +for the the outgoing packet, this determines +the alias address to be used. If no mapping +exists, then a default address, usually the +address of the packet aliasing host, is used. +If necessary, this default address can be +changed as often as each individual packet +arrives. + +The aliasing port number is determined +such that the new dynamic link does not +conflict with any existing links. In the +default operating mode, the packet aliasing +engine attempts to set the aliasing port +equal to the local port number. If this +results in a conflict, then port numbers +are randomly chosen until a unique aliasing +link can be established. In an alternate +operating mode, the first choice of an +aliasing port is also random and unrelated +to the local port number. + diff --git a/usr.sbin/ppp/log.c b/usr.sbin/ppp/log.c deleted file mode 100644 index edde6dcd0e4..00000000000 --- a/usr.sbin/ppp/log.c +++ /dev/null @@ -1,246 +0,0 @@ -/*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: log.c,v 1.5 1998/03/13 01:50:42 brian Exp $ - */ - -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <syslog.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "loadalias.h" -#include "defs.h" -#include "vars.h" - -static const char *LogNames[] = { - "Async", - "Carrier", - "CCP", - "Chat", - "Command", - "Connect", - "Debug", - "HDLC", - "ID0", - "IPCP", - "LCP", - "Link", - "LQM", - "Phase", - "TCP/IP", - "Tun", - "Warning", - "Error", - "Alert" -}; - -#define MSK(n) (1<<((n)-1)) - -static u_long LogMask = MSK(LogLINK) | MSK(LogCARRIER) | MSK(LogPHASE); -static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); -static int LogTunno = -1; - -static int -syslogLevel(int lev) -{ - switch (lev) { - case LogDEBUG:return LOG_DEBUG; - case LogWARN: - return LOG_WARNING; - case LogERROR: - return LOG_ERR; - case LogALERT: - return LOG_ALERT; - } - return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0; -} - -const char * -LogName(int id) -{ - return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1]; -} - -void -LogKeep(int id) -{ - if (id >= LogMIN && id <= LogMAXCONF) - LogMask |= MSK(id); -} - -void -LogKeepLocal(int id) -{ - if (id >= LogMIN && id <= LogMAXCONF) - LogMaskLocal |= MSK(id); -} - -void -LogDiscard(int id) -{ - if (id >= LogMIN && id <= LogMAXCONF) - LogMask &= ~MSK(id); -} - -void -LogDiscardLocal(int id) -{ - if (id >= LogMIN && id <= LogMAXCONF) - LogMaskLocal &= ~MSK(id); -} - -void -LogDiscardAll() -{ - LogMask = 0; -} - -void -LogDiscardAllLocal() -{ - LogMaskLocal = 0; -} - -int -LogIsKept(int id) -{ - if (id < LogMIN || id > LogMAX) - return 0; - if (id > LogMAXCONF) - return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG; - - return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) | - ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0); -} - -void -LogOpen(const char *Name) -{ - openlog(Name, LOG_PID, LOG_DAEMON); -} - -void -LogSetTun(int tunno) -{ - LogTunno = tunno; -} - -void -LogClose() -{ - closelog(); - LogTunno = -1; -} - -void -LogPrintf(int lev, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - if (LogIsKept(lev)) { - static char nfmt[200]; - - if ((LogIsKept(lev) & LOG_KEPT_LOCAL) && VarTerm) { - if ((LogIsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1) - snprintf(nfmt, sizeof nfmt, "tun%d: %s: %s", - LogTunno, LogName(lev), fmt); - else - snprintf(nfmt, sizeof nfmt, "%s: %s", LogName(lev), fmt); - vfprintf(VarTerm, nfmt, ap); - fflush(VarTerm); - } - - if ((LogIsKept(lev) & LOG_KEPT_SYSLOG) && (lev != LogWARN || !VarTerm)) { - if ((LogIsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1) - snprintf(nfmt, sizeof nfmt, "tun%d: %s: %s", - LogTunno, LogName(lev), fmt); - else - snprintf(nfmt, sizeof nfmt, "%s: %s", LogName(lev), fmt); - vsyslog(syslogLevel(lev), nfmt, ap); - } - } - va_end(ap); -} - -void -LogDumpBp(int lev, const char *hdr, const struct mbuf * bp) -{ - if (LogIsKept(lev)) { - char buf[50]; - char *b; - u_char *ptr; - int f; - - if (hdr && *hdr) - LogPrintf(lev, "%s\n", hdr); - - b = buf; - do { - f = bp->cnt; - ptr = MBUF_CTOP(bp); - while (f--) { - sprintf(b, " %02x", (int) *ptr++); - b += 3; - if (b == buf + sizeof buf - 2) { - strcpy(b, "\n"); - LogPrintf(lev, buf); - b = buf; - } - } - } while ((bp = bp->next) != NULL); - - if (b > buf) { - strcpy(b, "\n"); - LogPrintf(lev, buf); - } - } -} - -void -LogDumpBuff(int lev, const char *hdr, const u_char * ptr, int n) -{ - if (LogIsKept(lev)) { - char buf[50]; - char *b; - - if (hdr && *hdr) - LogPrintf(lev, "%s\n", hdr); - while (n > 0) { - b = buf; - for (b = buf; b != buf + sizeof buf - 2 && n--; b += 3) - sprintf(b, " %02x", (int) *ptr++); - strcpy(b, "\n"); - LogPrintf(lev, buf); - } - } -} diff --git a/usr.sbin/ppp/lqr.c b/usr.sbin/ppp/lqr.c deleted file mode 100644 index 2ccd99cf0be..00000000000 --- a/usr.sbin/ppp/lqr.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * PPP Line Quality Monitoring (LQM) Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: lqr.c,v 1.7 1998/06/28 09:41:41 brian Exp $ - * - * o LQR based on RFC1333 - * - * TODO: - * o LQM policy - * o Allow user to configure LQM method and interval. - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <string.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "lcpproto.h" -#include "lqr.h" -#include "hdlc.h" -#include "lcp.h" -#include "loadalias.h" -#include "vars.h" - -struct lqrdata MyLqrData, HisLqrData; -struct lqrsave HisLqrSave; - -static struct pppTimer LqrTimer; - -static u_int32_t lastpeerin = (u_int32_t) - 1; - -static int lqmmethod; -static u_int32_t echoseq; -static u_int32_t gotseq; -static int lqrsendcnt; - -struct echolqr { - u_int32_t magic; - u_int32_t signature; - u_int32_t sequence; -}; - -#define SIGNATURE 0x594e4f54 - -static void -SendEchoReq(void) -{ - struct fsm *fp = &LcpFsm; - struct echolqr *lqr, lqrdata; - - if (fp->state == ST_OPENED) { - lqr = &lqrdata; - lqr->magic = htonl(LcpInfo.want_magic); - lqr->signature = htonl(SIGNATURE); - LogPrintf(LogLQM, "Send echo LQR [%d]\n", echoseq); - lqr->sequence = htonl(echoseq++); - FsmOutput(fp, CODE_ECHOREQ, fp->reqid++, - (u_char *) lqr, sizeof(struct echolqr)); - } -} - -void -RecvEchoLqr(struct mbuf * bp) -{ - struct echolqr *lqr; - u_int32_t seq; - - if (plength(bp) == sizeof(struct echolqr)) { - lqr = (struct echolqr *) MBUF_CTOP(bp); - if (htonl(lqr->signature) == SIGNATURE) { - seq = ntohl(lqr->sequence); - LogPrintf(LogLQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence)); - /* careful not to update gotseq with older values */ - if ((gotseq > (u_int32_t)0 - 5 && seq < 5) || - (gotseq <= (u_int32_t)0 - 5 && seq > gotseq)) - gotseq = seq; - } - } -} - -void -LqrChangeOrder(struct lqrdata * src, struct lqrdata * dst) -{ - u_int32_t *sp, *dp; - int n; - - sp = (u_int32_t *) src; - dp = (u_int32_t *) dst; - for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_int32_t); n++) - *dp++ = ntohl(*sp++); -} - -static void -SendLqrReport(void *v) -{ - struct mbuf *bp; - - StopTimer(&LqrTimer); - - if (lqmmethod & LQM_LQR) { - if (lqrsendcnt > 5) { - /* - * XXX: Should implement LQM strategy - */ - LogPrintf(LogPHASE, "** Too many LQR packets lost **\n"); - LogPrintf(LogLQM, "LqrOutput: Too many LQR packets lost\n"); - lqmmethod = 0; /* Prevent recursion via LcpClose() */ - reconnect(RECON_TRUE); - LcpClose(); - } else { - bp = mballoc(sizeof(struct lqrdata), MB_LQR); - HdlcOutput(PRI_LINK, PROTO_LQR, bp); - lqrsendcnt++; - } - } else if (lqmmethod & LQM_ECHO) { - if ((echoseq > 5 && echoseq - 5 > gotseq) || - (echoseq <= 5 && echoseq > gotseq + 5)) { - LogPrintf(LogPHASE, "** Too many ECHO LQR packets lost **\n"); - LogPrintf(LogLQM, "LqrOutput: Too many ECHO LQR packets lost\n"); - lqmmethod = 0; /* Prevent recursion via LcpClose() */ - reconnect(RECON_TRUE); - LcpClose(); - } else - SendEchoReq(); - } - if (lqmmethod && LqrTimer.load) - StartTimer(&LqrTimer); -} - -void -LqrInput(struct mbuf * bp) -{ - int len; - u_char *cp; - struct lqrdata *lqr; - - len = plength(bp); - if (len != sizeof(struct lqrdata)) { - pfree(bp); - return; - } - if (!Acceptable(ConfLqr)) { - bp->offset -= 2; - bp->cnt += 2; - - cp = MBUF_CTOP(bp); - LcpSendProtoRej(cp, bp->cnt); - } else { - cp = MBUF_CTOP(bp); - lqr = (struct lqrdata *) cp; - if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) { - LogPrintf(LogERROR, "LqrInput: magic %x != expecting %x\n", - ntohl(lqr->MagicNumber), LcpInfo.his_magic); - pfree(bp); - return; - } - - /* - * Convert byte order and save into our strage - */ - LqrChangeOrder(lqr, &HisLqrData); - LqrDump("LqrInput", &HisLqrData); - lqrsendcnt = 0; /* we have received LQR from peer */ - - /* - * Generate an LQR response to peer we're not running LQR timer OR - * two successive LQR's PeerInLQRs are same OR we're not going to - * send our next one before the peers max timeout. - */ - if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs || - (LqrTimer.arg && - LqrTimer.rest * 100 / SECTICKS > (u_long)LqrTimer.arg)) { - lqmmethod |= LQM_LQR; - SendLqrReport(LqrTimer.arg); - } - lastpeerin = HisLqrData.PeerInLQRs; - } - pfree(bp); -} - -/* - * When LCP is reached to opened state, We'll start LQM activity. - */ -void -StartLqm() -{ - struct lcpstate *lcp = &LcpInfo; - - lqrsendcnt = 0; /* start waiting all over for ECHOs */ - echoseq = 0; - gotseq = 0; - memset(&HisLqrData, '\0', sizeof HisLqrData); - - lqmmethod = LQM_ECHO; - if (Enabled(ConfLqr) && !REJECTED(lcp, TY_QUALPROTO)) - lqmmethod |= LQM_LQR; - StopTimer(&LqrTimer); - - if (lcp->his_lqrperiod) - LogPrintf(LogLQM, "Expecting LQR every %d.%02d secs\n", - lcp->his_lqrperiod / 100, lcp->his_lqrperiod % 100); - - if (lcp->want_lqrperiod) { - LogPrintf(LogLQM, "Will send %s every %d.%02d secs\n", - lqmmethod & LQM_LQR ? "LQR" : "ECHO LQR", - lcp->want_lqrperiod / 100, lcp->want_lqrperiod % 100); - LqrTimer.state = TIMER_STOPPED; - LqrTimer.load = lcp->want_lqrperiod * SECTICKS / 100; - LqrTimer.func = SendLqrReport; - LqrTimer.arg = (void *)(u_long)lcp->his_lqrperiod; - SendLqrReport(LqrTimer.arg); - } else { - LqrTimer.load = 0; - if (!lcp->his_lqrperiod) - LogPrintf(LogLQM, "LQR/ECHO LQR not negotiated\n"); - } -} - -void -StopLqrTimer() -{ - StopTimer(&LqrTimer); -} - -void -StopLqr(int method) -{ - LogPrintf(LogLQM, "StopLqr method = %x\n", method); - - if (method == LQM_LQR) - LogPrintf(LogLQM, "Stop sending LQR, Use LCP ECHO instead.\n"); - if (method == LQM_ECHO) - LogPrintf(LogLQM, "Stop sending LCP ECHO.\n"); - lqmmethod &= ~method; - if (lqmmethod) - SendLqrReport(LqrTimer.arg); - else - StopTimer(&LqrTimer); -} - -void -LqrDump(const char *message, const struct lqrdata * lqr) -{ - if (LogIsKept(LogLQM)) { - LogPrintf(LogLQM, "%s:\n", message); - LogPrintf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", - lqr->MagicNumber, lqr->LastOutLQRs); - LogPrintf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", - lqr->LastOutPackets, lqr->LastOutOctets); - LogPrintf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", - lqr->PeerInLQRs, lqr->PeerInPackets); - LogPrintf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", - lqr->PeerInDiscards, lqr->PeerInErrors); - LogPrintf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", - lqr->PeerInOctets, lqr->PeerOutLQRs); - LogPrintf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", - lqr->PeerOutPackets, lqr->PeerOutOctets); - } -} diff --git a/usr.sbin/ppp/lqr.h b/usr.sbin/ppp/lqr.h deleted file mode 100644 index 6b260e298bc..00000000000 --- a/usr.sbin/ppp/lqr.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: lqr.h,v 1.3 1998/01/21 02:13:36 brian Exp $ - * - * TODO: - */ - -/* - * Structure of LQR packet defined in RFC1333 - */ -struct lqrdata { - u_int32_t MagicNumber; - u_int32_t LastOutLQRs; - u_int32_t LastOutPackets; - u_int32_t LastOutOctets; - u_int32_t PeerInLQRs; - u_int32_t PeerInPackets; - u_int32_t PeerInDiscards; - u_int32_t PeerInErrors; - u_int32_t PeerInOctets; - u_int32_t PeerOutLQRs; - u_int32_t PeerOutPackets; - u_int32_t PeerOutOctets; -}; - -struct lqrsave { - u_int32_t SaveInLQRs; - u_int32_t SaveInPackets; - u_int32_t SaveInDiscards; - u_int32_t SaveInErrors; - u_int32_t SaveInOctets; -}; - -extern struct lqrdata MyLqrData, HisLqrData; -extern struct lqrsave HisLqrSave; - -/* - * We support LQR and ECHO as LQM method - */ -#define LQM_LQR 1 -#define LQM_ECHO 2 - -extern void LqrDump(const char *, const struct lqrdata *); -extern void LqrChangeOrder(struct lqrdata *, struct lqrdata *); -extern void StartLqm(void); -extern void StopLqr(int); -extern void StopLqrTimer(void); -extern void RecvEchoLqr(struct mbuf *); -extern void LqrInput(struct mbuf *); diff --git a/usr.sbin/ppp/main.c b/usr.sbin/ppp/main.c deleted file mode 100644 index bbbc33a16c7..00000000000 --- a/usr.sbin/ppp/main.c +++ /dev/null @@ -1,1103 +0,0 @@ -/* - * User Process PPP - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: main.c,v 1.20 1998/06/28 09:41:43 brian Exp $ - * - * TODO: - * o Add commands for traffic summary, version display, etc. - * o Add signal handler for misc controls. - */ -#include <sys/param.h> -#include <sys/time.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <arpa/inet.h> - -#include <errno.h> -#include <fcntl.h> -#include <paths.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <termios.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "id.h" -#include "timer.h" -#include "fsm.h" -#include "modem.h" -#include "os.h" -#include "hdlc.h" -#include "lcp.h" -#include "ccp.h" -#include "ipcp.h" -#include "loadalias.h" -#include "vars.h" -#include "auth.h" -#include "filter.h" -#include "systems.h" -#include "ip.h" -#include "sig.h" -#include "server.h" -#include "main.h" -#include "vjcomp.h" -#include "async.h" -#include "pathnames.h" -#include "tun.h" -#include "route.h" - -#ifndef O_NONBLOCK -#ifdef O_NDELAY -#define O_NONBLOCK O_NDELAY -#endif -#endif - -int TermMode = 0; -int tunno = 0; - -static struct termios oldtio; /* Original tty mode */ -static struct termios comtio; /* Command level tty mode */ -static pid_t BGPid = 0; -static char pid_filename[MAXPATHLEN]; -static int dial_up; - -static void DoLoop(void); -static void TerminalStop(int); -static const char *ex_desc(int); - -static void -TtyInit(int DontWantInt) -{ - struct termios newtio; - int stat; - - stat = fcntl(netfd, F_GETFL, 0); - if (stat > 0) { - stat |= O_NONBLOCK; - (void) fcntl(netfd, F_SETFL, stat); - } - newtio = oldtio; - newtio.c_lflag &= ~(ECHO | ISIG | ICANON); - newtio.c_iflag = 0; - newtio.c_oflag &= ~OPOST; - newtio.c_cc[VEOF] = _POSIX_VDISABLE; - if (DontWantInt) - newtio.c_cc[VINTR] = _POSIX_VDISABLE; - newtio.c_cc[VMIN] = 1; - newtio.c_cc[VTIME] = 0; - newtio.c_cflag |= CS8; - tcsetattr(netfd, TCSANOW, &newtio); - comtio = newtio; -} - -/* - * Set tty into command mode. We allow canonical input and echo processing. - */ -void -TtyCommandMode(int prompt) -{ - struct termios newtio; - int stat; - - if (!(mode & MODE_INTER)) - return; - tcgetattr(netfd, &newtio); - newtio.c_lflag |= (ECHO | ISIG | ICANON); - newtio.c_iflag = oldtio.c_iflag; - newtio.c_oflag |= OPOST; - tcsetattr(netfd, TCSADRAIN, &newtio); - stat = fcntl(netfd, F_GETFL, 0); - if (stat > 0) { - stat |= O_NONBLOCK; - (void) fcntl(netfd, F_SETFL, stat); - } - TermMode = 0; - if (prompt) - Prompt(); -} - -/* - * Set tty into terminal mode which is used while we invoke term command. - */ -void -TtyTermMode() -{ - int stat; - - tcsetattr(netfd, TCSADRAIN, &comtio); - stat = fcntl(netfd, F_GETFL, 0); - if (stat > 0) { - stat &= ~O_NONBLOCK; - (void) fcntl(netfd, F_SETFL, stat); - } - TermMode = 1; -} - -void -TtyOldMode() -{ - int stat; - - stat = fcntl(netfd, F_GETFL, 0); - if (stat > 0) { - stat &= ~O_NONBLOCK; - (void) fcntl(netfd, F_SETFL, stat); - } - tcsetattr(netfd, TCSADRAIN, &oldtio); -} - -void -Cleanup(int excode) -{ - DropClient(1); - ServerClose(); - OsInterfaceDown(1); - HangupModem(1); - nointr_sleep(1); - DeleteIfRoutes(1); - ID0unlink(pid_filename); - if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { - char c = EX_ERRDEAD; - - if (write(BGFiledes[1], &c, 1) == 1) - LogPrintf(LogPHASE, "Parent notified of failure.\n"); - else - LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); - close(BGFiledes[1]); - } - LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); - TtyOldMode(); - LogClose(); - - exit(excode); -} - -static void -CloseConnection(int signo) -{ - /* NOTE, these are manual, we've done a setsid() */ - pending_signal(SIGINT, SIG_IGN); - LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); - reconnectState = RECON_FALSE; - reconnectCount = 0; - DownConnection(); - dial_up = 0; - pending_signal(SIGINT, CloseConnection); -} - -static void -CloseSession(int signo) -{ - if (BGPid) { - kill(BGPid, SIGINT); - exit(EX_TERM); - } - LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); - reconnect(RECON_FALSE); - LcpClose(); - Cleanup(EX_TERM); -} - -static void -TerminalCont(int signo) -{ - pending_signal(SIGCONT, SIG_DFL); - pending_signal(SIGTSTP, TerminalStop); - TtyCommandMode(getpgrp() == tcgetpgrp(netfd)); -} - -static void -TerminalStop(int signo) -{ - pending_signal(SIGCONT, TerminalCont); - TtyOldMode(); - pending_signal(SIGTSTP, SIG_DFL); - kill(getpid(), signo); -} - -static void -SetUpServer(int signo) -{ - int res; - - VarHaveLocalAuthKey = 0; - LocalAuthInit(); - if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) - LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", - res, SERVER_PORT + tunno); -} - -static void -BringDownServer(int signo) -{ - VarHaveLocalAuthKey = 0; - LocalAuthInit(); - ServerClose(); -} - -static const char * -ex_desc(int ex) -{ - static char num[12]; - static const char *desc[] = { - "normal", "start", "sock", "modem", "dial", "dead", "done", - "reboot", "errdead", "hangup", "term", "nodial", "nologin" - }; - - if (ex >= 0 && ex < sizeof desc / sizeof *desc) - return desc[ex]; - snprintf(num, sizeof num, "%d", ex); - return num; -} - -static void -Usage(void) -{ - fprintf(stderr, - "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" -#ifndef NOALIAS - " [ -alias ]" -#endif - " [system]\n"); - exit(EX_START); -} - -static char * -ProcessArgs(int argc, char **argv) -{ - int optc; - char *cp; - - optc = 0; - mode = MODE_INTER; - while (argc > 0 && **argv == '-') { - cp = *argv + 1; - if (strcmp(cp, "auto") == 0) { - mode |= MODE_AUTO; - mode &= ~MODE_INTER; - } else if (strcmp(cp, "background") == 0) { - mode |= MODE_BACKGROUND; - mode &= ~MODE_INTER; - } else if (strcmp(cp, "direct") == 0) { - mode |= MODE_DIRECT; - mode &= ~MODE_INTER; - } else if (strcmp(cp, "dedicated") == 0) { - mode |= MODE_DEDICATED; - mode &= ~MODE_INTER; - } else if (strcmp(cp, "ddial") == 0) { - mode |= MODE_DDIAL; - mode &= ~MODE_INTER; -#ifndef NOALIAS - } else if (strcmp(cp, "alias") == 0) { - if (loadAliasHandlers(&VarAliasHandlers) == 0) - mode |= MODE_ALIAS; - else - LogPrintf(LogWARN, "Cannot load alias library\n"); - optc--; /* this option isn't exclusive */ -#endif - } else - Usage(); - optc++; - argv++; - argc--; - } - if (argc > 1) { - fprintf(stderr, "specify only one system label.\n"); - exit(EX_START); - } - - if (optc > 1) { - fprintf(stderr, "specify only one mode.\n"); - exit(EX_START); - } - - return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ -} - -int -main(int argc, char **argv) -{ - FILE *lockfile; - char *name, *label; - int nfds; - - nfds = getdtablesize(); - if (nfds >= FD_SETSIZE) - /* - * If we've got loads of file descriptors, make sure they're all - * closed. If they aren't, we may end up with a seg fault when our - * `fd_set's get too big when select()ing ! - */ - while (--nfds > 2) - close(nfds); - - VarTerm = 0; - name = strrchr(argv[0], '/'); - LogOpen(name ? name + 1 : argv[0]); - - tcgetattr(STDIN_FILENO, &oldtio); /* Save original tty mode */ - - argc--; - argv++; - label = ProcessArgs(argc, argv); - if (!(mode & MODE_DIRECT)) - VarTerm = stdout; - - ID0init(); - if (ID0realuid() != 0) { - char conf[200], *ptr; - - snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); - do { - if (!access(conf, W_OK)) { - LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); - return -1; - } - ptr = conf + strlen(conf)-2; - while (ptr > conf && *ptr != '/') - *ptr-- = '\0'; - } while (ptr >= conf); - } - - if (!ValidSystem(label)) { - fprintf(stderr, "You may not use ppp in this mode with this label\n"); - if (mode & MODE_DIRECT) { - const char *l; - l = label ? label : "default"; - LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); - } - LogClose(); - return 1; - } - - if (!GetShortHost()) - return 1; - IsInteractive(1); - IpcpDefAddress(); - - if (mode & MODE_INTER) - VarLocalAuth = LOCAL_AUTH; - - if (SelectSystem("default", CONFFILE) < 0 && VarTerm) - fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); - - if (OpenTunnel(&tunno) < 0) { - LogPrintf(LogWARN, "OpenTunnel: %s\n", strerror(errno)); - return EX_START; - } - CleanInterface(IfDevName); - if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED)) - if (label == NULL) { - if (VarTerm) - fprintf(VarTerm, "Destination system must be specified in" - " auto, background or ddial mode.\n"); - return EX_START; - } - - pending_signal(SIGHUP, CloseSession); - pending_signal(SIGTERM, CloseSession); - pending_signal(SIGINT, CloseConnection); - pending_signal(SIGQUIT, CloseSession); -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif -#ifdef SIGALRM - pending_signal(SIGALRM, SIG_IGN); -#endif - if (mode & MODE_INTER) { -#ifdef SIGTSTP - pending_signal(SIGTSTP, TerminalStop); -#endif -#ifdef SIGTTIN - pending_signal(SIGTTIN, TerminalStop); -#endif -#ifdef SIGTTOU - pending_signal(SIGTTOU, SIG_IGN); -#endif - } - if (!(mode & MODE_INTER)) { -#ifdef SIGUSR1 - pending_signal(SIGUSR1, SetUpServer); -#endif -#ifdef SIGUSR2 - pending_signal(SIGUSR2, BringDownServer); -#endif - } - - if (label) { - if (SelectSystem(label, CONFFILE) < 0) { - LogPrintf(LogWARN, "Destination system %s not found in conf file.\n", - GetLabel()); - Cleanup(EX_START); - } - /* - * We don't SetLabel() 'till now in case SelectSystem() has an - * embeded load "otherlabel" command. - */ - SetLabel(label); - if (mode & MODE_OUTGOING_DAEMON && - DefHisAddress.ipaddr.s_addr == INADDR_ANY) { - LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for" - " auto, background or ddial mode.\n", label); - Cleanup(EX_START); - } - } - - if (mode & MODE_DAEMON) { - if (mode & MODE_BACKGROUND) { - if (pipe(BGFiledes)) { - LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); - Cleanup(EX_SOCK); - } - } - - if (!(mode & MODE_DIRECT)) { - pid_t bgpid; - - bgpid = fork(); - if (bgpid == -1) { - LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); - Cleanup(EX_SOCK); - } - if (bgpid) { - char c = EX_NORMAL; - - if (mode & MODE_BACKGROUND) { - /* Wait for our child to close its pipe before we exit. */ - BGPid = bgpid; - close(BGFiledes[1]); - if (read(BGFiledes[0], &c, 1) != 1) { - fprintf(VarTerm, "Child exit, no status.\n"); - LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); - } else if (c == EX_NORMAL) { - fprintf(VarTerm, "PPP enabled.\n"); - LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); - } else { - fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); - LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", - ex_desc((int) c)); - } - close(BGFiledes[0]); - } - return c; - } else if (mode & MODE_BACKGROUND) - close(BGFiledes[0]); - } - - VarTerm = 0; /* We know it's currently stdout */ - close(STDOUT_FILENO); - close(STDERR_FILENO); - - if (mode & MODE_DIRECT) - /* STDIN_FILENO gets used by OpenModem in DIRECT mode */ - TtyInit(1); - else if (mode & MODE_DAEMON) { - setsid(); - close(STDIN_FILENO); - } - } else { - close(STDIN_FILENO); - if ((netfd = open(_PATH_TTY, O_RDONLY)) < 0) { - fprintf(stderr, "Cannot open %s for intput !\n", _PATH_TTY); - return 2; - } - close(STDERR_FILENO); - TtyInit(0); - TtyCommandMode(1); - } - - snprintf(pid_filename, sizeof pid_filename, "%stun%d.pid", - _PATH_VARRUN, tunno); - lockfile = ID0fopen(pid_filename, "w"); - if (lockfile != NULL) { - fprintf(lockfile, "%d\n", (int) getpid()); - fclose(lockfile); - } -#ifndef RELEASE_CRUNCH - else - LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", - pid_filename, strerror(errno)); -#endif - - LogPrintf(LogPHASE, "PPP Started.\n"); - - - do - DoLoop(); - while (mode & MODE_DEDICATED); - - Cleanup(EX_DONE); - return 0; -} - -/* - * Turn into packet mode, where we speak PPP. - */ -void -PacketMode(int delay) -{ - if (RawModem() < 0) { - LogPrintf(LogWARN, "PacketMode: Not connected.\n"); - return; - } - AsyncInit(); - VjInit(15); - LcpInit(); - IpcpInit(); - CcpInit(); - LcpUp(); - - LcpOpen(delay); - if (mode & MODE_INTER) - TtyCommandMode(1); - if (VarTerm) { - fprintf(VarTerm, "Packet mode.\n"); - aft_cmd = 1; - } -} - -static void -ShowHelp(void) -{ - fprintf(stderr, "The following commands are available:\r\n"); - fprintf(stderr, " ~p\tEnter Packet mode\r\n"); - fprintf(stderr, " ~-\tDecrease log level\r\n"); - fprintf(stderr, " ~+\tIncrease log level\r\n"); - fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); - fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); - fprintf(stderr, " ~.\tTerminate program\r\n"); - fprintf(stderr, " ~?\tThis help\r\n"); -} - -static void -ReadTty(void) -{ - int n; - char ch; - static int ttystate; - char linebuff[LINE_LEN]; - - LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", - TermMode, netfd, mode); - if (!TermMode) { - n = read(netfd, linebuff, sizeof linebuff - 1); - if (n > 0) { - aft_cmd = 1; - if (linebuff[n-1] == '\n') - linebuff[--n] = '\0'; - else - linebuff[n] = '\0'; - if (n) - DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client"); - Prompt(); - } else if (n <= 0) { - LogPrintf(LogPHASE, "Client connection closed.\n"); - DropClient(0); - } - return; - } - - /* - * We are in terminal mode, decode special sequences - */ - n = read(netfd, &ch, 1); - LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); - - if (n > 0) { - switch (ttystate) { - case 0: - if (ch == '~') - ttystate++; - else - write(modem, &ch, n); - break; - case 1: - switch (ch) { - case '?': - ShowHelp(); - break; - case 'p': - - /* - * XXX: Should check carrier. - */ - if (LcpFsm.state <= ST_CLOSED) - PacketMode(0); - break; - case '.': - TermMode = 1; - aft_cmd = 1; - TtyCommandMode(1); - break; - case 't': - if (LogIsKept(LogDEBUG)) { - ShowTimers(); - break; - } - case 'm': - if (LogIsKept(LogDEBUG)) { - ShowMemMap(NULL); - break; - } - default: - if (write(modem, &ch, n) < 0) - LogPrintf(LogERROR, "error writing to modem.\n"); - break; - } - ttystate = 0; - break; - } - } -} - - -/* - * Here, we'll try to detect HDLC frame - */ - -static const char *FrameHeaders[] = { - "\176\377\003\300\041", - "\176\377\175\043\300\041", - "\176\177\175\043\100\041", - "\176\175\337\175\043\300\041", - "\176\175\137\175\043\100\041", - NULL, -}; - -static const u_char * -HdlcDetect(u_char * cp, int n) -{ - const char *ptr, *fp, **hp; - - cp[n] = '\0'; /* be sure to null terminated */ - ptr = NULL; - for (hp = FrameHeaders; *hp; hp++) { - fp = *hp; - if (DEV_IS_SYNC) - fp++; - ptr = strstr((char *) cp, fp); - if (ptr) - break; - } - return ((const u_char *) ptr); -} - -static struct pppTimer RedialTimer; - -static void -RedialTimeout(void *v) -{ - StopTimer(&RedialTimer); - LogPrintf(LogPHASE, "Redialing timer expired.\n"); -} - -static void -StartRedialTimer(int Timeout) -{ - StopTimer(&RedialTimer); - - if (Timeout) { - RedialTimer.state = TIMER_STOPPED; - - if (Timeout > 0) - RedialTimer.load = Timeout * SECTICKS; - else - RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; - - LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", - RedialTimer.load / SECTICKS); - - RedialTimer.func = RedialTimeout; - StartTimer(&RedialTimer); - } -} - -#define IN_SIZE sizeof(struct sockaddr_in) -#define UN_SIZE sizeof(struct sockaddr_in) -#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE) - -static void -DoLoop(void) -{ - fd_set rfds, wfds, efds; - int pri, i, n, wfd, nfds; - char hisaddr[ADDRSZ]; - struct sockaddr *sa = (struct sockaddr *)hisaddr; - struct sockaddr_in *sockin = (struct sockaddr_in *)hisaddr; - struct timeval timeout, *tp; - int ssize = ADDRSZ; - const u_char *cp; - int tries; - int qlen; - int res; - struct tun_data tun; -#define rbuff tun.data - - if (mode & MODE_DIRECT) { - LogPrintf(LogDEBUG, "Opening modem\n"); - if (OpenModem() < 0) - return; - LogPrintf(LogPHASE, "Packet mode enabled\n"); - PacketMode(VarOpenMode); - } else if (mode & MODE_DEDICATED) { - if (modem < 0) - while (OpenModem() < 0) - nointr_sleep(VarReconnectTimer); - } - fflush(VarTerm); - - timeout.tv_sec = 0; - timeout.tv_usec = 0; - reconnectState = RECON_UNKNOWN; - - if (mode & MODE_BACKGROUND) - dial_up = 1; /* Bring the line up */ - else - dial_up = 0; /* XXXX */ - tries = 0; - for (;;) { - nfds = 0; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - - /* - * If the link is down and we're in DDIAL mode, bring it back up. - */ - if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) - dial_up = 1; - - /* - * If we lost carrier and want to re-establish the connection due to the - * "set reconnect" value, we'd better bring the line back up. - */ - if (LcpFsm.state <= ST_CLOSED) { - if (!dial_up && reconnectState == RECON_TRUE) { - if (++reconnectCount <= VarReconnectTries) { - LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", - reconnectCount, VarReconnectTries); - StartRedialTimer(VarReconnectTimer); - dial_up = 1; - } else { - if (VarReconnectTries) - LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", - VarReconnectTries); - reconnectCount = 0; - if (mode & MODE_BACKGROUND) - Cleanup(EX_DEAD); - } - reconnectState = RECON_ENVOKED; - } else if (mode & MODE_DEDICATED) - PacketMode(VarOpenMode); - } - - /* - * If Ip packet for output is enqueued and require dial up, Just do it! - */ - if (dial_up && RedialTimer.state != TIMER_RUNNING) { - LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); - if (OpenModem() < 0) { - tries++; - if (!(mode & MODE_DDIAL) && VarDialTries) - LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", - tries, VarDialTries); - else - LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); - - if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { - if (mode & MODE_BACKGROUND) - Cleanup(EX_DIAL); /* Can't get the modem */ - dial_up = 0; - reconnectState = RECON_UNKNOWN; - reconnectCount = 0; - tries = 0; - } else - StartRedialTimer(VarRedialTimeout); - } else { - tries++; /* Tries are per number, not per list of - * numbers. */ - if (!(mode & MODE_DDIAL) && VarDialTries) - LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); - else - LogPrintf(LogCHAT, "Dial attempt %u\n", tries); - - if ((res = DialModem()) == EX_DONE) { - ModemTimeout(NULL); - PacketMode(VarOpenMode); - dial_up = 0; - reconnectState = RECON_UNKNOWN; - tries = 0; - } else { - if (mode & MODE_BACKGROUND) { - if (VarNextPhone == NULL || res == EX_SIG) - Cleanup(EX_DIAL); /* Tried all numbers - no luck */ - else - /* Try all numbers in background mode */ - StartRedialTimer(VarRedialNextTimeout); - } else if (!(mode & MODE_DDIAL) && - ((VarDialTries && tries >= VarDialTries) || - res == EX_SIG)) { - /* I give up ! Can't get through :( */ - StartRedialTimer(VarRedialTimeout); - dial_up = 0; - reconnectState = RECON_UNKNOWN; - reconnectCount = 0; - tries = 0; - } else if (VarNextPhone == NULL) - /* Dial failed. Keep quite during redial wait period. */ - StartRedialTimer(VarRedialTimeout); - else - StartRedialTimer(VarRedialNextTimeout); - } - } - } - qlen = ModemQlen(); - - if (qlen == 0) { - IpStartOutput(); - qlen = ModemQlen(); - } - -#ifdef SIGALRM - handle_signals(); -#endif - - if (modem >= 0) { - if (modem + 1 > nfds) - nfds = modem + 1; - FD_SET(modem, &rfds); - FD_SET(modem, &efds); - if (qlen > 0) { - FD_SET(modem, &wfds); - } - } - if (server >= 0) { - if (server + 1 > nfds) - nfds = server + 1; - FD_SET(server, &rfds); - } - -#ifndef SIGALRM - /* - * *** IMPORTANT *** - * CPU is serviced every TICKUNIT micro seconds. This value must be chosen - * with great care. If this values is too big, it results in loss of - * characters from the modem and poor response. If this value is too - * small, ppp eats too much CPU time. - */ - usleep(TICKUNIT); - TimerService(); -#endif - - /* If there are aren't many packets queued, look for some more. */ - if (qlen < 20 && tun_in >= 0) { - if (tun_in + 1 > nfds) - nfds = tun_in + 1; - FD_SET(tun_in, &rfds); - } - if (netfd >= 0) { - if (netfd + 1 > nfds) - nfds = netfd + 1; - FD_SET(netfd, &rfds); - FD_SET(netfd, &efds); - } -#ifndef SIGALRM - - /* - * Normally, select() will not block because modem is writable. In AUTO - * mode, select will block until we find packet from tun - */ - tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; - i = select(nfds, &rfds, &wfds, &efds, tp); -#else - - /* - * When SIGALRM timer is running, a select function will be return -1 and - * EINTR after a Time Service signal hundler is done. If the redial - * timer is not running and we are trying to dial, poll with a 0 value - * timer. - */ - tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; - i = select(nfds, &rfds, &wfds, &efds, tp); -#endif - - if (i == 0) { - continue; - } - if (i < 0) { - if (errno == EINTR) { - handle_signals(); - continue; - } - LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); - break; - } - if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { - LogPrintf(LogALERT, "Exception detected.\n"); - break; - } - if (server >= 0 && FD_ISSET(server, &rfds)) { - wfd = accept(server, sa, &ssize); - if (wfd < 0) { - LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); - continue; - } - switch (sa->sa_family) { - case AF_LOCAL: - LogPrintf(LogPHASE, "Connected to local client.\n"); - break; - case AF_INET: - if (ntohs(sockin->sin_port) < 1024) { - LogPrintf(LogALERT, "Rejected client connection from %s:%u" - "(invalid port number) !\n", - inet_ntoa(sockin->sin_addr), ntohs(sockin->sin_port)); - close(wfd); - continue; - } - LogPrintf(LogPHASE, "Connected to client from %s:%u\n", - inet_ntoa(sockin->sin_addr), sockin->sin_port); - break; - default: - write(wfd, "Unrecognised access !\n", 22); - close(wfd); - continue; - } - if (netfd >= 0) { - write(wfd, "Connection already in use.\n", 27); - close(wfd); - continue; - } - netfd = wfd; - VarTerm = fdopen(netfd, "a+"); - LocalAuthInit(); - IsInteractive(1); - Prompt(); - } - if (netfd >= 0 && FD_ISSET(netfd, &rfds)) - /* something to read from tty */ - ReadTty(); - if (modem >= 0 && FD_ISSET(modem, &wfds)) { - /* ready to write into modem */ - ModemStartOutput(modem); - if (modem < 0) - dial_up = 1; - } - if (modem >= 0 && FD_ISSET(modem, &rfds)) { - /* something to read from modem */ - if (LcpFsm.state <= ST_CLOSED) - nointr_usleep(10000); - n = read(modem, rbuff, sizeof rbuff); - if ((mode & MODE_DIRECT) && n <= 0) { - DownConnection(); - } else - LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); - - if (LcpFsm.state <= ST_CLOSED) { - /* - * In dedicated mode, we just discard input until LCP is started. - */ - if (!(mode & MODE_DEDICATED)) { - cp = HdlcDetect(rbuff, n); - if (cp) { - /* - * LCP packet is detected. Turn ourselves into packet mode. - */ - if (cp != rbuff) { - write(modem, rbuff, cp - rbuff); - write(modem, "\r\n", 2); - } - PacketMode(0); - } else - write(fileno(VarTerm), rbuff, n); - } - } else { - if (n > 0) - AsyncInput(rbuff, n); - } - } - if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read - * from tun */ - n = read(tun_in, &tun, sizeof tun); - if (n < 0) { - LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); - continue; - } - n -= sizeof tun - sizeof tun.data; - if (n <= 0) { - LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n); - continue; - } - if (!tun_check_header(tun, AF_INET)) - continue; - if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { - /* we've been asked to send something addressed *to* us :( */ - if (VarLoopback) { - pri = PacketCheck(rbuff, n, FL_IN); - if (pri >= 0) { - struct mbuf *bp; - -#ifndef NOALIAS - if (mode & MODE_ALIAS) { - VarPacketAliasIn(rbuff, sizeof rbuff); - n = ntohs(((struct ip *) rbuff)->ip_len); - } -#endif - bp = mballoc(n, MB_IPIN); - memcpy(MBUF_CTOP(bp), rbuff, n); - IpInput(bp); - LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); - } - continue; - } else - LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); - } - - /* - * Process on-demand dialup. Output packets are queued within tunnel - * device until IPCP is opened. - */ - if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO) && - (pri = PacketCheck(rbuff, n, FL_DIAL)) >= 0) - dial_up = 1; - - pri = PacketCheck(rbuff, n, FL_OUT); - if (pri >= 0) { -#ifndef NOALIAS - if (mode & MODE_ALIAS) { - VarPacketAliasOut(rbuff, sizeof rbuff); - n = ntohs(((struct ip *) rbuff)->ip_len); - } -#endif - IpEnqueue(pri, rbuff, n); - } - } - } - LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); -} diff --git a/usr.sbin/ppp/mbuf.c b/usr.sbin/ppp/mbuf.c deleted file mode 100644 index 397faca503a..00000000000 --- a/usr.sbin/ppp/mbuf.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * PPP Memory handling module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: mbuf.c,v 1.3 1998/01/21 02:13:37 brian Exp $ - * - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "loadalias.h" -#include "vars.h" -#include "server.h" - -static struct memmap { - struct mbuf *queue; - int count; -} MemMap[MB_MAX + 2]; - -static int totalalloced; - -int -plength(struct mbuf * bp) -{ - int len; - - for (len = 0; bp; bp = bp->next) - len += bp->cnt; - return (len); -} - -struct mbuf * -mballoc(int cnt, int type) -{ - u_char *p; - struct mbuf *bp; - - if (type > MB_MAX) - LogPrintf(LogERROR, "Bad mbuf type %d\n", type); - bp = (struct mbuf *) malloc(sizeof(struct mbuf)); - if (bp == NULL) { - LogPrintf(LogALERT, "failed to allocate memory: %u\n", sizeof(struct mbuf)); - ServerClose(); - exit(1); - } - memset(bp, '\0', sizeof(struct mbuf)); - p = (u_char *) malloc(cnt); - if (p == NULL) { - LogPrintf(LogALERT, "failed to allocate memory: %d\n", cnt); - ServerClose(); - exit(1); - } - MemMap[type].count += cnt; - totalalloced += cnt; - bp->base = p; - bp->size = bp->cnt = cnt; - bp->type = type; - bp->pnext = NULL; - return (bp); -} - -struct mbuf * -mbfree(struct mbuf * bp) -{ - struct mbuf *nbp; - - if (bp) { - nbp = bp->next; - MemMap[bp->type].count -= bp->size; - totalalloced -= bp->size; - free(bp->base); - free(bp); - return (nbp); - } - return (bp); -} - -void -pfree(struct mbuf * bp) -{ - while (bp) - bp = mbfree(bp); -} - -struct mbuf * -mbread(struct mbuf * bp, u_char * ptr, int len) -{ - int nb; - - while (bp && len > 0) { - if (len > bp->cnt) - nb = bp->cnt; - else - nb = len; - memcpy(ptr, MBUF_CTOP(bp), nb); - ptr += nb; - bp->cnt -= nb; - len -= nb; - bp->offset += nb; - if (bp->cnt == 0) { -#ifdef notdef - bp = bp->next; -#else - bp = mbfree(bp); -#endif - } - } - return (bp); -} - -void -mbwrite(struct mbuf * bp, u_char * ptr, int cnt) -{ - int plen; - int nb; - - plen = plength(bp); - if (plen < cnt) - cnt = plen; - - while (cnt > 0) { - nb = (cnt < bp->cnt) ? cnt : bp->cnt; - memcpy(MBUF_CTOP(bp), ptr, nb); - cnt -= bp->cnt; - bp = bp->next; - } -} - -int -ShowMemMap(struct cmdargs const *arg) -{ - int i; - - if (!VarTerm) - return 1; - - for (i = 0; i <= MB_MAX; i += 2) - fprintf(VarTerm, "%d: %d %d: %d\n", - i, MemMap[i].count, i + 1, MemMap[i + 1].count); - - return 0; -} - -void -LogMemory() -{ - LogPrintf(LogDEBUG, "LogMemory: mem alloced: %d\n", totalalloced); - LogPrintf(LogDEBUG, "LogMemory: 1: %d 2: %d 3: %d 4: %d\n", - MemMap[1].count, MemMap[2].count, MemMap[3].count, MemMap[4].count); - LogPrintf(LogDEBUG, "LogMemory: 5: %d 6: %d 7: %d 8: %d\n", - MemMap[5].count, MemMap[6].count, MemMap[7].count, MemMap[8].count); -} diff --git a/usr.sbin/ppp/modem.c b/usr.sbin/ppp/modem.c deleted file mode 100644 index 59c5f6bcf82..00000000000 --- a/usr.sbin/ppp/modem.c +++ /dev/null @@ -1,937 +0,0 @@ -/* - * PPP Modem handling module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: modem.c,v 1.14 1998/03/13 01:26:00 brian Exp $ - * - * TODO: - */ -#include <sys/param.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <errno.h> -#include <fcntl.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/tty.h> -#include <unistd.h> -#include <utmp.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "id.h" -#include "timer.h" -#include "fsm.h" -#include "hdlc.h" -#include "lcp.h" -#include "ip.h" -#include "modem.h" -#include "loadalias.h" -#include "vars.h" -#include "main.h" -#include "chat.h" -#include "throughput.h" -#ifdef __OpenBSD__ -#include <util.h> -#else -#include <libutil.h> -#endif - -#ifndef O_NONBLOCK -#ifdef O_NDELAY -#define O_NONBLOCK O_NDELAY -#endif -#endif - -static int mbits; /* Current DCD status */ -static int connect_count; -static struct pppTimer ModemTimer; - -#define Online (mbits & TIOCM_CD) - -static struct mbuf *modemout; -static struct mqueue OutputQueues[PRI_LINK + 1]; -static int dev_is_modem; -static struct pppThroughput throughput; - -static void CloseLogicalModem(void); - -void -Enqueue(struct mqueue * queue, struct mbuf * bp) -{ - if (queue->last) { - queue->last->pnext = bp; - queue->last = bp; - } else - queue->last = queue->top = bp; - queue->qlen++; - LogPrintf(LogDEBUG, "Enqueue: len = %d\n", queue->qlen); -} - -struct mbuf * -Dequeue(struct mqueue *queue) -{ - struct mbuf *bp; - - LogPrintf(LogDEBUG, "Dequeue: len = %d\n", queue->qlen); - bp = queue->top; - if (bp) { - queue->top = queue->top->pnext; - queue->qlen--; - if (queue->top == NULL) { - queue->last = queue->top; - if (queue->qlen) - LogPrintf(LogERROR, "Dequeue: Not zero (%d)!!!\n", queue->qlen); - } - } - return (bp); -} - -void -SequenceQueues() -{ - LogPrintf(LogDEBUG, "SequenceQueues\n"); - while (OutputQueues[PRI_NORMAL].qlen) - Enqueue(OutputQueues + PRI_LINK, Dequeue(OutputQueues + PRI_NORMAL)); -} - -static struct speeds { - int nspeed; - speed_t speed; -} speeds[] = { - -#ifdef B50 - { 50, B50, }, -#endif -#ifdef B75 - { 75, B75, }, -#endif -#ifdef B110 - { 110, B110, }, -#endif -#ifdef B134 - { 134, B134, }, -#endif -#ifdef B150 - { 150, B150, }, -#endif -#ifdef B200 - { 200, B200, }, -#endif -#ifdef B300 - { 300, B300, }, -#endif -#ifdef B600 - { 600, B600, }, -#endif -#ifdef B1200 - { 1200, B1200, }, -#endif -#ifdef B1800 - { 1800, B1800, }, -#endif -#ifdef B2400 - { 2400, B2400, }, -#endif -#ifdef B4800 - { 4800, B4800, }, -#endif -#ifdef B9600 - { 9600, B9600, }, -#endif -#ifdef B19200 - { 19200, B19200, }, -#endif -#ifdef B38400 - { 38400, B38400, }, -#endif -#ifndef _POSIX_SOURCE -#ifdef B7200 - { 7200, B7200, }, -#endif -#ifdef B14400 - { 14400, B14400, }, -#endif -#ifdef B28800 - { 28800, B28800, }, -#endif -#ifdef B57600 - { 57600, B57600, }, -#endif -#ifdef B76800 - { 76800, B76800, }, -#endif -#ifdef B115200 - { 115200, B115200, }, -#endif -#ifdef B230400 - { 230400, B230400, }, -#endif -#ifdef EXTA - { 19200, EXTA, }, -#endif -#ifdef EXTB - { 38400, EXTB, }, -#endif -#endif /* _POSIX_SOURCE */ - { 0, 0 } -}; - -static int -SpeedToInt(speed_t speed) -{ - struct speeds *sp; - - for (sp = speeds; sp->nspeed; sp++) { - if (sp->speed == speed) { - return (sp->nspeed); - } - } - return 0; -} - -speed_t -IntToSpeed(int nspeed) -{ - struct speeds *sp; - - for (sp = speeds; sp->nspeed; sp++) { - if (sp->nspeed == nspeed) { - return (sp->speed); - } - } - return B0; -} - -static void -ModemSetDevice(const char *name) -{ - strncpy(VarDevice, name, sizeof VarDevice - 1); - VarDevice[sizeof VarDevice - 1] = '\0'; - VarBaseDevice = strncmp(VarDevice, "/dev/", 5) ? VarDevice : VarDevice + 5; -} - -void -DownConnection() -{ - LogPrintf(LogPHASE, "Disconnected!\n"); - LcpDown(); -} - -/* - * ModemTimeout() watches DCD signal and notifies if it's status is changed. - * - */ -void -ModemTimeout(void *data) -{ - int ombits = mbits; - int change; - - StopTimer(&ModemTimer); - StartTimer(&ModemTimer); - - if (dev_is_modem) { - if (modem >= 0) { - if (ioctl(modem, TIOCMGET, &mbits) < 0) { - LogPrintf(LogPHASE, "ioctl error (%s)!\n", strerror(errno)); - DownConnection(); - return; - } - } else - mbits = 0; - change = ombits ^ mbits; - if (change & TIOCM_CD) { - if (Online) { - LogPrintf(LogDEBUG, "ModemTimeout: offline -> online\n"); - /* - * In dedicated mode, start packet mode immediate after we detected - * carrier. - */ - if (mode & MODE_DEDICATED) - PacketMode(VarOpenMode); - } else { - LogPrintf(LogDEBUG, "ModemTimeout: online -> offline\n"); - reconnect(RECON_TRUE); - DownConnection(); - } - } - else - LogPrintf(LogDEBUG, "ModemTimeout: Still %sline\n", - Online ? "on" : "off"); - } else if (!Online) { - /* mbits was set to zero in OpenModem() */ - mbits = TIOCM_CD; - } -} - -static void -StartModemTimer(void) -{ - StopTimer(&ModemTimer); - ModemTimer.state = TIMER_STOPPED; - ModemTimer.load = SECTICKS; - ModemTimer.func = ModemTimeout; - LogPrintf(LogDEBUG, "ModemTimer using ModemTimeout() - %p\n", ModemTimeout); - StartTimer(&ModemTimer); -} - -static struct parity { - const char *name; - const char *name1; - int set; -} validparity[] = { - { "even", "P_EVEN", CS7 | PARENB }, - { "odd", "P_ODD", CS7 | PARENB | PARODD }, - { "none", "P_ZERO", CS8 }, - { NULL, 0 }, -}; - -static int -GetParityValue(const char *str) -{ - struct parity *pp; - - for (pp = validparity; pp->name; pp++) { - if (strcasecmp(pp->name, str) == 0 || - strcasecmp(pp->name1, str) == 0) { - return VarParity = pp->set; - } - } - return (-1); -} - -int -ChangeParity(const char *str) -{ - struct termios rstio; - int val; - - val = GetParityValue(str); - if (val > 0) { - VarParity = val; - tcgetattr(modem, &rstio); - rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); - rstio.c_cflag |= val; - tcsetattr(modem, TCSADRAIN, &rstio); - return 0; - } - LogPrintf(LogWARN, "ChangeParity: %s: Invalid parity\n", str); - return -1; -} - -static int -OpenConnection(char *host, char *port) -{ - struct sockaddr_in dest; - int sock; - struct hostent *hp; - struct servent *sp; - - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = inet_addr(host); - if (dest.sin_addr.s_addr == INADDR_NONE) { - hp = gethostbyname(host); - if (hp) { - memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], 4); - } else { - LogPrintf(LogWARN, "OpenConnection: unknown host: %s\n", host); - return (-1); - } - } - dest.sin_port = htons(atoi(port)); - if (dest.sin_port == 0) { - sp = getservbyname(port, "tcp"); - if (sp) { - dest.sin_port = sp->s_port; - } else { - LogPrintf(LogWARN, "OpenConnection: unknown service: %s\n", port); - return (-1); - } - } - LogPrintf(LogPHASE, "Connecting to %s:%s\n", host, port); - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) { - return (sock); - } - if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) { - LogPrintf(LogWARN, "OpenConnection: connection failed.\n"); - return (-1); - } - LogPrintf(LogDEBUG, "OpenConnection: modem fd is %d.\n", sock); - return (sock); -} - -static char fn[MAXPATHLEN]; - -static int -LockModem(void) -{ - int res; - FILE *lockfile; - - if (*VarDevice != '/') - return 0; - - if (!(mode & MODE_DIRECT) && (res = ID0uu_lock(VarBaseDevice)) != UU_LOCK_OK) { - if (res == UU_LOCK_INUSE) - LogPrintf(LogPHASE, "Modem %s is in use\n", VarDevice); - else - LogPrintf(LogPHASE, "Modem %s is in use: uu_lock: %s\n", - VarDevice, uu_lockerr(res)); - return (-1); - } - - snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, VarBaseDevice); - lockfile = ID0fopen(fn, "w"); - if (lockfile != NULL) { - fprintf(lockfile, "tun%d\n", tunno); - fclose(lockfile); - } -#ifndef RELEASE_CRUNCH - else - LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", fn, strerror(errno)); -#endif - - return 0; -} - -static void -UnlockModem(void) -{ - if (*VarDevice != '/') - return; - - snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, VarBaseDevice); -#ifndef RELEASE_CRUNCH - if (ID0unlink(fn) == -1) - LogPrintf(LogALERT, "Warning: Can't remove %s: %s\n", fn, strerror(errno)); -#else - ID0unlink(fn); -#endif - - if (!(mode & MODE_DIRECT) && ID0uu_unlock(VarBaseDevice) == -1) - LogPrintf(LogALERT, "Warning: Can't uu_unlock %s\n", fn); -} - -static void -HaveModem(void) -{ - throughput_start(&throughput); - connect_count++; - LogPrintf(LogPHASE, "Connected!\n"); -} - -static struct termios modemios; - -int -OpenModem() -{ - struct termios rstio; - int oldflag; - char *host, *port; - char *cp; - char tmpDeviceList[sizeof VarDeviceList]; - char *tmpDevice; - - if (modem >= 0) - LogPrintf(LogDEBUG, "OpenModem: Modem is already open!\n"); - /* We're going back into "term" mode */ - else if (mode & MODE_DIRECT) { - if (isatty(STDIN_FILENO)) { - LogPrintf(LogDEBUG, "OpenModem(direct): Modem is a tty\n"); - ModemSetDevice(ttyname(STDIN_FILENO)); - if (LockModem() == -1) { - close(STDIN_FILENO); - return -1; - } - modem = STDIN_FILENO; - HaveModem(); - } else { - LogPrintf(LogDEBUG, "OpenModem(direct): Modem is not a tty\n"); - ModemSetDevice(""); - /* We don't call ModemTimeout() with this type of connection */ - HaveModem(); - return modem = STDIN_FILENO; - } - } else { - strncpy(tmpDeviceList, VarDeviceList, sizeof tmpDeviceList - 1); - tmpDeviceList[sizeof tmpDeviceList - 1] = '\0'; - - for(tmpDevice=strtok(tmpDeviceList, ","); tmpDevice && (modem < 0); - tmpDevice=strtok(NULL,",")) { - ModemSetDevice(tmpDevice); - if (strncmp(VarDevice, "/dev/", 5) == 0) { - if (LockModem() == -1) { - modem = -1; - } - else { - modem = ID0open(VarDevice, O_RDWR | O_NONBLOCK); - if (modem < 0) { - LogPrintf(LogERROR, "OpenModem failed: %s: %s\n", VarDevice, - strerror(errno)); - UnlockModem(); - modem = -1; - } - else { - HaveModem(); - LogPrintf(LogDEBUG, "OpenModem: Modem is %s\n", VarDevice); - } - } - } else { - /* PPP over TCP */ - cp = strchr(VarDevice, ':'); - if (cp) { - *cp = '\0'; - host = VarDevice; - port = cp + 1; - if (*host && *port) { - modem = OpenConnection(host, port); - *cp = ':'; /* Don't destroy VarDevice */ - if (modem < 0) - return (-1); - HaveModem(); - LogPrintf(LogDEBUG, "OpenModem: Modem is socket %s\n", VarDevice); - } else { - *cp = ':'; /* Don't destroy VarDevice */ - LogPrintf(LogERROR, "Invalid host:port: \"%s\"\n", VarDevice); - return (-1); - } - } else { - LogPrintf(LogERROR, - "Device (%s) must be in /dev or be a host:port pair\n", - VarDevice); - return (-1); - } - } - } - - if (modem < 0) return modem; - } - - /* - * If we are working on tty device, change it's mode into the one desired - * for further operation. In this implementation, we assume that modem is - * configuted to use CTS/RTS flow control. - */ - mbits = 0; - dev_is_modem = isatty(modem) || DEV_IS_SYNC; - if (DEV_IS_SYNC) - nointr_sleep(1); - if (dev_is_modem && !DEV_IS_SYNC) { - tcgetattr(modem, &rstio); - modemios = rstio; - LogPrintf(LogDEBUG, "OpenModem: modem = %d\n", modem); - LogPrintf(LogDEBUG, "OpenModem: modem (get): iflag = %x, oflag = %x," - " cflag = %x\n", rstio.c_iflag, rstio.c_oflag, rstio.c_cflag); - cfmakeraw(&rstio); - if (VarCtsRts) - rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; - else { - rstio.c_cflag |= CLOCAL; - rstio.c_iflag |= IXOFF; - } - rstio.c_iflag |= IXON; - if (!(mode & MODE_DEDICATED)) - rstio.c_cflag |= HUPCL; - if ((mode & MODE_DIRECT) == 0) { - - /* - * If we are working as direct mode, don't change tty speed. - */ - rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); - rstio.c_cflag |= VarParity; - if (cfsetspeed(&rstio, IntToSpeed(VarSpeed)) == -1) { - LogPrintf(LogWARN, "Unable to set modem speed (modem %d to %d)\n", - modem, VarSpeed); - } - } - tcsetattr(modem, TCSADRAIN, &rstio); - LogPrintf(LogDEBUG, "modem (put): iflag = %x, oflag = %x, cflag = %x\n", - rstio.c_iflag, rstio.c_oflag, rstio.c_cflag); - - if (!(mode & MODE_DIRECT)) - if (ioctl(modem, TIOCMGET, &mbits)) { - LogPrintf(LogERROR, "OpenModem: Cannot get modem status: %s\n", - strerror(errno)); - CloseLogicalModem(); - return (-1); - } - LogPrintf(LogDEBUG, "OpenModem: modem control = %o\n", mbits); - - oldflag = fcntl(modem, F_GETFL, 0); - if (oldflag < 0) { - LogPrintf(LogERROR, "OpenModem: Cannot get modem flags: %s\n", - strerror(errno)); - CloseLogicalModem(); - return (-1); - } - (void) fcntl(modem, F_SETFL, oldflag & ~O_NONBLOCK); - } - StartModemTimer(); - - return (modem); -} - -int -ModemSpeed() -{ - struct termios rstio; - - tcgetattr(modem, &rstio); - return (SpeedToInt(cfgetispeed(&rstio))); -} - -/* - * Put modem tty line into raw mode which is necessary in packet mode operation - */ -int -RawModem() -{ - struct termios rstio; - int oldflag; - - if (!isatty(modem) || DEV_IS_SYNC) - return (0); - if (!(mode & MODE_DIRECT) && modem >= 0 && !Online) { - LogPrintf(LogDEBUG, "RawModem: mode = %d, modem = %d, mbits = %x\n", mode, modem, mbits); - } - tcgetattr(modem, &rstio); - cfmakeraw(&rstio); - if (VarCtsRts) - rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; - else - rstio.c_cflag |= CLOCAL; - - if (!(mode & MODE_DEDICATED)) - rstio.c_cflag |= HUPCL; - tcsetattr(modem, TCSADRAIN, &rstio); - oldflag = fcntl(modem, F_GETFL, 0); - if (oldflag < 0) - return (-1); - (void) fcntl(modem, F_SETFL, oldflag | O_NONBLOCK); - return (0); -} - -static void -UnrawModem(void) -{ - int oldflag; - - if (isatty(modem) && !DEV_IS_SYNC) { - tcsetattr(modem, TCSAFLUSH, &modemios); - oldflag = fcntl(modem, F_GETFL, 0); - if (oldflag < 0) - return; - (void) fcntl(modem, F_SETFL, oldflag & ~O_NONBLOCK); - } -} - -void -ModemAddInOctets(int n) -{ - throughput_addin(&throughput, n); -} - -void -ModemAddOutOctets(int n) -{ - throughput_addout(&throughput, n); -} - -static void -ClosePhysicalModem(void) -{ - LogPrintf(LogDEBUG, "ClosePhysicalModem\n"); - close(modem); - modem = -1; - throughput_log(&throughput, LogPHASE, "Modem"); -} - -void -HangupModem(int flag) -{ - struct termios tio; - - LogPrintf(LogDEBUG, "Hangup modem (%s)\n", modem >= 0 ? "open" : "closed"); - - if (modem < 0) - return; - - StopTimer(&ModemTimer); - throughput_stop(&throughput); - - if (TermMode) { - LogPrintf(LogDEBUG, "HangupModem: Not in 'term' mode\n"); - return; - } - - if (!isatty(modem)) { - mbits &= ~TIOCM_DTR; - ClosePhysicalModem(); - return; - } - - if (modem >= 0 && Online) { - mbits &= ~TIOCM_DTR; - tcgetattr(modem, &tio); - if (cfsetspeed(&tio, B0) == -1) { - LogPrintf(LogWARN, "Unable to set modem to speed 0\n"); - } - tcsetattr(modem, TCSANOW, &tio); - nointr_sleep(1); - } - - if (modem >= 0) { - char ScriptBuffer[SCRIPT_LEN]; - - strncpy(ScriptBuffer, VarHangupScript, sizeof ScriptBuffer - 1); - ScriptBuffer[sizeof ScriptBuffer - 1] = '\0'; - LogPrintf(LogDEBUG, "HangupModem: Script: %s\n", ScriptBuffer); - if (flag || !(mode & MODE_DEDICATED)) { - DoChat(ScriptBuffer); - tcflush(modem, TCIOFLUSH); - UnrawModem(); - CloseLogicalModem(); - } else { - /* - * If we are working as dedicated mode, never close it until we are - * directed to quit program. - */ - mbits |= TIOCM_DTR; - ioctl(modem, TIOCMSET, &mbits); - DoChat(ScriptBuffer); - } - } -} - -static void -CloseLogicalModem(void) -{ - LogPrintf(LogDEBUG, "CloseLogicalModem\n"); - if (modem >= 0) { - if (Utmp) { - ID0logout(VarBaseDevice); - Utmp = 0; - } - ClosePhysicalModem(); - UnlockModem(); - } -} - -/* - * Write to modem. Actualy, requested packets are queued, and goes out - * to the line when ModemStartOutput() is called. - */ -void -WriteModem(int pri, const char *ptr, int count) -{ - struct mbuf *bp; - - bp = mballoc(count, MB_MODEM); - memcpy(MBUF_CTOP(bp), ptr, count); - - /* - * Should be NORMAL and LINK only. All IP frames get here marked NORMAL. - */ - Enqueue(&OutputQueues[pri], bp); -} - -void -ModemOutput(int pri, struct mbuf * bp) -{ - struct mbuf *wp; - int len; - - len = plength(bp); - wp = mballoc(len, MB_MODEM); - mbread(bp, MBUF_CTOP(wp), len); - Enqueue(&OutputQueues[pri], wp); - ModemStartOutput(modem); -} - -int -ModemQlen() -{ - struct mqueue *queue; - int len = 0; - int i; - - for (i = PRI_NORMAL; i <= PRI_LINK; i++) { - queue = &OutputQueues[i]; - len += queue->qlen; - } - return (len); - -} - -void -ModemStartOutput(int fd) -{ - struct mqueue *queue; - int nb, nw; - int i; - - if (modemout == NULL && ModemQlen() == 0) - IpStartOutput(); - if (modemout == NULL) { - i = PRI_LINK; - for (queue = &OutputQueues[PRI_LINK]; queue >= OutputQueues; queue--) { - if (queue->top) { - modemout = Dequeue(queue); - if (LogIsKept(LogDEBUG)) { - if (i > PRI_NORMAL) { - struct mqueue *q; - - q = &OutputQueues[0]; - LogPrintf(LogDEBUG, "ModemStartOutput: Output from queue %d," - " normal has %d\n", i, q->qlen); - } - LogPrintf(LogDEBUG, "ModemStartOutput: Dequeued %d\n", i); - } - break; - } - i--; - } - } - if (modemout) { - nb = modemout->cnt; - if (nb > 1600) - nb = 1600; - nw = write(fd, MBUF_CTOP(modemout), nb); - LogPrintf(LogDEBUG, "ModemStartOutput: wrote: %d(%d)\n", nw, nb); - LogDumpBuff(LogDEBUG, "ModemStartOutput: modem write", - MBUF_CTOP(modemout), nb); - if (nw > 0) { - modemout->cnt -= nw; - modemout->offset += nw; - if (modemout->cnt == 0) { - modemout = mbfree(modemout); - LogPrintf(LogDEBUG, "ModemStartOutput: mbfree\n"); - } - } else if (nw < 0) { - if (errno != EAGAIN) { - LogPrintf(LogERROR, "modem write (%d): %s\n", modem, strerror(errno)); - reconnect(RECON_TRUE); - DownConnection(); - } - } - } -} - -int -DialModem() -{ - char ScriptBuffer[SCRIPT_LEN]; - int excode; - - strncpy(ScriptBuffer, VarDialScript, sizeof ScriptBuffer - 1); - ScriptBuffer[sizeof ScriptBuffer - 1] = '\0'; - if ((excode = DoChat(ScriptBuffer)) > 0) { - if (VarTerm) - fprintf(VarTerm, "dial OK!\n"); - strncpy(ScriptBuffer, VarLoginScript, sizeof ScriptBuffer - 1); - if ((excode = DoChat(ScriptBuffer)) > 0) { - VarAltPhone = NULL; - if (VarTerm) - fprintf(VarTerm, "login OK!\n"); - return EX_DONE; - } else if (excode == -1) - excode = EX_SIG; - else { - LogPrintf(LogWARN, "DialModem: login failed.\n"); - excode = EX_NOLOGIN; - } - ModemTimeout(NULL); /* Dummy call to check modem status */ - } else if (excode == -1) - excode = EX_SIG; - else { - LogPrintf(LogWARN, "DialModem: dial failed.\n"); - excode = EX_NODIAL; - } - HangupModem(0); - return (excode); -} - -int -ShowModemStatus(struct cmdargs const *arg) -{ - const char *dev; -#ifdef TIOCOUTQ - int nb; -#endif - - if (!VarTerm) - return 1; - - dev = *VarDevice ? VarDevice : "network"; - - fprintf(VarTerm, "device: %s speed: ", dev); - if (DEV_IS_SYNC) - fprintf(VarTerm, "sync\n"); - else - fprintf(VarTerm, "%d\n", VarSpeed); - - switch (VarParity & CSIZE) { - case CS7: - fprintf(VarTerm, "cs7, "); - break; - case CS8: - fprintf(VarTerm, "cs8, "); - break; - } - if (VarParity & PARENB) { - if (VarParity & PARODD) - fprintf(VarTerm, "odd parity, "); - else - fprintf(VarTerm, "even parity, "); - } else - fprintf(VarTerm, "no parity, "); - - fprintf(VarTerm, "CTS/RTS %s.\n", (VarCtsRts ? "on" : "off")); - - if (LogIsKept(LogDEBUG)) - fprintf(VarTerm, "fd = %d, modem control = %o\n", modem, mbits); - fprintf(VarTerm, "connect count: %d\n", connect_count); -#ifdef TIOCOUTQ - if (modem >= 0) { - if (ioctl(modem, TIOCOUTQ, &nb) >= 0) - fprintf(VarTerm, "outq: %d\n", nb); - else - fprintf(VarTerm, "outq: ioctl probe failed: %s\n", strerror(errno)); - } -#endif - fprintf(VarTerm, "outqlen: %d\n", ModemQlen()); - fprintf(VarTerm, "DialScript = %s\n", VarDialScript); - fprintf(VarTerm, "LoginScript = %s\n", VarLoginScript); - fprintf(VarTerm, "PhoneNumber(s) = %s\n", VarPhoneList); - - fprintf(VarTerm, "\n"); - throughput_disp(&throughput, VarTerm); - - return 0; -} diff --git a/usr.sbin/ppp/os.c b/usr.sbin/ppp/os.c deleted file mode 100644 index 752b5d23251..00000000000 --- a/usr.sbin/ppp/os.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * PPP OS Layer Interface Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: os.c,v 1.10 1998/06/28 09:41:44 brian Exp $ - * - */ -#include <sys/param.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <net/if.h> -#include <arpa/inet.h> - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/ioctl.h> -#include <termios.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "id.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "ipcp.h" -#include "os.h" -#include "loadalias.h" -#include "vars.h" -#include "arp.h" -#include "systems.h" -#include "route.h" -#include "lcp.h" -#include "ccp.h" - -char *IfDevName; - -static struct ifaliasreq ifra; -static struct ifreq ifrq; -static struct in_addr oldmine, oldhis; -static int linkup; - -enum set_method { SET_UP, SET_DOWN, SET_TRY }; - -static int -SetIpDevice(struct in_addr myaddr, - struct in_addr hisaddr, - struct in_addr netmask, - enum set_method how) -{ - struct sockaddr_in *sock_in; - int s; - u_int32_t mask, addr; - - s = ID0socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); - return (-1); - } - if (how == SET_DOWN) { - if (Enabled(ConfProxy)) - cifproxyarp(s, oldhis); - if (oldmine.s_addr == 0 && oldhis.s_addr == 0) { - close(s); - return (0); - } - memset(&ifra.ifra_addr, '\0', sizeof ifra.ifra_addr); - memset(&ifra.ifra_broadaddr, '\0', sizeof ifra.ifra_broadaddr); - memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); - if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { - LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n", - strerror(errno)); - close(s); - return (-1); - } - oldmine.s_addr = oldhis.s_addr = 0; - } else { - /* If given addresses are alreay set, then ignore this request */ - if (oldmine.s_addr == myaddr.s_addr && oldhis.s_addr == hisaddr.s_addr) { - close(s); - return (0); - } - - /* - * If different address has been set, then delete it first. - */ - if (oldmine.s_addr || oldhis.s_addr) { - memset(&ifra.ifra_addr, '\0', sizeof ifra.ifra_addr); - memset(&ifra.ifra_broadaddr, '\0', sizeof ifra.ifra_broadaddr); - memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); - if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { - LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n", - strerror(errno)); - close(s); - return (-1); - } - } - - /* Set interface address */ - sock_in = (struct sockaddr_in *) & (ifra.ifra_addr); - sock_in->sin_family = AF_INET; - sock_in->sin_addr = myaddr; - sock_in->sin_len = sizeof *sock_in; - - /* Set destination address */ - sock_in = (struct sockaddr_in *) & (ifra.ifra_broadaddr); - sock_in->sin_family = AF_INET; - sock_in->sin_addr = hisaddr; - sock_in->sin_len = sizeof *sock_in; - - addr = ntohl(myaddr.s_addr); - if (IN_CLASSA(addr)) - mask = IN_CLASSA_NET; - else if (IN_CLASSB(addr)) - mask = IN_CLASSB_NET; - else - mask = IN_CLASSC_NET; - - /* - * if subnet mask is given, use it instead of class mask. - */ - if (netmask.s_addr && (ntohl(netmask.s_addr) & mask) == mask) - mask = ntohl(netmask.s_addr); - - sock_in = (struct sockaddr_in *) & (ifra.ifra_mask); - sock_in->sin_family = AF_INET; - sock_in->sin_addr.s_addr = htonl(mask); - sock_in->sin_len = sizeof *sock_in; - - if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { - if (how != SET_TRY) - LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", - strerror(errno)); - close(s); - return (-1); - } - - oldhis.s_addr = hisaddr.s_addr; - oldmine.s_addr = myaddr.s_addr; - if (Enabled(ConfProxy)) - sifproxyarp(s, hisaddr); - } - close(s); - return (0); -} - -int -CleanInterface(const char *name) -{ - int s; - - s = ID0socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); - return (-1); - } - strncpy(ifrq.ifr_name, name, sizeof ifrq.ifr_name - 1); - ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; - while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { - memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); - ifra.ifra_addr = ifrq.ifr_addr; - if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { - if (ifra.ifra_addr.sa_family == AF_INET) - LogPrintf(LogERROR, "tun_configure: Can't get dst for %s on %s !\n", - inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), - name); - close(s); - return 0; - } - ifra.ifra_broadaddr = ifrq.ifr_dstaddr; - if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { - if (ifra.ifra_addr.sa_family == AF_INET) - LogPrintf(LogERROR, "tun_configure: Can't delete %s address on %s !\n", - inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), - name); - close(s); - return 0; - } - } - close(s); - - return 1; -} - -int -OsTrySetIpaddress(struct in_addr myaddr, struct in_addr hisaddr) -{ - return (SetIpDevice(myaddr, hisaddr, ifnetmask, SET_TRY)); -} - -int -OsSetIpaddress(struct in_addr myaddr, struct in_addr hisaddr) -{ - return (SetIpDevice(myaddr, hisaddr, ifnetmask, SET_UP)); -} - -static struct in_addr peer_addr; - -void -OsLinkup() -{ - char *s; - - if (linkup == 0) { - reconnectState = RECON_UNKNOWN; - if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { - char c = EX_NORMAL; - - if (write(BGFiledes[1], &c, 1) == 1) - LogPrintf(LogPHASE, "Parent notified of success.\n"); - else - LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); - close(BGFiledes[1]); - BGFiledes[1] = -1; - } - peer_addr = IpcpInfo.his_ipaddr; - s = (char *) inet_ntoa(peer_addr); - if (LogIsKept(LogLINK)) - LogPrintf(LogLINK, "OsLinkup: %s\n", s); - else - LogPrintf(LogLCP, "OsLinkup: %s\n", s); - - if (SelectSystem(inet_ntoa(IpcpInfo.want_ipaddr), LINKUPFILE) < 0) { - if (GetLabel()) { - if (SelectSystem(GetLabel(), LINKUPFILE) < 0) - SelectSystem("MYADDR", LINKUPFILE); - } else - SelectSystem("MYADDR", LINKUPFILE); - } - linkup = 1; - } -} - -int -OsLinkIsUp() -{ - return linkup; -} - -void -OsLinkdown() -{ - char *s; - int Level; - - if (linkup) { - s = (char *) inet_ntoa(peer_addr); - Level = LogIsKept(LogLINK) ? LogLINK : LogIPCP; - LogPrintf(Level, "OsLinkdown: %s\n", s); - - FsmDown(&IpcpFsm); /* IPCP must come down */ - FsmDown(&CcpFsm); /* CCP must come down */ - - linkup = 0; - if (SelectSystem(s, LINKDOWNFILE) < 0) { - if (GetLabel()) { - if (SelectSystem(GetLabel(), LINKDOWNFILE) < 0) - SelectSystem("MYADDR", LINKDOWNFILE); - } else - SelectSystem("MYADDR", LINKDOWNFILE); - } - } -} - -int -OsInterfaceDown(int final) -{ - struct in_addr zeroaddr; - int s; - - OsLinkdown(); - if (!final && (mode & MODE_DAEMON)) /* We still want interface alive */ - return (0); - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "OsInterfaceDown: socket: %s\n", strerror(errno)); - return (-1); - } - ifrq.ifr_flags &= ~IFF_UP; - if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { - LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCSIFFLAGS): %s\n", - strerror(errno)); - close(s); - return (-1); - } - zeroaddr.s_addr = 0; - SetIpDevice(zeroaddr, zeroaddr, zeroaddr, SET_DOWN); - - close(s); - return (0); -} - -/* - * Open tunnel device and returns its descriptor - */ - -#define MAX_TUN 256 -/* MAX_TUN is set at an arbitrarily large value * - * as the loop aborts when it reaches the first * - * 'Device not configured' (ENXIO), or the third * - * 'No such file or directory' (ENOENT) error. */ -int -OpenTunnel(int *ptun) -{ - int s; - char ifname[IFNAMSIZ]; - static char devname[14]; /* sufficient room for "/dev/tun65535" */ - unsigned unit, enoentcount = 0; - int err; - - err = ENOENT; - for (unit = 0; unit <= MAX_TUN; unit++) { - snprintf(devname, sizeof devname, "/dev/tun%d", unit); - tun_out = ID0open(devname, O_RDWR); - if (tun_out >= 0) - break; - if (errno == ENXIO) { - unit = MAX_TUN; - err = errno; - } else if (errno == ENOENT) { - enoentcount++; - if (enoentcount > 2) - unit = MAX_TUN; - } else - err = errno; - } - if (unit > MAX_TUN) { - if (VarTerm) - fprintf(VarTerm, "No tunnel device is available (%s).\n", strerror(err)); - return -1; - } - *ptun = unit; - - LogSetTun(unit); - - /* - * At first, name the interface. - */ - strncpy(ifname, devname + 5, IFNAMSIZ - 1); - - memset(&ifra, '\0', sizeof ifra); - memset(&ifrq, '\0', sizeof ifrq); - - strncpy(ifrq.ifr_name, ifname, IFNAMSIZ - 1); - strncpy(ifra.ifra_name, ifname, IFNAMSIZ - 1); - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "OpenTunnel: socket(): %s\n", strerror(errno)); - return (-1); - } - - /* - * Now, bring up the interface. - */ - if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { - LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", - strerror(errno)); - close(s); - return (-1); - } - ifrq.ifr_flags |= IFF_UP; - if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { - LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", - strerror(errno)); - close(s); - return (-1); - } - tun_in = tun_out; - IfDevName = devname + 5; - if (GetIfIndex(IfDevName) < 0) { - LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); - close(s); - return (-1); - } - if (VarTerm) - fprintf(VarTerm, "Using interface: %s\n", IfDevName); - LogPrintf(LogPHASE, "Using interface: %s\n", IfDevName); - close(s); - return (0); -} diff --git a/usr.sbin/ppp/os.h b/usr.sbin/ppp/os.h deleted file mode 100644 index 3197b2968e3..00000000000 --- a/usr.sbin/ppp/os.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: os.h,v 1.3 1998/01/08 23:47:09 brian Exp $ - * - * TODO: - */ - -extern char *IfDevName; - -extern int OsSetIpaddress(struct in_addr, struct in_addr); -extern int OsTrySetIpaddress(struct in_addr, struct in_addr); -extern int OsInterfaceDown(int); -extern int OpenTunnel(int *); -extern void OsLinkup(void); -extern int OsLinkIsUp(void); -extern void OsLinkdown(void); -extern int CleanInterface(const char *); diff --git a/usr.sbin/ppp/pap.c b/usr.sbin/ppp/pap.c deleted file mode 100644 index c89849136c6..00000000000 --- a/usr.sbin/ppp/pap.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * PPP PAP Module - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993-94, Internet Initiative Japan, Inc. - * All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: pap.c,v 1.4 1998/03/13 01:26:01 brian Exp $ - * - * TODO: - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <pwd.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#ifdef __OpenBSD__ -#include <util.h> -#else -#include <libutil.h> -#endif -#include <utmp.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "lcp.h" -#include "pap.h" -#include "loadalias.h" -#include "vars.h" -#include "hdlc.h" -#include "lcpproto.h" -#include "phase.h" -#include "auth.h" -#include "id.h" - -static const char *papcodes[] = { "???", "REQUEST", "ACK", "NAK" }; - -static void -SendPapChallenge(int papid) -{ - struct fsmheader lh; - struct mbuf *bp; - u_char *cp; - int namelen, keylen, plen; - - namelen = strlen(VarAuthName); - keylen = strlen(VarAuthKey); - plen = namelen + keylen + 2; - LogPrintf(LogDEBUG, "SendPapChallenge: namelen = %d, keylen = %d\n", - namelen, keylen); - if (LogIsKept(LogDEBUG)) - LogPrintf(LogPHASE, "PAP: %s (%s)\n", VarAuthName, VarAuthKey); - else - LogPrintf(LogPHASE, "PAP: %s\n", VarAuthName); - lh.code = PAP_REQUEST; - lh.id = papid; - lh.length = htons(plen + sizeof(struct fsmheader)); - bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM); - memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); - cp = MBUF_CTOP(bp) + sizeof(struct fsmheader); - *cp++ = namelen; - memcpy(cp, VarAuthName, namelen); - cp += namelen; - *cp++ = keylen; - memcpy(cp, VarAuthKey, keylen); - - HdlcOutput(PRI_LINK, PROTO_PAP, bp); -} - -struct authinfo AuthPapInfo = { - SendPapChallenge, -}; - -static void -SendPapCode(int id, int code, const char *message) -{ - struct fsmheader lh; - struct mbuf *bp; - u_char *cp; - int plen, mlen; - - lh.code = code; - lh.id = id; - mlen = strlen(message); - plen = mlen + 1; - lh.length = htons(plen + sizeof(struct fsmheader)); - bp = mballoc(plen + sizeof(struct fsmheader), MB_FSM); - memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); - cp = MBUF_CTOP(bp) + sizeof(struct fsmheader); - *cp++ = mlen; - memcpy(cp, message, mlen); - LogPrintf(LogPHASE, "PapOutput: %s\n", papcodes[code]); - HdlcOutput(PRI_LINK, PROTO_PAP, bp); -} - -/* - * Validate given username and passwrd against with secret table - */ -static int -PapValidate(u_char * name, u_char * key) -{ - int nlen, klen; - - nlen = *name++; - klen = *key; - *key++ = 0; - key[klen] = 0; - LogPrintf(LogDEBUG, "PapValidate: name %s (%d), key %s (%d)\n", - name, nlen, key, klen); - -#ifndef NOPASSWDAUTH - if (Enabled(ConfPasswdAuth)) { - struct passwd *pwd; - int result; - - LogPrintf(LogLCP, "Using PasswdAuth\n"); - result = (pwd = getpwnam(name)) && - !strcmp(crypt(key, pwd->pw_passwd), pwd->pw_passwd); - endpwent(); - return result; - } -#endif - - return (AuthValidate(SECRETFILE, name, key)); -} - -void -PapInput(struct mbuf * bp) -{ - int len = plength(bp); - struct fsmheader *php; - struct lcpstate *lcp = &LcpInfo; - u_char *cp; - - if (len >= sizeof(struct fsmheader)) { - php = (struct fsmheader *) MBUF_CTOP(bp); - if (len >= ntohs(php->length)) { - if (php->code < PAP_REQUEST || php->code > PAP_NAK) - php->code = 0; - LogPrintf(LogPHASE, "PapInput: %s\n", papcodes[php->code]); - - switch (php->code) { - case PAP_REQUEST: - cp = (u_char *) (php + 1); - if (PapValidate(cp, cp + *cp + 1)) { - SendPapCode(php->id, PAP_ACK, "Greetings!!"); - lcp->auth_ineed = 0; - if (lcp->auth_iwait == 0) { - if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) { - if (Utmp) - LogPrintf(LogERROR, "Oops, already logged in on %s\n", - VarBaseDevice); - else { - struct utmp ut; - memset(&ut, 0, sizeof ut); - time(&ut.ut_time); - strncpy(ut.ut_name, cp+1, sizeof ut.ut_name); - strncpy(ut.ut_line, VarBaseDevice, sizeof ut.ut_line - 1); - ID0login(&ut); - Utmp = 1; - } - } - NewPhase(PHASE_NETWORK); - } - } else { - SendPapCode(php->id, PAP_NAK, "Login incorrect"); - reconnect(RECON_FALSE); - LcpClose(); - } - break; - case PAP_ACK: - StopAuthTimer(&AuthPapInfo); - cp = (u_char *) (php + 1); - len = *cp++; - cp[len] = 0; - LogPrintf(LogPHASE, "Received PAP_ACK (%s)\n", cp); - if (lcp->auth_iwait == PROTO_PAP) { - lcp->auth_iwait = 0; - if (lcp->auth_ineed == 0) - NewPhase(PHASE_NETWORK); - } - break; - case PAP_NAK: - StopAuthTimer(&AuthPapInfo); - cp = (u_char *) (php + 1); - len = *cp++; - cp[len] = 0; - LogPrintf(LogPHASE, "Received PAP_NAK (%s)\n", cp); - reconnect(RECON_FALSE); - LcpClose(); - break; - } - } - } - pfree(bp); -} diff --git a/usr.sbin/ppp/pathnames.h b/usr.sbin/ppp/pathnames.h deleted file mode 100644 index 989731e946a..00000000000 --- a/usr.sbin/ppp/pathnames.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - * $Id: pathnames.h,v 1.1 1997/11/23 20:27:35 brian Exp $ - * - * @(#)pathnames.h 5.2 (Berkeley) 6/1/90 - */ - -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#define _PATH_PPP "/etc/ppp" -#else -#define _PATH_PPP "/etc" -#endif diff --git a/usr.sbin/ppp/phase.c b/usr.sbin/ppp/phase.c deleted file mode 100644 index ac808f9f4ff..00000000000 --- a/usr.sbin/ppp/phase.c +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: phase.c,v 1.4 1997/12/21 14:27:10 brian Exp $ - */ - -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "lcp.h" -#include "lcpproto.h" -#include "timer.h" -#include "auth.h" -#include "pap.h" -#include "chap.h" -#include "defs.h" -#include "ipcp.h" -#include "ccp.h" -#include "main.h" -#include "loadalias.h" -#include "vars.h" -#include "phase.h" - -int phase = 0; /* Curent phase */ - -static const char *PhaseNames[] = { - "Dead", "Establish", "Authenticate", "Network", "Terminate" -}; - -static const char * -Auth2Nam(u_short auth) -{ - switch (auth) { - case PROTO_PAP: - return "PAP"; - case PROTO_CHAP: - return "CHAP"; - case 0: - return "none"; - } - return "unknown"; -} - -void -NewPhase(int new) -{ - struct lcpstate *lcp = &LcpInfo; - - phase = new; - LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]); - switch (phase) { - case PHASE_AUTHENTICATE: - lcp->auth_ineed = lcp->want_auth; - lcp->auth_iwait = lcp->his_auth; - if (lcp->his_auth || lcp->want_auth) { - LogPrintf(LogPHASE, " his = %s, mine = %s\n", - Auth2Nam(lcp->his_auth), Auth2Nam(lcp->want_auth)); - if (lcp->his_auth == PROTO_PAP) - StartAuthChallenge(&AuthPapInfo); - if (lcp->want_auth == PROTO_CHAP) - StartAuthChallenge(&AuthChapInfo); - } else - NewPhase(PHASE_NETWORK); - break; - case PHASE_NETWORK: - IpcpUp(); - IpcpOpen(); - CcpUp(); - CcpOpen(); - break; - case PHASE_DEAD: - if (mode & MODE_DIRECT) - Cleanup(EX_DEAD); - if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE) - Cleanup(EX_DEAD); - break; - } -} diff --git a/usr.sbin/ppp/phase.h b/usr.sbin/ppp/phase.h deleted file mode 100644 index f82529d7968..00000000000 --- a/usr.sbin/ppp/phase.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: phase.h,v 1.2 1998/01/21 02:13:39 brian Exp $ - * - * TODO: - */ - -#define PHASE_DEAD 0 /* Link is dead */ -#define PHASE_ESTABLISH 1 /* Establishing link */ -#define PHASE_AUTHENTICATE 2 /* Being authenticated */ -#define PHASE_NETWORK 3 -#define PHASE_TERMINATE 4 /* Terminating link */ - -extern int phase; /* Curent phase */ - -extern void NewPhase(int); diff --git a/usr.sbin/ppp/ppp/Makefile b/usr.sbin/ppp/ppp/Makefile new file mode 100644 index 00000000000..25f289a2258 --- /dev/null +++ b/usr.sbin/ppp/ppp/Makefile @@ -0,0 +1,63 @@ +# $Id: Makefile,v 1.1 1998/08/31 00:22:14 brian Exp $ + +PROG= ppp +SRCS= arp.c async.c auth.c bundle.c cbcp.c ccp.c chap.c chat.c command.c \ + datalink.c deflate.c defs.c filter.c fsm.c hdlc.c id.c ip.c \ + ipcp.c iplist.c lcp.c link.c log.c lqr.c main.c mbuf.c modem.c \ + mp.c pap.c physical.c pred.c probe.c prompt.c route.c server.c \ + sig.c slcompress.c systems.c throughput.c timer.c tun.c vjcomp.c +CFLAGS+=-Wall +LDADD+= -lutil -lz +DPADD+= ${LIBUTIL} ${LIBZ} +BINMODE=4554 +BINOWN= root +BINGRP= network + +OPSYS!= uname -s +.if (${OPSYS} == "OpenBSD") +MAN= ppp.8 +.else +MAN8= ppp.8 +LDADD+= -lmd -lcrypt +DPADD+= ${LIBMD} ${LIBCRYPT} +.endif + +.if defined(RELEASE_CRUNCH) +CFLAGS+=-DRELEASE_CRUNCH +.endif + +.if defined(NOALIAS) +CFLAGS+=-DNOALIAS +.else +.if !defined(RELEASE_CRUNCH) +SRCS+= alias_cmd.c +.if (${OPSYS} == "OpenBSD") +CFLAGS+=-I../libalias +LDADD+= ../libalias/libalias.a +DPADD+= ../libalias/libalias.a +.else +LDADD+= -lalias +DPADD+= ${LIBALIAS} +.endif +.endif +.endif + +.if exists(${.CURDIR}/../../secure) && !defined(NOCRYPT) && !defined(NOSECURE) && !defined(RELEASE_CRUNCH) +DISTRIBUTION=des +CFLAGS+=-DHAVE_DES +SRCS+= chap_ms.c +LDADD+= -ldes +DPADD+= ${LIBDES} +.endif + +.if defined(RELEASE_CRUNCH) +# We must create these objects because the crunchgen will link them, +# and we don't want any unused symbols to spoil the final link. +CFLAGS+=-DNOALIAS +SRCS+= alias_cmd.c chap_ms.c +chap_ms.o alias_cmd.o: + >null_${.PREFIX}.c + cc -c -o ${.TARGET} null_${.PREFIX}.c +.endif + +.include <bsd.prog.mk> diff --git a/usr.sbin/ppp/README.alias b/usr.sbin/ppp/ppp/README.alias index de5b3c90af7..5d297738b2f 100644 --- a/usr.sbin/ppp/README.alias +++ b/usr.sbin/ppp/ppp/README.alias @@ -7,7 +7,7 @@ User PPP Packet Aliasing 2. Setup 3. New commands in ppp 4. Future Work - 5. Authors / Acknowledgments + 5. Authors / Acknowledgements 6. Revision History for Aliasing Code @@ -52,7 +52,7 @@ masquerading solutions. The implementation supports all standard, non-encoding TCP and UDP protocols. Examples of these protocols are http, gopher and telnet. The standard UDP -mode of RealAudio is not presently supported, but the TCP mode does work +mode of Real-Audio is not presently supported, but the TCP mode does work correctly. The packet aliasing code also handle many ICMP messages. In particular, @@ -86,12 +86,12 @@ and masks. 3. New commands in ppp -In order to control aliasing behavior in a simple manner (no need for -recompilation), a new command has been added to iij-ppp: alias. This +In order to control aliasing behaviour in a simple manner (no need for +recompilation), a new command has been added to ppp: alias. This is in addition to the -alias command line option. System managers and -more experienced users may prefer to use the iij-ppp command syntax +more experienced users may prefer to use the ppp command syntax within the ppp.conf file. The alias command also allows packet aliasing -behavior to be more precisely specified. +behaviour to be more precisely specified. The decision to add a command instead of extending 'set' or 'option' was to make obvious that these options only work when aliasing is enabled. @@ -119,7 +119,7 @@ Set to "yes" to disable all incoming connections. This just drops connections to, for example, ftp, telnet or web servers. The aliasing mechanism prevents these connections. Technically, this option denies all incoming TCP and UDP requests, making the aliasing software a -fairly efficient one-way firewall. The default is no, which will +fairly efficient one-way firewall. The default is no, which will allow all incoming connections to telnetd, ftpd, etc. @@ -128,7 +128,7 @@ all incoming connections to telnetd, ftpd, etc. Controls logging of alias link creation to "/var/log/alias.log" - this is usually only useful if debugging a setup, to see if the bug is in the PPP aliasing. The debugging information is fairly limited, listing -the number of aliasing links open for different prototocols. +the number of aliasing links open for different protocols. - alias same_ports [yes|no] (default yes) @@ -137,7 +137,7 @@ When a connection is being established going through the aliasing routines, it will normally have its port number changed to allow the aliasing code to track it. If same_ports is enabled, the alias software attempts to keep the connection's source port unchanged. -This will allow rsh, RPC and other specialized protocols to work +This will allow rsh, RPC and other specialised protocols to work _most of the time_, at least on the host machine. Please, do not report this being unstable as a bug - it is a result of the way aliasing has to work. TCP/IP was intended to have one IP address @@ -149,11 +149,11 @@ per machine. This is a fairly obscure option. For the most part, the packet aliasing software does not have to allocate system sockets when it chooses an aliasing port number. Under very specific circumstances, FTP data -connections (which don't know the remote port nubmer, though it is +connections (which don't know the remote port number, though it is usually 20) and IRC DCC send (which doesn't know either the address or the port from which the connection will come), there can potentially be some interference with an open server socket having the same port number -on the ppp host machine. This possibility for interferience only exists +on the ppp host machine. This possibility for interference only exists until the TCP connection has been acknowledged on both sides. The safe option is yes, though fewer system resources are consumed by specifying no. @@ -183,7 +183,7 @@ local area network. One example of this would be: alias port tcp 192.168.0.4:telnet 8066 -All traffic to port 8066 fthe ppp host would then be sent to +All traffic to port 8066 of the ppp host would then be sent to the telnet port (23) of machine 192.168.0.4. Port numbers can either be designated numerically or by symbolic names listed in /etc/services. Similarly, addresses can be either @@ -205,14 +205,14 @@ case of a single, dynamically allocated IP address: The above command would redirect all incoming traffic to machine 10.0.0.8. -If several address aliases specifiy the same public addres +If several address aliases specify the same public address as follows alias addr 192.168.0.2 public_addr alias addr 192.168.0.3 public_addr alias addr 192.168.0.4 public_addr -then incoming traffice will be directed to the last +then incoming traffic will be directed to the last translated local address (192.168.0.4), but outgoing traffic to the first two addresses will still be aliased to the specified public address. @@ -239,12 +239,12 @@ robust. The packet aliasing engine (alias.c, alias_db.c, alias_ftp.c, alias_irc.c and alias_util.c) runs in user space, and is intended to be both portable and reusable for interfaces other than ppp. To access the basic engine -only requires four simple function calls (initialization, communication of +only requires four simple function calls (initialisation, communication of host address, outgoing aliasing and incoming de-aliasing). -5. Authors / Acknowledgments +5. Authors / Acknowledgements Charles Mott (cmott@srv.net) <versions 1.0 - 1.8, 2.0, 2.1> Eivind Eklund (perhaps@yes.no) <versions 1.8b - 1.9, new ppp commands> @@ -275,7 +275,7 @@ Version 1.2: September 7, 1996 (cjm) Fragment handling error in alias_db.c corrected. Version 1.3: September 15, 1996 (cjm) - - Generalized mechanism for handling incoming connections + - Generalised mechanism for handling incoming connections (no more 0 to 1023 restriction). - Increased ICMP support (will handle traceroute now). - Improved TCP close connection logic. @@ -291,7 +291,7 @@ Version 1.6: September 18, 1996 Simplified ICMP data storage. Will now handle tracert from Win95 as well as FreeBSD traceroute. -Verstion 1.7: January 9, 1997 (cjm) +Version 1.7: January 9, 1997 (cjm) - Reduced malloc() activity for ICMP echo and timestamp requests. - Added handling for out-of-order IP fragments. @@ -303,12 +303,12 @@ Verstion 1.7: January 9, 1997 (cjm) from two hosts which are both running packet aliasing. -Verstion 1.8: January 14, 1997 (cjm) +Version 1.8: January 14, 1997 (cjm) - Fixed data type error in function StartPoint() in alias_db.c (this bug did not exist before v1.7) Version 1.8b: January 16, 1997 (Eivind Eklund <perhaps@yes.no>) - - Upgraded base PPP version to be the sourcecode from + - Upgraded base PPP version to be the source code from FreeBSD 2.1.6, with additional security patches. This version should still be possible to run on 2.1.5, though - I've run it with a 2.1.5 kernel without problems. @@ -335,10 +335,10 @@ Version 1.9: February 1, 1997 (Eivind Eklund <perhaps@yes.no>) (cjm) Version 2.0: March, 1997 (cjm) - - Incoming packets which are not recognized by the packet + - Incoming packets which are not recognised by the packet aliasing engine are now completely dropped in ip.c. - Aliasing links are cleared when a host interface address - changes (due to re-dial and dynamic address allocatioa). + changes (due to re-dial and dynamic address allocation). - PacketAliasPermanentLink() API added. - Option for only aliasing private, unregistered IP addresses added. @@ -347,6 +347,6 @@ Version 2.0: March, 1997 (cjm) Version 2.1: May, 1997 (cjm) - Continuing rework to the aliasing lookup engine to support multiple incoming addresses and static NAT. - - Now supports outgoing as well as incoming ICMP error messges/ + - Now supports outgoing as well as incoming ICMP error messages/ - PPP commands to support address and port redirection. diff --git a/usr.sbin/ppp/ppp/README.changes b/usr.sbin/ppp/ppp/README.changes new file mode 100644 index 00000000000..3e4873e5a5f --- /dev/null +++ b/usr.sbin/ppp/ppp/README.changes @@ -0,0 +1,73 @@ +This file summarises changes made to ppp that effect +its configuration. + +It does not describe new features, rather it attempts +to answer any `this used to work, why doesn't it now?' +questions. + +o The `set debug' command was replaced with `set log'. +o The `set log LCP' command was split into LCP, IPCP and CCP logs. +o Syslogd is used for logging. /etc/syslog.conf must be updated. +o LQR is disabled by default. +o Openmode is active by default. +o Users must be a member of group `network' for ppp access. Furthermore, + they must be `allow'ed to run ppp via the `allow' command in the + configuration file. + For a brief period, ppp could only be run as root. +o No diagnostic socket is created by default. The `set server' command + must be used. +o The diagnostic socket password must be specified *only* on the `set + server' command line. +o When `set server' is used to re-select a diagnostic port, all existing + diagnostic connections are dropped. +o pppd-deflate is now called deflate24. +o Filter IPs of 0.0.0.0 have a default width of 0, not 32. +o Errors in `add' and `delete' are logged as warnings rather than being + written to the TCP/IP log. +o Any number of diagnostic prompts are allowed, and they are allowed in + interactive mode. +o The default `device' is cuaa1, then cuaa0 +o A password of "*" in ppp.secret causes a passwd database lookup in + pap mode. +o The value of the CONNECT environment variable is logged in the + utmp host field in -direct mode. +o Out-of-sequence FSM packets (IPCP/LCP/CCP) are dropped by default. +o Reconnect values are used after an LQR timeout. +o ^C works on the parent in -background mode. +o The dial/call/open command works asynchronously. As a result, prompts + do not lose control while dialing. +o The `display' command has been removed. All information is available + with the appropriate `show' command. +o Msext does not need to be enabled/disabled. Setting the NBNS (set nbns) + will auto enable it. The DNS side may be enabled/disabled, and if + enabled without a `set dns' (was `set ns') will use values from + /etc/resolv.conf. +o Filters are now called `allow', `dial', `in' and `out'. `set + ifilter ...' becomes `set filter in ...' etc. +o Authname and Authkey may only be `set' in phase DEAD. +o Set encrypt is no longer necessary. Ppp will respond to M$CHAP + servers correctly if it's built with DES. +o Throughput statistics are enabled by default. +o `Set stopped' only has two parameters. It's no longer possible to + have an IPCP stopped timer. +o `Set timeout' only has one parameter. Use `set lqrperiod' and `set + {lcp,ccp,ipcp,chap,pap}retry' for the other timers. `show timeout' + is also now available using the relevant show commands. +o `set loopback' is now `enable/disable loopback'. +o `show auto', `show loopback' and `show mtu' are all part of `show bundle'. +o `show mru' is part of `show lcp' +o `show msext' and `show vj' are part of `show ipcp' +o `show reconnect' and `show redial' are part of `show link' +o A signal 15 (TERM) will now shut down the link gracefully. +o A signal 2 (HUP) will drop all links immediately. +o Signal 30 (USR1) is now ignored. +o Add & delete commands are not necessary in ppp.linkup if they are + `sticky routes' (ie, contain MYADDR or HISADDR). +o LINK and CARRIER logging are no longer available. +o Timer based DEBUG messages are now logged in the new TIMER log. +o Ppp can use tun devices > tun255. +o Protocol-compressed packets are accepted even if they were denied + at LCP negotiation time. +o Passwords aren't logged when logging the ``set server'' line. +o Command line options only need enough characters to uniquely identify + them. -a == -auto, -dd == -ddial etc. -interactive is also allowed. diff --git a/usr.sbin/ppp/README.devel b/usr.sbin/ppp/ppp/README.devel index 28f54ee0901..c18e85eaedf 100644 --- a/usr.sbin/ppp/README.devel +++ b/usr.sbin/ppp/ppp/README.devel @@ -4,19 +4,22 @@ The original version was usually referred to as iij-ppp. Ppp is currently maintained under FreeBSD and OpenBSD by Brian Somers <brian@Awfulhak.org>. The sources for both operating systems are the -same although the Makefiles vary due to the nature of each system. -If and when it's ported to another OS, things will probably be shuffled -around so that there are several Makefiles, one per architecture. +same except that OpenBSD is missing some files (the OpenBSD project +does not want libalias - not as a library anyway) and the Makefiles vary +due to the nature of each system. If and when it's ported to another OS, +things will probably be shuffled around so that there are several Makefiles, +one per architecture. The latest sources are available in FreeBSD-current and OpenBSD-current. An archive hacked so that it will build on just about any version of FreeBSD is frequently generated and made available on -http://www.FreeBSD.org/~brian. Once the first OpenBSD release is made -with ppp, an up-to-date OpenBSD archive will be made available too. +http://www.FreeBSD.org/~brian. An up-to-date OpenBSD archive will also be +made available soon. A FAQ is available at http://www.FreeBSD.org/FAQ/userppp.html. It applies equally to OpenBSD as it does to FreeBSD. The man page is quite extensive, and there are lots of examples in /etc/ppp/ppp.*.sample. These examples -come with the hacked archive above but must be installed manually. +come with the hacked archive above but must be installed manually with +``make etc-install''. Ppp is still under development. There is no official TODO list. diff --git a/usr.sbin/ppp/ppp/alias_cmd.c b/usr.sbin/ppp/ppp/alias_cmd.c new file mode 100644 index 00000000000..cfef974bfb0 --- /dev/null +++ b/usr.sbin/ppp/ppp/alias_cmd.c @@ -0,0 +1,211 @@ +/*- + * The code in this file was written by Eivind Eklund <perhaps@yes.no>, + * who places it in the public domain without restriction. + * + * $Id: alias_cmd.c,v 1.1 1998/08/31 00:22:15 brian Exp $ + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <alias.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "log.h" +#include "alias_cmd.h" +#include "descriptor.h" +#include "prompt.h" +#include "timer.h" +#include "fsm.h" +#include "slcompress.h" +#include "throughput.h" +#include "iplist.h" +#include "mbuf.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "filter.h" +#include "bundle.h" + + +static int StrToAddr(const char *, struct in_addr *); +static int StrToPort(const char *, u_short *, const char *); +static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, const char *); + + +int +alias_RedirectPort(struct cmdargs const *arg) +{ + if (!arg->bundle->AliasEnabled) { + prompt_Printf(arg->prompt, "Alias not enabled\n"); + return 1; + } else if (arg->argc == arg->argn+3) { + char proto_constant; + const char *proto; + u_short local_port; + u_short alias_port; + int error; + struct in_addr local_addr; + struct in_addr null_addr; + struct alias_link *link; + + proto = arg->argv[arg->argn]; + if (strcmp(proto, "tcp") == 0) { + proto_constant = IPPROTO_TCP; + } else if (strcmp(proto, "udp") == 0) { + proto_constant = IPPROTO_UDP; + } else { + prompt_Printf(arg->prompt, "port redirect: protocol must be" + " tcp or udp\n"); + prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + return 1; + } + + error = StrToAddrAndPort(arg->argv[arg->argn+1], &local_addr, &local_port, + proto); + if (error) { + prompt_Printf(arg->prompt, "port redirect: error reading" + " local addr:port\n"); + prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + return 1; + } + error = StrToPort(arg->argv[arg->argn+2], &alias_port, proto); + if (error) { + prompt_Printf(arg->prompt, "port redirect: error reading alias port\n"); + prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + return 1; + } + null_addr.s_addr = INADDR_ANY; + + link = PacketAliasRedirectPort(local_addr, local_port, + null_addr, 0, + null_addr, alias_port, + proto_constant); + + if (link == NULL) + prompt_Printf(arg->prompt, "port redirect: error returned by packed" + " aliasing engine (code=%d)\n", error); + } else + return -1; + + return 0; +} + + +int +alias_RedirectAddr(struct cmdargs const *arg) +{ + if (!arg->bundle->AliasEnabled) { + prompt_Printf(arg->prompt, "alias not enabled\n"); + return 1; + } else if (arg->argc == arg->argn+2) { + int error; + struct in_addr local_addr; + struct in_addr alias_addr; + struct alias_link *link; + + error = StrToAddr(arg->argv[arg->argn], &local_addr); + if (error) { + prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); + return 1; + } + error = StrToAddr(arg->argv[arg->argn+1], &alias_addr); + if (error) { + prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); + prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + return 1; + } + link = PacketAliasRedirectAddr(local_addr, alias_addr); + if (link == NULL) { + prompt_Printf(arg->prompt, "address redirect: packet aliasing" + " engine error\n"); + prompt_Printf(arg->prompt, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + } + } else + return -1; + + return 0; +} + + +static int +StrToAddr(const char *str, struct in_addr *addr) +{ + struct hostent *hp; + + if (inet_aton(str, addr)) + return 0; + + hp = gethostbyname(str); + if (!hp) { + log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); + return -1; + } + *addr = *((struct in_addr *) hp->h_addr); + return 0; +} + + +static int +StrToPort(const char *str, u_short *port, const char *proto) +{ + int iport; + struct servent *sp; + char *end; + + iport = strtol(str, &end, 10); + if (end != str) { + *port = htons(iport); + return 0; + } + sp = getservbyname(str, proto); + if (!sp) { + log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", + str, proto); + return -1; + } + *port = sp->s_port; + return 0; +} + + +static int +StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *port, const char *proto) +{ + char *colon; + int res; + + colon = strchr(str, ':'); + if (!colon) { + log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); + return -1; + } + + *colon = '\0'; /* Cheat the const-ness ! */ + res = StrToAddr(str, addr); + *colon = ':'; /* Cheat the const-ness ! */ + if (res != 0) + return -1; + + return StrToPort(colon+1, port, proto); +} diff --git a/usr.sbin/ppp/ppp/alias_cmd.h b/usr.sbin/ppp/ppp/alias_cmd.h new file mode 100644 index 00000000000..ff5476659b4 --- /dev/null +++ b/usr.sbin/ppp/ppp/alias_cmd.h @@ -0,0 +1,11 @@ +/*- + * The code in this file was written by Eivind Eklund <perhaps@yes.no>, + * who places it in the public domain without restriction. + * + * $Id: alias_cmd.h,v 1.1 1998/08/31 00:22:15 brian Exp $ + */ + +struct cmdargs; + +extern int alias_RedirectPort(struct cmdargs const *); +extern int alias_RedirectAddr(struct cmdargs const *); diff --git a/usr.sbin/ppp/arp.c b/usr.sbin/ppp/ppp/arp.c index be66deee71b..1e1df64dbd2 100644 --- a/usr.sbin/ppp/arp.c +++ b/usr.sbin/ppp/ppp/arp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: arp.c,v 1.10 1998/01/24 00:00:33 brian Exp $ + * $Id: arp.c,v 1.1 1998/08/31 00:22:15 brian Exp $ * */ @@ -25,57 +25,46 @@ * TODO: */ -#include <sys/param.h> -#include <sys/time.h> +#include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <net/route.h> #include <net/if_dl.h> #include <netinet/in.h> -#include <net/if_types.h> #include <netinet/if_ether.h> #include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> -#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/errno.h> -#include <sys/ioctl.h> #include <sys/sysctl.h> -#include <sys/uio.h> #include <unistd.h> -#include "command.h" #include "mbuf.h" #include "log.h" #include "id.h" -#include "route.h" +#include "timer.h" +#include "fsm.h" +#include "defs.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" #include "arp.h" -#ifdef DEBUG -/* - * To test the proxy arp stuff, just - * - * cc -o arp-test -DDEBUG arp.c - * - */ -#define LogIsKept(x) 1 -#define LogPrintf fprintf -#undef LogDEBUG -#define LogDEBUG stderr -#undef LogERROR -#define LogERROR stderr -#undef LogPHASE -#define LogPHASE stdout -#define ID0socket socket -#define ID0ioctl ioctl -#endif - -static int rtm_seq; - -static int get_ether_addr(int, struct in_addr, struct sockaddr_dl *); - /* * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, * if it exists. @@ -89,7 +78,7 @@ static int get_ether_addr(int, struct in_addr, struct sockaddr_dl *); #if RTM_VERSION >= 3 /* - * sifproxyarp - Make a proxy ARP entry for the peer. + * arp_SetProxy - Make a proxy ARP entry for the peer. */ static struct { struct rt_msghdr hdr; @@ -101,7 +90,7 @@ static struct { static int arpmsg_valid; int -sifproxyarp(int unit, struct in_addr hisaddr) +arp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) { int routes; @@ -110,31 +99,31 @@ sifproxyarp(int unit, struct in_addr hisaddr) * address. */ memset(&arpmsg, 0, sizeof arpmsg); - if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { - LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n"); + if (!get_ether_addr(s, addr, &arpmsg.hwa)) { + log_Printf(LogWARN, "Cannot determine ethernet address for proxy ARP\n"); return 0; } routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); if (routes < 0) { - LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", + log_Printf(LogERROR, "arp_SetProxy: opening routing socket: %s\n", strerror(errno)); return 0; } arpmsg.hdr.rtm_type = RTM_ADD; arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; arpmsg.hdr.rtm_version = RTM_VERSION; - arpmsg.hdr.rtm_seq = ++rtm_seq; + arpmsg.hdr.rtm_seq = ++bundle->routing_seq; arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; arpmsg.hdr.rtm_inits = RTV_EXPIRE; arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); arpmsg.dst.sin_family = AF_INET; - arpmsg.dst.sin_addr.s_addr = hisaddr.s_addr; + arpmsg.dst.sin_addr.s_addr = addr.s_addr; arpmsg.dst.sin_other = SIN_PROXY; arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg + arpmsg.hwa.sdl_len; if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { - LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); + log_Printf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); close(routes); return 0; } @@ -144,10 +133,10 @@ sifproxyarp(int unit, struct in_addr hisaddr) } /* - * cifproxyarp - Delete the proxy ARP entry for the peer. + * arp_ClearProxy - Delete the proxy ARP entry for the peer. */ int -cifproxyarp(int unit, struct in_addr hisaddr) +arp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) { int routes; @@ -156,16 +145,16 @@ cifproxyarp(int unit, struct in_addr hisaddr) arpmsg_valid = 0; arpmsg.hdr.rtm_type = RTM_DELETE; - arpmsg.hdr.rtm_seq = ++rtm_seq; + arpmsg.hdr.rtm_seq = ++bundle->routing_seq; routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); if (routes < 0) { - LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", + log_Printf(LogERROR, "arp_SetProxy: opening routing socket: %s\n", strerror(errno)); return 0; } if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { - LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); + log_Printf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); close(routes); return 0; } @@ -176,10 +165,10 @@ cifproxyarp(int unit, struct in_addr hisaddr) #else /* RTM_VERSION */ /* - * sifproxyarp - Make a proxy ARP entry for the peer. + * arp_SetProxy - Make a proxy ARP entry for the peer. */ int -sifproxyarp(int unit, struct in_addr hisaddr) +arp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) { struct arpreq arpreq; struct { @@ -193,36 +182,38 @@ sifproxyarp(int unit, struct in_addr hisaddr) * Get the hardware address of an interface on the same subnet as our local * address. */ - if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { - LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); + if (!get_ether_addr(s, addr, &dls.sdl)) { + log_Printf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); return 0; } arpreq.arp_ha.sa_len = sizeof(struct sockaddr); arpreq.arp_ha.sa_family = AF_UNSPEC; memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); - ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr.s_addr; + ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; - if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { - LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno)); + if (ID0ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) { + log_Printf(LogERROR, "arp_SetProxy: ioctl(SIOCSARP): %s\n", + strerror(errno)); return 0; } return 1; } /* - * cifproxyarp - Delete the proxy ARP entry for the peer. + * arp_ClearProxy - Delete the proxy ARP entry for the peer. */ int -cifproxyarp(int unit, struct in_addr hisaddr) +arp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) { struct arpreq arpreq; memset(&arpreq, '\0', sizeof arpreq); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); - ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr.s_addr; - if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { - LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno)); + ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; + if (ID0ioctl(s, SIOCDARP, (caddr_t) & arpreq) < 0) { + log_Printf(LogERROR, "arp_ClearProxy: ioctl(SIOCDARP): %s\n", + strerror(errno)); return 0; } return 1; @@ -236,7 +227,7 @@ cifproxyarp(int unit, struct in_addr hisaddr) * the same subnet as ipaddr. */ -static int +int get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) { int mib[6], sa_len, skip, b; @@ -256,7 +247,7 @@ get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "get_ether_addr: sysctl: estimate: %s\n", + log_Printf(LogERROR, "get_ether_addr: sysctl: estimate: %s\n", strerror(errno)); return 0; } @@ -289,9 +280,9 @@ get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) (RTA_NETMASK|RTA_IFA)) continue; /* Found a candidate. Do the addresses match ? */ - if (LogIsKept(LogDEBUG) && + if (log_IsKept(LogDEBUG) && ptr == (char *)ifm + ifm->ifm_msglen + ifam->ifam_msglen) - LogPrintf(LogDEBUG, "%.*s interface is a candidate for proxy\n", + log_Printf(LogDEBUG, "%.*s interface is a candidate for proxy\n", dl->sdl_nlen, dl->sdl_data); b = 1; ifa = mask = NULL; @@ -315,18 +306,18 @@ get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) } b <<= 1; } - if (LogIsKept(LogDEBUG)) { + if (log_IsKept(LogDEBUG)) { char a[16]; strncpy(a, inet_ntoa(mask->sin_addr), sizeof a - 1); a[sizeof a - 1] = '\0'; - LogPrintf(LogDEBUG, "Check addr %s, mask %s\n", + log_Printf(LogDEBUG, "Check addr %s, mask %s\n", inet_ntoa(ifa->sin_addr), a); } if (ifa->sin_family == AF_INET && (ifa->sin_addr.s_addr & mask->sin_addr.s_addr) == (ipaddr.s_addr & mask->sin_addr.s_addr)) { - LogPrintf(LogPHASE, "Found interface %.*s for proxy arp\n", - dl->sdl_alen, dl->sdl_data); + log_Printf(LogPHASE, "Found interface %.*s for %s\n", + dl->sdl_alen, dl->sdl_data, inet_ntoa(ipaddr)); memcpy(hwaddr, dl, dl->sdl_len); free(buf); return 1; @@ -337,19 +328,3 @@ get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) return 0; } - -#ifdef DEBUG -int -main(int argc, char **argv) -{ - struct in_addr ipaddr; - int s, f; - - s = socket(AF_INET, SOCK_DGRAM, 0); - for (f = 1; f < argc; f++) { - if (inet_aton(argv[f], &ipaddr)) - sifproxyarp(s, ipaddr); - } - close(s); -} -#endif diff --git a/usr.sbin/ppp/main.h b/usr.sbin/ppp/ppp/arp.h index d4439eaa563..a37821924eb 100644 --- a/usr.sbin/ppp/main.h +++ b/usr.sbin/ppp/ppp/arp.h @@ -17,15 +17,13 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: main.h,v 1.2 1998/01/20 22:46:28 brian Exp $ + * $Id: arp.h,v 1.1 1998/08/31 00:22:15 brian Exp $ * */ -extern int TermMode; -extern int tunno; +struct sockaddr_dl; +struct bundle; -extern void Cleanup(int); -extern void TtyTermMode(void); -extern void PacketMode(int); -extern void TtyOldMode(void); -extern void TtyCommandMode(int); +extern int arp_ClearProxy(struct bundle *, struct in_addr, int); +extern int arp_SetProxy(struct bundle *, struct in_addr, int); +extern int get_ether_addr(int, struct in_addr, struct sockaddr_dl *); diff --git a/usr.sbin/ppp/async.c b/usr.sbin/ppp/ppp/async.c index 137b6f9ca92..a4502ca1b5d 100644 --- a/usr.sbin/ppp/async.c +++ b/usr.sbin/ppp/ppp/async.c @@ -17,78 +17,64 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: async.c,v 1.3 1998/06/27 12:06:39 brian Exp $ + * $Id: async.c,v 1.1 1998/08/31 00:22:15 brian Exp $ * */ -#include <sys/param.h> -#include <netinet/in.h> +#include <sys/types.h> -#include <stdio.h> #include <string.h> #include <termios.h> -#include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" +#include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "lcpproto.h" -#include "modem.h" -#include "loadalias.h" -#include "vars.h" #include "async.h" - -#define HDLCSIZE (MAX_MRU*2+6) - -static struct async_state { - int mode; - int length; - u_char hbuff[HDLCSIZE]; /* recv buffer */ - u_char xbuff[HDLCSIZE]; /* xmit buffer */ - u_int32_t my_accmap; - u_int32_t his_accmap; -} AsyncState; +#include "throughput.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "physical.h" #define MODE_HUNT 0x01 #define MODE_ESC 0x02 void -AsyncInit() +async_Init(struct async *async) { - struct async_state *stp = &AsyncState; - - stp->mode = MODE_HUNT; - stp->length = 0; - stp->my_accmap = stp->his_accmap = 0xffffffff; + async->mode = MODE_HUNT; + async->length = 0; + async->my_accmap = async->his_accmap = 0xffffffff; + memset(async->cfg.EscMap, '\0', sizeof async->cfg.EscMap); } void -SetLinkParams(struct lcpstate *lcp) +async_SetLinkParams(struct async *async, struct lcp *lcp) { - struct async_state *stp = &AsyncState; - - stp->my_accmap = lcp->want_accmap; - stp->his_accmap = lcp->his_accmap; + async->my_accmap = lcp->want_accmap; + async->his_accmap = lcp->his_accmap; } /* * Encode into async HDLC byte code if necessary */ static void -HdlcPutByte(u_char **cp, u_char c, int proto) +HdlcPutByte(struct async *async, u_char **cp, u_char c, int proto) { u_char *wp; wp = *cp; - if ((c < 0x20 && (proto == PROTO_LCP || (AsyncState.his_accmap & (1 << c)))) + if ((c < 0x20 && (proto == PROTO_LCP || (async->his_accmap & (1 << c)))) || (c == HDLC_ESC) || (c == HDLC_SYN)) { *wp++ = HDLC_ESC; c ^= HDLC_XOR; } - if (EscMap[32] && EscMap[c >> 3] & (1 << (c & 7))) { + if (async->cfg.EscMap[32] && async->cfg.EscMap[c >> 3] & (1 << (c & 7))) { *wp++ = HDLC_ESC; c ^= HDLC_XOR; } @@ -97,27 +83,26 @@ HdlcPutByte(u_char **cp, u_char c, int proto) } void -AsyncOutput(int pri, struct mbuf *bp, int proto) +async_Output(int pri, struct mbuf *bp, int proto, struct physical *physical) { - struct async_state *hs = &AsyncState; u_char *cp, *sp, *ep; struct mbuf *wp; int cnt; - if (plength(bp) > HDLCSIZE) { - pfree(bp); + if (mbuf_Length(bp) > HDLCSIZE) { + mbuf_Free(bp); return; } - cp = hs->xbuff; + cp = physical->async.xbuff; ep = cp + HDLCSIZE - 10; wp = bp; *cp++ = HDLC_SYN; while (wp) { sp = MBUF_CTOP(wp); for (cnt = wp->cnt; cnt > 0; cnt--) { - HdlcPutByte(&cp, *sp++, proto); + HdlcPutByte(&physical->async, &cp, *sp++, proto); if (cp >= ep) { - pfree(bp); + mbuf_Free(bp); return; } } @@ -125,72 +110,74 @@ AsyncOutput(int pri, struct mbuf *bp, int proto) } *cp++ = HDLC_SYN; - cnt = cp - hs->xbuff; - LogDumpBuff(LogASYNC, "WriteModem", hs->xbuff, cnt); - WriteModem(pri, (char *) hs->xbuff, cnt); - ModemAddOutOctets(cnt); - pfree(bp); + cnt = cp - physical->async.xbuff; + log_DumpBuff(LogASYNC, "WriteModem", physical->async.xbuff, cnt); + link_Write(&physical->link, pri, (char *)physical->async.xbuff, cnt); + link_AddOutOctets(&physical->link, cnt); + mbuf_Free(bp); } static struct mbuf * -AsyncDecode(u_char c) +async_Decode(struct async *async, u_char c) { - struct async_state *hs = &AsyncState; struct mbuf *bp; - if ((hs->mode & MODE_HUNT) && c != HDLC_SYN) + if ((async->mode & MODE_HUNT) && c != HDLC_SYN) return NULL; switch (c) { case HDLC_SYN: - hs->mode &= ~MODE_HUNT; - if (hs->length) { /* packet is ready. */ - bp = mballoc(hs->length, MB_ASYNC); - mbwrite(bp, hs->hbuff, hs->length); - hs->length = 0; + async->mode &= ~MODE_HUNT; + if (async->length) { /* packet is ready. */ + bp = mbuf_Alloc(async->length, MB_ASYNC); + mbuf_Write(bp, async->hbuff, async->length); + async->length = 0; return bp; } break; case HDLC_ESC: - if (!(hs->mode & MODE_ESC)) { - hs->mode |= MODE_ESC; + if (!(async->mode & MODE_ESC)) { + async->mode |= MODE_ESC; break; } /* Fall into ... */ default: - if (hs->length >= HDLCSIZE) { + if (async->length >= HDLCSIZE) { /* packet is too large, discard it */ - LogPrintf(LogERROR, "Packet too large (%d), discarding.\n", hs->length); - hs->length = 0; - hs->mode = MODE_HUNT; + log_Printf(LogWARN, "Packet too large (%d), discarding.\n", + async->length); + async->length = 0; + async->mode = MODE_HUNT; break; } - if (hs->mode & MODE_ESC) { + if (async->mode & MODE_ESC) { c ^= HDLC_XOR; - hs->mode &= ~MODE_ESC; + async->mode &= ~MODE_ESC; } - hs->hbuff[hs->length++] = c; + async->hbuff[async->length++] = c; break; } return NULL; } void -AsyncInput(u_char *buff, int cnt) +async_Input(struct bundle *bundle, u_char *buff, int cnt, + struct physical *physical) { struct mbuf *bp; - ModemAddInOctets(cnt); - if (DEV_IS_SYNC) { - bp = mballoc(cnt, MB_ASYNC); + link_AddInOctets(&physical->link, cnt); + + if (physical_IsSync(physical)) { + bp = mbuf_Alloc(cnt, MB_ASYNC); memcpy(MBUF_CTOP(bp), buff, cnt); bp->cnt = cnt; - HdlcInput(bp); + hdlc_Input(bundle, bp, physical); } else { while (cnt > 0) { - bp = AsyncDecode(*buff++); + bp = async_Decode(&physical->async, *buff++); if (bp) - HdlcInput(bp); + hdlc_Input(bundle, bp, physical); cnt--; } } diff --git a/usr.sbin/ppp/ppp/async.h b/usr.sbin/ppp/ppp/async.h new file mode 100644 index 00000000000..ccac7fe481c --- /dev/null +++ b/usr.sbin/ppp/ppp/async.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: async.h,v 1.1 1998/08/31 00:22:16 brian Exp $ + */ + +#define HDLCSIZE (MAX_MRU*2+6) + +struct async { + int mode; + int length; + u_char hbuff[HDLCSIZE]; /* recv buffer */ + u_char xbuff[HDLCSIZE]; /* xmit buffer */ + u_int32_t my_accmap; + u_int32_t his_accmap; + + struct { + u_char EscMap[33]; + } cfg; +}; + +struct lcp; +struct mbuf; +struct physical; +struct bundle; + +extern void async_Init(struct async *); +extern void async_SetLinkParams(struct async *, struct lcp *); +extern void async_Output(int, struct mbuf *, int, struct physical *); +extern void async_Input(struct bundle *, u_char *, int, struct physical *); diff --git a/usr.sbin/ppp/ppp/auth.c b/usr.sbin/ppp/ppp/auth.c new file mode 100644 index 00000000000..6d65156bf25 --- /dev/null +++ b/usr.sbin/ppp/ppp/auth.c @@ -0,0 +1,279 @@ +/* + * PPP Secret Key Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: auth.c,v 1.1 1998/08/31 00:22:16 brian Exp $ + * + * TODO: + * o Implement check against with registered IP addresses. + */ +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "mbuf.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "auth.h" +#include "systems.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "chat.h" +#include "lcpproto.h" +#include "filter.h" +#include "mp.h" +#include "bundle.h" + +const char * +Auth2Nam(u_short auth) +{ + switch (auth) { + case PROTO_PAP: + return "PAP"; + case PROTO_CHAP: + return "CHAP"; + case 0: + return "none"; + } + return "unknown"; +} + +static int +auth_CheckPasswd(const char *name, const char *data, const char *key) +{ + if (!strcmp(data, "*")) { + /* Then look up the real password database */ + struct passwd *pw; + int result; + + result = (pw = getpwnam(name)) && + !strcmp(crypt(key, pw->pw_passwd), pw->pw_passwd); + endpwent(); + return result; + } + + return !strcmp(data, key); +} + +int +auth_SetPhoneList(const char *name, char *phone, int phonelen) +{ + FILE *fp; + int n; + char *vector[6]; + char buff[LINE_LEN]; + + fp = OpenSecret(SECRETFILE); + if (fp != NULL) { + while (fgets(buff, sizeof buff, fp)) { + if (buff[0] == '#') + continue; + buff[strlen(buff) - 1] = '\0'; + memset(vector, '\0', sizeof vector); + n = MakeArgs(buff, vector, VECSIZE(vector)); + if (n < 5) + continue; + if (strcmp(vector[0], name) == 0) { + CloseSecret(fp); + if (*vector[4] == '\0') + return 0; + strncpy(phone, vector[4], phonelen - 1); + phone[phonelen - 1] = '\0'; + return 1; /* Valid */ + } + } + CloseSecret(fp); + } + *phone = '\0'; + return 0; +} + +int +auth_Select(struct bundle *bundle, const char *name) +{ + FILE *fp; + int n; + char *vector[5]; + char buff[LINE_LEN]; + + if (*name == '\0') { + ipcp_Setup(&bundle->ncp.ipcp); + return 1; + } + + fp = OpenSecret(SECRETFILE); + if (fp != NULL) { + while (fgets(buff, sizeof buff, fp)) { + if (buff[0] == '#') + continue; + buff[strlen(buff) - 1] = '\0'; + memset(vector, '\0', sizeof vector); + n = MakeArgs(buff, vector, VECSIZE(vector)); + if (n < 2) + continue; + if (strcmp(vector[0], name) == 0) { + CloseSecret(fp); + if (n > 2 && *vector[2] && strcmp(vector[2], "*") && + !ipcp_UseHisaddr(bundle, vector[2], 1)) + return 0; + ipcp_Setup(&bundle->ncp.ipcp); + if (n > 3 && *vector[3] && strcmp(vector[3], "*")) + bundle_SetLabel(bundle, vector[3]); + return 1; /* Valid */ + } + } + CloseSecret(fp); + } + +#ifndef NOPASSWDAUTH + /* Let 'em in anyway - they must have been in the passwd file */ + ipcp_Setup(&bundle->ncp.ipcp); + return 1; +#else + /* Disappeared from ppp.secret ? */ + return 0; +#endif +} + +int +auth_Validate(struct bundle *bundle, const char *system, + const char *key, struct physical *physical) +{ + /* Used by PAP routines */ + + FILE *fp; + int n; + char *vector[5]; + char buff[LINE_LEN]; + + fp = OpenSecret(SECRETFILE); + if (fp != NULL) { + while (fgets(buff, sizeof buff, fp)) { + if (buff[0] == '#') + continue; + buff[strlen(buff) - 1] = 0; + memset(vector, '\0', sizeof vector); + n = MakeArgs(buff, vector, VECSIZE(vector)); + if (n < 2) + continue; + if (strcmp(vector[0], system) == 0) { + CloseSecret(fp); + return auth_CheckPasswd(vector[0], vector[1], key); + } + } + CloseSecret(fp); + } + +#ifndef NOPASSWDAUTH + if (Enabled(bundle, OPT_PASSWDAUTH)) + return auth_CheckPasswd(system, "*", key); +#endif + + return 0; /* Invalid */ +} + +char * +auth_GetSecret(struct bundle *bundle, const char *system, int len, + struct physical *physical) +{ + /* Used by CHAP routines */ + + FILE *fp; + int n; + char *vector[5]; + char buff[LINE_LEN]; + + fp = OpenSecret(SECRETFILE); + if (fp == NULL) + return (NULL); + + while (fgets(buff, sizeof buff, fp)) { + if (buff[0] == '#') + continue; + buff[strlen(buff) - 1] = 0; + memset(vector, '\0', sizeof vector); + n = MakeArgs(buff, vector, VECSIZE(vector)); + if (n < 2) + continue; + if (strlen(vector[0]) == len && strncmp(vector[0], system, len) == 0) { + CloseSecret(fp); + return vector[1]; + } + } + CloseSecret(fp); + return (NULL); /* Invalid */ +} + +static void +AuthTimeout(void *vauthp) +{ + struct authinfo *authp = (struct authinfo *)vauthp; + + timer_Stop(&authp->authtimer); + if (--authp->retry > 0) { + timer_Start(&authp->authtimer); + (*authp->ChallengeFunc)(authp, ++authp->id, authp->physical); + } +} + +void +auth_Init(struct authinfo *authinfo) +{ + memset(authinfo, '\0', sizeof(struct authinfo)); + authinfo->cfg.fsmretry = DEF_FSMRETRY; +} + +void +auth_StartChallenge(struct authinfo *authp, struct physical *physical, + void (*fn)(struct authinfo *, int, struct physical *)) +{ + authp->ChallengeFunc = fn; + authp->physical = physical; + timer_Stop(&authp->authtimer); + authp->authtimer.func = AuthTimeout; + authp->authtimer.name = "auth"; + authp->authtimer.load = authp->cfg.fsmretry * SECTICKS; + authp->authtimer.arg = (void *) authp; + authp->retry = 3; + authp->id = 1; + (*authp->ChallengeFunc)(authp, authp->id, physical); + timer_Start(&authp->authtimer); +} + +void +auth_StopTimer(struct authinfo *authp) +{ + timer_Stop(&authp->authtimer); + authp->physical = NULL; +} diff --git a/usr.sbin/ppp/auth.h b/usr.sbin/ppp/ppp/auth.h index aa430576da9..eb0d26a37e0 100644 --- a/usr.sbin/ppp/auth.h +++ b/usr.sbin/ppp/ppp/auth.h @@ -15,27 +15,35 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: auth.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * $Id: auth.h,v 1.1 1998/08/31 00:22:16 brian Exp $ * * TODO: */ -typedef enum { - VALID, - INVALID, - NOT_FOUND -} LOCAL_AUTH_VALID; +struct physical; +struct bundle; struct authinfo { - void (*ChallengeFunc) (int); + void (*ChallengeFunc)(struct authinfo *, int, struct physical *); struct pppTimer authtimer; int retry; int id; + struct physical *physical; + struct { + u_int fsmretry; + } cfg; }; -extern LOCAL_AUTH_VALID LocalAuthValidate(const char *, const char *, const char *); -extern void StopAuthTimer(struct authinfo *); -extern void StartAuthChallenge(struct authinfo *); -extern void LocalAuthInit(void); -extern int AuthValidate(const char *, const char *, const char *); -extern char *AuthGetSecret(const char *, const char *, int, int); +extern const char *Auth2Nam(u_short); + +extern void auth_Init(struct authinfo *); +extern void auth_StopTimer(struct authinfo *); +extern void auth_StartChallenge(struct authinfo *, struct physical *, + void (*fn)(struct authinfo *, int, + struct physical *)); +extern int auth_Validate(struct bundle *, const char *, const char *, + struct physical *); +extern char *auth_GetSecret(struct bundle *, const char *, int, + struct physical *); +extern int auth_SetPhoneList(const char *, char *, int); +extern int auth_Select(struct bundle *, const char *); diff --git a/usr.sbin/ppp/ppp/bundle.c b/usr.sbin/ppp/ppp/bundle.c new file mode 100644 index 00000000000..83228eaa2fc --- /dev/null +++ b/usr.sbin/ppp/ppp/bundle.c @@ -0,0 +1,1746 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: bundle.c,v 1.1 1998/08/31 00:22:16 brian Exp $ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#ifndef NOALIAS +#include <alias.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "id.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "lqr.h" +#include "hdlc.h" +#include "throughput.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "route.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" +#include "async.h" +#include "physical.h" +#include "modem.h" +#include "auth.h" +#include "lcpproto.h" +#include "chap.h" +#include "tun.h" +#include "prompt.h" +#include "chat.h" +#include "cbcp.h" +#include "datalink.h" +#include "ip.h" + +#define SCATTER_SEGMENTS 4 /* version, datalink, name, physical */ +#define SOCKET_OVERHEAD 100 /* additional buffer space for large */ + /* {recv,send}msg() calls */ + +static int bundle_RemainingIdleTime(struct bundle *); +static int bundle_RemainingAutoLoadTime(struct bundle *); + +static const char *PhaseNames[] = { + "Dead", "Establish", "Authenticate", "Network", "Terminate" +}; + +const char * +bundle_PhaseName(struct bundle *bundle) +{ + return bundle->phase <= PHASE_TERMINATE ? + PhaseNames[bundle->phase] : "unknown"; +} + +void +bundle_NewPhase(struct bundle *bundle, u_int new) +{ + if (new == bundle->phase) + return; + + if (new <= PHASE_TERMINATE) + log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); + + switch (new) { + case PHASE_DEAD: + log_DisplayPrompts(); + bundle->phase = new; + break; + + case PHASE_ESTABLISH: + bundle->phase = new; + break; + + case PHASE_AUTHENTICATE: + bundle->phase = new; + log_DisplayPrompts(); + break; + + case PHASE_NETWORK: + ipcp_Setup(&bundle->ncp.ipcp); + fsm_Up(&bundle->ncp.ipcp.fsm); + fsm_Open(&bundle->ncp.ipcp.fsm); + bundle->phase = new; + log_DisplayPrompts(); + break; + + case PHASE_TERMINATE: + bundle->phase = new; + mp_Down(&bundle->ncp.mp); + log_DisplayPrompts(); + break; + } +} + +static int +bundle_CleanInterface(const struct bundle *bundle) +{ + int s; + struct ifreq ifrq; + struct ifaliasreq ifra; + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "bundle_CleanInterface: socket(): %s\n", + strerror(errno)); + return (-1); + } + strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1); + ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; + while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { + memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); + strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); + ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; + ifra.ifra_addr = ifrq.ifr_addr; + if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { + if (ifra.ifra_addr.sa_family == AF_INET) + log_Printf(LogERROR, "Can't get dst for %s on %s !\n", + inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), + bundle->ifp.Name); + close(s); + return 0; + } + ifra.ifra_broadaddr = ifrq.ifr_dstaddr; + if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { + if (ifra.ifra_addr.sa_family == AF_INET) + log_Printf(LogERROR, "Can't delete %s address on %s !\n", + inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), + bundle->ifp.Name); + close(s); + return 0; + } + } + close(s); + + return 1; +} + +static void +bundle_LayerStart(void *v, struct fsm *fp) +{ + /* The given FSM is about to start up ! */ +} + + +static void +bundle_Notify(struct bundle *bundle, char c) +{ + if (bundle->notify.fd != -1) { + if (write(bundle->notify.fd, &c, 1) == 1) + log_Printf(LogPHASE, "Parent notified of success.\n"); + else + log_Printf(LogPHASE, "Failed to notify parent of success.\n"); + close(bundle->notify.fd); + bundle->notify.fd = -1; + } +} + +static void +bundle_ClearQueues(void *v) +{ + struct bundle *bundle = (struct bundle *)v; + struct datalink *dl; + + log_Printf(LogPHASE, "Clearing choked output queue\n"); + timer_Stop(&bundle->choked.timer); + + /* + * Emergency time: + * + * We've had a full queue for PACKET_DEL_SECS seconds without being + * able to get rid of any of the packets. We've probably given up + * on the redials at this point, and the queued data has almost + * definitely been timed out by the layer above. As this is preventing + * us from reading the TUN_NAME device (we don't want to buffer stuff + * indefinitely), we may as well nuke this data and start with a clean + * slate ! + * + * Unfortunately, this has the side effect of shafting any compression + * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). + */ + + ip_DeleteQueue(&bundle->ncp.ipcp); + mp_DeleteQueue(&bundle->ncp.mp); + for (dl = bundle->links; dl; dl = dl->next) + physical_DeleteQueue(dl->physical); +} + +static void +bundle_AutoLoadTimeout(void *v) +{ + struct bundle *bundle = (struct bundle *)v; + + if (bundle->autoload.comingup) { + log_Printf(LogPHASE, "autoload: Another link is required\n"); + /* bundle_Open() stops the timer */ + bundle_Open(bundle, NULL, PHYS_AUTO, 0); + } else { + struct datalink *dl, *last; + + timer_Stop(&bundle->autoload.timer); + for (last = NULL, dl = bundle->links; dl; dl = dl->next) + if (dl->physical->type == PHYS_AUTO && dl->state == DATALINK_OPEN) + last = dl; + + if (last) + datalink_Close(last, CLOSE_STAYDOWN); + } +} + +static void +bundle_StartAutoLoadTimer(struct bundle *bundle, int up) +{ + struct datalink *dl; + + timer_Stop(&bundle->autoload.timer); + + if (bundle->CleaningUp || bundle->phase != PHASE_NETWORK) { + dl = NULL; + bundle->autoload.running = 0; + } else if (up) { + for (dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_CLOSED && dl->physical->type == PHYS_AUTO) { + if (bundle->cfg.autoload.max.timeout) { + bundle->autoload.timer.func = bundle_AutoLoadTimeout; + bundle->autoload.timer.name = "autoload up"; + bundle->autoload.timer.load = + bundle->cfg.autoload.max.timeout * SECTICKS; + bundle->autoload.timer.arg = bundle; + timer_Start(&bundle->autoload.timer); + bundle->autoload.done = time(NULL) + bundle->cfg.autoload.max.timeout; + } else + bundle_AutoLoadTimeout(bundle); + break; + } + bundle->autoload.running = (dl || bundle->cfg.autoload.min.timeout) ? 1 : 0; + } else { + int nlinks; + struct datalink *adl; + + for (nlinks = 0, adl = NULL, dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_OPEN) { + if (dl->physical->type == PHYS_AUTO) + adl = dl; + if (++nlinks > 1 && adl) { + if (bundle->cfg.autoload.min.timeout) { + bundle->autoload.timer.func = bundle_AutoLoadTimeout; + bundle->autoload.timer.name = "autoload down"; + bundle->autoload.timer.load = + bundle->cfg.autoload.min.timeout * SECTICKS; + bundle->autoload.timer.arg = bundle; + timer_Start(&bundle->autoload.timer); + bundle->autoload.done = + time(NULL) + bundle->cfg.autoload.min.timeout; + } + break; + } + } + + bundle->autoload.running = 1; + } + + bundle->autoload.comingup = up ? 1 : 0; +} + +static void +bundle_StopAutoLoadTimer(struct bundle *bundle) +{ + timer_Stop(&bundle->autoload.timer); + bundle->autoload.done = 0; +} + +static int +bundle_RemainingAutoLoadTime(struct bundle *bundle) +{ + if (bundle->autoload.done) + return bundle->autoload.done - time(NULL); + return -1; +} + +static void +bundle_LinkAdded(struct bundle *bundle, struct datalink *dl) +{ + bundle->phys_type.all |= dl->physical->type; + if (dl->state == DATALINK_OPEN) + bundle->phys_type.open |= dl->physical->type; + + /* Note: We only re-add links that are DATALINK_OPEN */ + if (dl->physical->type == PHYS_AUTO && + bundle->autoload.timer.state == TIMER_STOPPED && + dl->state != DATALINK_OPEN && + bundle->phase == PHASE_NETWORK) + bundle->autoload.running = 1; + + if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) + != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) + /* We may need to start our idle timer */ + bundle_StartIdleTimer(bundle); +} + +void +bundle_LinksRemoved(struct bundle *bundle) +{ + struct datalink *dl; + + bundle->phys_type.all = bundle->phys_type.open = 0; + for (dl = bundle->links; dl; dl = dl->next) + bundle_LinkAdded(bundle, dl); + + if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) + == bundle->phys_type.open) + bundle_StopIdleTimer(bundle); +} + +static void +bundle_LayerUp(void *v, struct fsm *fp) +{ + /* + * The given fsm is now up + * If it's an LCP, adjust our phys_mode.open value. + * If it's an LCP set our mtu (if we're multilink, add up the link + * speeds and set the MRRU) and start our autoload timer. + * If it's an NCP, tell our -background parent to go away. + * If it's the first NCP, start the idle timer. + */ + struct bundle *bundle = (struct bundle *)v; + + if (fp->proto == PROTO_LCP) { + struct physical *p = link2physical(fp->link); + + bundle_LinkAdded(bundle, p->dl); + if (bundle->ncp.mp.active) { + struct datalink *dl; + + bundle->ifp.Speed = 0; + for (dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_OPEN) + bundle->ifp.Speed += modem_Speed(dl->physical); + tun_configure(bundle, bundle->ncp.mp.peer_mrru); + bundle->autoload.running = 1; + } else { + bundle->ifp.Speed = modem_Speed(p); + tun_configure(bundle, fsm2lcp(fp)->his_mru); + } + } else if (fp->proto == PROTO_IPCP) { + bundle_StartIdleTimer(bundle); + bundle_Notify(bundle, EX_NORMAL); + } +} + +static void +bundle_LayerDown(void *v, struct fsm *fp) +{ + /* + * The given FSM has been told to come down. + * If it's our last NCP, stop the idle timer. + * If it's an LCP, adjust our phys_type.open value and any timers. + * If it's an LCP and we're in multilink mode, adjust our tun + * speed and make sure our minimum sequence number is adjusted. + */ + + struct bundle *bundle = (struct bundle *)v; + + if (fp->proto == PROTO_IPCP) + bundle_StopIdleTimer(bundle); + else if (fp->proto == PROTO_LCP) { + bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ + if (bundle->ncp.mp.active) { + struct datalink *dl; + struct datalink *lost; + + bundle->ifp.Speed = 0; + lost = NULL; + for (dl = bundle->links; dl; dl = dl->next) + if (fp == &dl->physical->link.lcp.fsm) + lost = dl; + else if (dl->state == DATALINK_OPEN) + bundle->ifp.Speed += modem_Speed(dl->physical); + + if (bundle->ifp.Speed) + /* Don't configure down to a speed of 0 */ + tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru); + + if (lost) + mp_LinkLost(&bundle->ncp.mp, lost); + else + log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", + fp->link->name); + } + } +} + +static void +bundle_LayerFinish(void *v, struct fsm *fp) +{ + /* The given fsm is now down (fp cannot be NULL) + * + * If it's the last LCP, fsm_Down all NCPs + * If it's the last NCP, fsm_Close all LCPs + */ + + struct bundle *bundle = (struct bundle *)v; + struct datalink *dl; + + if (fp->proto == PROTO_IPCP) { + if (bundle_Phase(bundle) != PHASE_DEAD) + bundle_NewPhase(bundle, PHASE_TERMINATE); + for (dl = bundle->links; dl; dl = dl->next) + datalink_Close(dl, CLOSE_NORMAL); + fsm2initial(fp); + } else if (fp->proto == PROTO_LCP) { + int others_active; + + others_active = 0; + for (dl = bundle->links; dl; dl = dl->next) + if (fp != &dl->physical->link.lcp.fsm && + dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) + others_active++; + + if (!others_active) + fsm2initial(&bundle->ncp.ipcp.fsm); + } +} + +int +bundle_LinkIsUp(const struct bundle *bundle) +{ + return bundle->ncp.ipcp.fsm.state == ST_OPENED; +} + +void +bundle_Close(struct bundle *bundle, const char *name, int how) +{ + /* + * Please close the given datalink. + * If name == NULL or name is the last datalink, fsm_Close all NCPs + * (except our MP) + * If it isn't the last datalink, just Close that datalink. + */ + + struct datalink *dl, *this_dl; + int others_active; + + others_active = 0; + this_dl = NULL; + + for (dl = bundle->links; dl; dl = dl->next) { + if (name && !strcasecmp(name, dl->name)) + this_dl = dl; + if (name == NULL || this_dl == dl) { + switch (how) { + case CLOSE_LCP: + datalink_DontHangup(dl); + /* fall through */ + case CLOSE_STAYDOWN: + datalink_StayDown(dl); + break; + } + } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) + others_active++; + } + + if (name && this_dl == NULL) { + log_Printf(LogWARN, "%s: Invalid datalink name\n", name); + return; + } + + if (!others_active) { + bundle_StopIdleTimer(bundle); + bundle_StopAutoLoadTimer(bundle); + if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || + bundle->ncp.ipcp.fsm.state == ST_STARTING) + fsm_Close(&bundle->ncp.ipcp.fsm); + else { + fsm2initial(&bundle->ncp.ipcp.fsm); + for (dl = bundle->links; dl; dl = dl->next) + datalink_Close(dl, how); + } + } else if (this_dl && this_dl->state != DATALINK_CLOSED && + this_dl->state != DATALINK_HANGUP) + datalink_Close(this_dl, how); +} + +void +bundle_Down(struct bundle *bundle, int how) +{ + struct datalink *dl; + + for (dl = bundle->links; dl; dl = dl->next) + datalink_Down(dl, how); +} + +static int +bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + struct bundle *bundle = descriptor2bundle(d); + struct datalink *dl; + int result, want, queued, nlinks; + + result = 0; + + /* If there are aren't many packets queued, look for some more. */ + for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) + nlinks++; + + if (nlinks) { + queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp); + if (bundle->autoload.running) { + if (queued < bundle->cfg.autoload.max.packets) { + if (queued > bundle->cfg.autoload.min.packets) + bundle_StopAutoLoadTimer(bundle); + else if (bundle->autoload.timer.state != TIMER_RUNNING || + bundle->autoload.comingup) + bundle_StartAutoLoadTimer(bundle, 0); + } else if (bundle->autoload.timer.state != TIMER_RUNNING || + !bundle->autoload.comingup) + bundle_StartAutoLoadTimer(bundle, 1); + } + + if (r && (bundle->phase == PHASE_NETWORK || + bundle->phys_type.all & PHYS_AUTO)) { + /* enough surplus so that we can tell if we're getting swamped */ + want = bundle->cfg.autoload.max.packets + nlinks * 2; + /* but at least 20 packets ! */ + if (want < 20) + want = 20; + if (queued < want) { + /* Not enough - select() for more */ + if (bundle->choked.timer.state == TIMER_RUNNING) + timer_Stop(&bundle->choked.timer); /* Not needed any more */ + FD_SET(bundle->dev.fd, r); + if (*n < bundle->dev.fd + 1) + *n = bundle->dev.fd + 1; + log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); + result++; + } else if (bundle->choked.timer.state == TIMER_STOPPED) { + bundle->choked.timer.func = bundle_ClearQueues; + bundle->choked.timer.name = "output choke"; + bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; + bundle->choked.timer.arg = bundle; + timer_Start(&bundle->choked.timer); + } + } + } + + /* Which links need a select() ? */ + for (dl = bundle->links; dl; dl = dl->next) + result += descriptor_UpdateSet(&dl->desc, r, w, e, n); + + /* + * This *MUST* be called after the datalink UpdateSet()s as it + * might be ``holding'' one of the datalinks (death-row) and + * wants to be able to de-select() it from the descriptor set. + */ + result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); + + return result; +} + +static int +bundle_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct bundle *bundle = descriptor2bundle(d); + struct datalink *dl; + + for (dl = bundle->links; dl; dl = dl->next) + if (descriptor_IsSet(&dl->desc, fdset)) + return 1; + + if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) + return 1; + + return FD_ISSET(bundle->dev.fd, fdset); +} + +static void +bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, + const fd_set *fdset) +{ + struct datalink *dl; + + if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) + descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); + + for (dl = bundle->links; dl; dl = dl->next) + if (descriptor_IsSet(&dl->desc, fdset)) + descriptor_Read(&dl->desc, bundle, fdset); + + if (FD_ISSET(bundle->dev.fd, fdset)) { + struct tun_data tun; + int n, pri; + + /* something to read from tun */ + n = read(bundle->dev.fd, &tun, sizeof tun); + if (n < 0) { + log_Printf(LogWARN, "read from %s: %s\n", TUN_NAME, strerror(errno)); + return; + } + n -= sizeof tun - sizeof tun.data; + if (n <= 0) { + log_Printf(LogERROR, "read from %s: Only %d bytes read ?\n", TUN_NAME, n); + return; + } + if (!tun_check_header(tun, AF_INET)) + return; + + if (((struct ip *)tun.data)->ip_dst.s_addr == + bundle->ncp.ipcp.my_ip.s_addr) { + /* we've been asked to send something addressed *to* us :( */ + if (Enabled(bundle, OPT_LOOPBACK)) { + pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); + if (pri >= 0) { + struct mbuf *bp; + +#ifndef NOALIAS + if (bundle->AliasEnabled) { + PacketAliasIn(tun.data, sizeof tun.data); + n = ntohs(((struct ip *)tun.data)->ip_len); + } +#endif + bp = mbuf_Alloc(n, MB_IPIN); + memcpy(MBUF_CTOP(bp), tun.data, n); + ip_Input(bundle, bp); + log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); + } + return; + } else + log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); + } + + /* + * Process on-demand dialup. Output packets are queued within tunnel + * device until IPCP is opened. + */ + + if (bundle_Phase(bundle) == PHASE_DEAD) { + /* + * Note, we must be in AUTO mode :-/ otherwise our interface should + * *not* be UP and we can't receive data + */ + if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) + bundle_Open(bundle, NULL, PHYS_AUTO, 0); + else + /* + * Drop the packet. If we were to queue it, we'd just end up with + * a pile of timed-out data in our output queue by the time we get + * around to actually dialing. We'd also prematurely reach the + * threshold at which we stop select()ing to read() the tun + * device - breaking auto-dial. + */ + return; + } + + pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); + if (pri >= 0) { +#ifndef NOALIAS + if (bundle->AliasEnabled) { + PacketAliasOut(tun.data, sizeof tun.data); + n = ntohs(((struct ip *)tun.data)->ip_len); + } +#endif + ip_Enqueue(&bundle->ncp.ipcp, pri, tun.data, n); + } + } +} + +static int +bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle, + const fd_set *fdset) +{ + struct datalink *dl; + int result = 0; + + /* This is not actually necessary as struct mpserver doesn't Write() */ + if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) + descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); + + for (dl = bundle->links; dl; dl = dl->next) + if (descriptor_IsSet(&dl->desc, fdset)) + result += descriptor_Write(&dl->desc, bundle, fdset); + + return result; +} + +void +bundle_LockTun(struct bundle *bundle) +{ + FILE *lockfile; + char pidfile[MAXPATHLEN]; + + snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); + lockfile = ID0fopen(pidfile, "w"); + if (lockfile != NULL) { + fprintf(lockfile, "%d\n", (int)getpid()); + fclose(lockfile); + } +#ifndef RELEASE_CRUNCH + else + log_Printf(LogERROR, "Warning: Can't create %s: %s\n", + pidfile, strerror(errno)); +#endif +} + +static void +bundle_UnlockTun(struct bundle *bundle) +{ + char pidfile[MAXPATHLEN]; + + snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); + ID0unlink(pidfile); +} + +struct bundle * +bundle_Create(const char *prefix, int type, const char **argv) +{ + int s, enoentcount, err; + struct ifreq ifrq; + static struct bundle bundle; /* there can be only one */ + + if (bundle.ifp.Name != NULL) { /* Already allocated ! */ + log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); + return NULL; + } + + err = ENOENT; + enoentcount = 0; + for (bundle.unit = 0; ; bundle.unit++) { + snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", + prefix, bundle.unit); + bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); + if (bundle.dev.fd >= 0) + break; + else if (errno == ENXIO) { + err = errno; + break; + } else if (errno == ENOENT) { + if (++enoentcount > 2) + break; + } else + err = errno; + } + + if (bundle.dev.fd < 0) { + log_Printf(LogWARN, "No available tunnel devices found (%s).\n", + strerror(err)); + return NULL; + } + + log_SetTun(bundle.unit); + bundle.argv = argv; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); + close(bundle.dev.fd); + return NULL; + } + + bundle.ifp.Name = strrchr(bundle.dev.Name, '/'); + if (bundle.ifp.Name == NULL) + bundle.ifp.Name = bundle.dev.Name; + else + bundle.ifp.Name++; + + /* + * Now, bring up the interface. + */ + memset(&ifrq, '\0', sizeof ifrq); + strncpy(ifrq.ifr_name, bundle.ifp.Name, sizeof ifrq.ifr_name - 1); + ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; + if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + log_Printf(LogERROR, "bundle_Create: ioctl(SIOCGIFFLAGS): %s\n", + strerror(errno)); + close(s); + close(bundle.dev.fd); + bundle.ifp.Name = NULL; + return NULL; + } + ifrq.ifr_flags |= IFF_UP; + if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { + log_Printf(LogERROR, "bundle_Create: ioctl(SIOCSIFFLAGS): %s\n", + strerror(errno)); + close(s); + close(bundle.dev.fd); + bundle.ifp.Name = NULL; + return NULL; + } + + close(s); + + if ((bundle.ifp.Index = GetIfIndex(bundle.ifp.Name)) < 0) { + log_Printf(LogERROR, "Can't find interface index.\n"); + close(bundle.dev.fd); + bundle.ifp.Name = NULL; + return NULL; + } + log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifp.Name); + + bundle.ifp.Speed = 0; + + bundle.routing_seq = 0; + bundle.phase = PHASE_DEAD; + bundle.CleaningUp = 0; + bundle.AliasEnabled = 0; + + bundle.fsm.LayerStart = bundle_LayerStart; + bundle.fsm.LayerUp = bundle_LayerUp; + bundle.fsm.LayerDown = bundle_LayerDown; + bundle.fsm.LayerFinish = bundle_LayerFinish; + bundle.fsm.object = &bundle; + + bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; + *bundle.cfg.auth.name = '\0'; + *bundle.cfg.auth.key = '\0'; + bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | + OPT_THROUGHPUT | OPT_UTMP; + *bundle.cfg.label = '\0'; + bundle.cfg.mtu = DEF_MTU; + bundle.cfg.autoload.max.packets = 0; + bundle.cfg.autoload.max.timeout = 0; + bundle.cfg.autoload.min.packets = 0; + bundle.cfg.autoload.min.timeout = 0; + bundle.cfg.choked.timeout = CHOKED_TIMEOUT; + bundle.phys_type.all = type; + bundle.phys_type.open = 0; + + bundle.links = datalink_Create("deflink", &bundle, type); + if (bundle.links == NULL) { + log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); + close(bundle.dev.fd); + bundle.ifp.Name = NULL; + return NULL; + } + + bundle.desc.type = BUNDLE_DESCRIPTOR; + bundle.desc.UpdateSet = bundle_UpdateSet; + bundle.desc.IsSet = bundle_IsSet; + bundle.desc.Read = bundle_DescriptorRead; + bundle.desc.Write = bundle_DescriptorWrite; + + mp_Init(&bundle.ncp.mp, &bundle); + + /* Send over the first physical link by default */ + ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, + &bundle.fsm); + + memset(&bundle.filter, '\0', sizeof bundle.filter); + bundle.filter.in.fragok = bundle.filter.in.logok = 1; + bundle.filter.in.name = "IN"; + bundle.filter.out.fragok = bundle.filter.out.logok = 1; + bundle.filter.out.name = "OUT"; + bundle.filter.dial.name = "DIAL"; + bundle.filter.dial.logok = 1; + bundle.filter.alive.name = "ALIVE"; + bundle.filter.alive.logok = 1; + memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); + bundle.idle.done = 0; + bundle.notify.fd = -1; + memset(&bundle.autoload.timer, '\0', sizeof bundle.autoload.timer); + bundle.autoload.done = 0; + bundle.autoload.running = 0; + memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); + + /* Clean out any leftover crud */ + bundle_CleanInterface(&bundle); + + bundle_LockTun(&bundle); + + return &bundle; +} + +static void +bundle_DownInterface(struct bundle *bundle) +{ + struct ifreq ifrq; + int s; + + route_IfDelete(bundle, 1); + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); + return; + } + + memset(&ifrq, '\0', sizeof ifrq); + strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1); + ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; + if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", + strerror(errno)); + close(s); + return; + } + ifrq.ifr_flags &= ~IFF_UP; + if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { + log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", + strerror(errno)); + close(s); + return; + } + close(s); +} + +void +bundle_Destroy(struct bundle *bundle) +{ + struct datalink *dl; + + /* + * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), + * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting + * out under exceptional conditions such as a descriptor exception. + */ + timer_Stop(&bundle->idle.timer); + timer_Stop(&bundle->choked.timer); + timer_Stop(&bundle->autoload.timer); + mp_Down(&bundle->ncp.mp); + ipcp_CleanInterface(&bundle->ncp.ipcp); + bundle_DownInterface(bundle); + + /* Again, these are all DATALINK_CLOSED unless we're abending */ + dl = bundle->links; + while (dl) + dl = datalink_Destroy(dl); + + close(bundle->dev.fd); + bundle_UnlockTun(bundle); + + /* In case we never made PHASE_NETWORK */ + bundle_Notify(bundle, EX_ERRDEAD); + + bundle->ifp.Name = NULL; +} + +struct rtmsg { + struct rt_msghdr m_rtm; + char m_space[64]; +}; + +int +bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, + struct in_addr gateway, struct in_addr mask, int bang, int ssh) +{ + struct rtmsg rtmes; + int s, nb, wb; + char *cp; + const char *cmdstr; + struct sockaddr_in rtdata; + int result = 1; + + if (bang) + cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); + else + cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); + s = ID0socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) { + log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); + return result; + } + memset(&rtmes, '\0', sizeof rtmes); + rtmes.m_rtm.rtm_version = RTM_VERSION; + rtmes.m_rtm.rtm_type = cmd; + rtmes.m_rtm.rtm_addrs = RTA_DST; + rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; + rtmes.m_rtm.rtm_pid = getpid(); + rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; + + memset(&rtdata, '\0', sizeof rtdata); + rtdata.sin_len = sizeof rtdata; + rtdata.sin_family = AF_INET; + rtdata.sin_port = 0; + rtdata.sin_addr = dst; + + cp = rtmes.m_space; + memcpy(cp, &rtdata, rtdata.sin_len); + cp += rtdata.sin_len; + if (cmd == RTM_ADD) { + if (gateway.s_addr == INADDR_ANY) { + /* Add a route through the interface */ + struct sockaddr_dl dl; + const char *iname; + int ilen; + + iname = Index2Nam(bundle->ifp.Index); + ilen = strlen(iname); + dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; + dl.sdl_family = AF_LINK; + dl.sdl_index = bundle->ifp.Index; + dl.sdl_type = 0; + dl.sdl_nlen = ilen; + dl.sdl_alen = 0; + dl.sdl_slen = 0; + strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); + memcpy(cp, &dl, dl.sdl_len); + cp += dl.sdl_len; + rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; + } else { + rtdata.sin_addr = gateway; + memcpy(cp, &rtdata, rtdata.sin_len); + cp += rtdata.sin_len; + rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; + } + } + + if (dst.s_addr == INADDR_ANY) + mask.s_addr = INADDR_ANY; + + if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { + rtdata.sin_addr = mask; + memcpy(cp, &rtdata, rtdata.sin_len); + cp += rtdata.sin_len; + rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; + } + + nb = cp - (char *) &rtmes; + rtmes.m_rtm.rtm_msglen = nb; + wb = ID0write(s, &rtmes, nb); + if (wb < 0) { + log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); + log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); + log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); + log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); + log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); +failed: + if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || + (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { + if (!bang) { + log_Printf(LogWARN, "Add route failed: %s already exists\n", + inet_ntoa(dst)); + result = 0; /* Don't add to our dynamic list */ + } else { + rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; + if ((wb = ID0write(s, &rtmes, nb)) < 0) + goto failed; + } + } else if (cmd == RTM_DELETE && + (rtmes.m_rtm.rtm_errno == ESRCH || + (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { + if (!bang) + log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", + inet_ntoa(dst)); + } else if (rtmes.m_rtm.rtm_errno == 0) { + if (!ssh || errno != ENETUNREACH) + log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, + inet_ntoa(dst), strerror(errno)); + } else + log_Printf(LogWARN, "%s route failed: %s: %s\n", + cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); + } + log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", + wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); + close(s); + + return result; +} + +void +bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) +{ + /* + * Our datalink has closed. + * CleanDatalinks() (called from DoLoop()) will remove closed + * BACKGROUND and DIRECT links. + * If it's the last data link, enter phase DEAD. + * + * NOTE: dl may not be in our list (bundle_SendDatalink()) ! + */ + + struct datalink *odl; + int other_links; + + log_SetTtyCommandMode(dl); + + other_links = 0; + for (odl = bundle->links; odl; odl = odl->next) + if (odl != dl && odl->state != DATALINK_CLOSED) + other_links++; + + if (!other_links) { + if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ + bundle_DownInterface(bundle); + fsm2initial(&bundle->ncp.ipcp.fsm); + bundle_NewPhase(bundle, PHASE_DEAD); + bundle_StopIdleTimer(bundle); + bundle_StopAutoLoadTimer(bundle); + bundle->autoload.running = 0; + } else + bundle->autoload.running = 1; +} + +void +bundle_Open(struct bundle *bundle, const char *name, int mask, int force) +{ + /* + * Please open the given datalink, or all if name == NULL + */ + struct datalink *dl; + + timer_Stop(&bundle->autoload.timer); + for (dl = bundle->links; dl; dl = dl->next) + if (name == NULL || !strcasecmp(dl->name, name)) { + if ((mask & dl->physical->type) && + (dl->state == DATALINK_CLOSED || + (force && dl->state == DATALINK_OPENING && + dl->dial_timer.state == TIMER_RUNNING))) { + if (force) + timer_Stop(&dl->dial_timer); + datalink_Up(dl, 1, 1); + if (mask == PHYS_AUTO) + /* Only one AUTO link at a time (see the AutoLoad timer) */ + break; + } + if (name != NULL) + break; + } +} + +struct datalink * +bundle2datalink(struct bundle *bundle, const char *name) +{ + struct datalink *dl; + + if (name != NULL) { + for (dl = bundle->links; dl; dl = dl->next) + if (!strcasecmp(dl->name, name)) + return dl; + } else if (bundle->links && !bundle->links->next) + return bundle->links; + + return NULL; +} + +int +bundle_FillQueues(struct bundle *bundle) +{ + int total; + + if (bundle->ncp.mp.active) + total = mp_FillQueues(bundle); + else { + struct datalink *dl; + int add; + + for (total = 0, dl = bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_OPEN) { + add = link_QueueLen(&dl->physical->link); + if (add == 0 && dl->physical->out == NULL) + add = ip_FlushPacket(&dl->physical->link, bundle); + total += add; + } + } + + return total + ip_QueueLen(&bundle->ncp.ipcp); +} + +int +bundle_ShowLinks(struct cmdargs const *arg) +{ + struct datalink *dl; + + for (dl = arg->bundle->links; dl; dl = dl->next) { + prompt_Printf(arg->prompt, "Name: %s [%s, %s]", + dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); + if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN) + prompt_Printf(arg->prompt, " weight %d, %d bytes/sec", + dl->mp.weight, + dl->physical->link.throughput.OctetsPerSecond); + prompt_Printf(arg->prompt, "\n"); + } + + return 0; +} + +static const char * +optval(struct bundle *bundle, int bit) +{ + return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; +} + +int +bundle_ShowStatus(struct cmdargs const *arg) +{ + int remaining; + + prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); + prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); + prompt_Printf(arg->prompt, " Interface: %s @ %lubps\n", + arg->bundle->ifp.Name, arg->bundle->ifp.Speed); + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); + prompt_Printf(arg->prompt, " Auth name: %s\n", + arg->bundle->cfg.auth.name); + prompt_Printf(arg->prompt, " Auto Load: Up after %ds of >= %d packets\n", + arg->bundle->cfg.autoload.max.timeout, + arg->bundle->cfg.autoload.max.packets); + prompt_Printf(arg->prompt, " Down after %ds of <= %d" + " packets\n", arg->bundle->cfg.autoload.min.timeout, + arg->bundle->cfg.autoload.min.packets); + if (arg->bundle->autoload.timer.state == TIMER_RUNNING) + prompt_Printf(arg->prompt, " %ds remaining 'till " + "a link comes %s\n", + bundle_RemainingAutoLoadTime(arg->bundle), + arg->bundle->autoload.comingup ? "up" : "down"); + else + prompt_Printf(arg->prompt, " %srunning with %d" + " packets queued\n", arg->bundle->autoload.running ? + "" : "not ", ip_QueueLen(&arg->bundle->ncp.ipcp)); + + prompt_Printf(arg->prompt, " Choked Timer: %ds\n", + arg->bundle->cfg.choked.timeout); + prompt_Printf(arg->prompt, " Idle Timer: "); + if (arg->bundle->cfg.idle_timeout) { + prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout); + remaining = bundle_RemainingIdleTime(arg->bundle); + if (remaining != -1) + prompt_Printf(arg->prompt, " (%ds remaining)", remaining); + prompt_Printf(arg->prompt, "\n"); + } else + prompt_Printf(arg->prompt, "disabled\n"); + prompt_Printf(arg->prompt, " MTU: "); + if (arg->bundle->cfg.mtu) + prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); + else + prompt_Printf(arg->prompt, "unspecified\n"); + + prompt_Printf(arg->prompt, " Sticky Routes: %s\n", + optval(arg->bundle, OPT_SROUTES)); + prompt_Printf(arg->prompt, " ID check: %s\n", + optval(arg->bundle, OPT_IDCHECK)); + prompt_Printf(arg->prompt, " Loopback: %s\n", + optval(arg->bundle, OPT_LOOPBACK)); + prompt_Printf(arg->prompt, " PasswdAuth: %s\n", + optval(arg->bundle, OPT_PASSWDAUTH)); + prompt_Printf(arg->prompt, " Proxy: %s\n", + optval(arg->bundle, OPT_PROXY)); + prompt_Printf(arg->prompt, " Throughput: %s\n", + optval(arg->bundle, OPT_THROUGHPUT)); + prompt_Printf(arg->prompt, " Utmp Logging: %s\n", + optval(arg->bundle, OPT_UTMP)); + + return 0; +} + +static void +bundle_IdleTimeout(void *v) +{ + struct bundle *bundle = (struct bundle *)v; + + log_Printf(LogPHASE, "Idle timer expired.\n"); + bundle_StopIdleTimer(bundle); + bundle_Close(bundle, NULL, CLOSE_STAYDOWN); +} + +/* + * Start Idle timer. If timeout is reached, we call bundle_Close() to + * close LCP and link. + */ +void +bundle_StartIdleTimer(struct bundle *bundle) +{ + timer_Stop(&bundle->idle.timer); + if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != + bundle->phys_type.open && bundle->cfg.idle_timeout) { + bundle->idle.timer.func = bundle_IdleTimeout; + bundle->idle.timer.name = "idle"; + bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; + bundle->idle.timer.arg = bundle; + timer_Start(&bundle->idle.timer); + bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; + } +} + +void +bundle_SetIdleTimer(struct bundle *bundle, int value) +{ + bundle->cfg.idle_timeout = value; + if (bundle_LinkIsUp(bundle)) + bundle_StartIdleTimer(bundle); +} + +void +bundle_StopIdleTimer(struct bundle *bundle) +{ + timer_Stop(&bundle->idle.timer); + bundle->idle.done = 0; +} + +static int +bundle_RemainingIdleTime(struct bundle *bundle) +{ + if (bundle->idle.done) + return bundle->idle.done - time(NULL); + return -1; +} + +int +bundle_IsDead(struct bundle *bundle) +{ + return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); +} + +static struct datalink * +bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) +{ + struct datalink **dlp; + + for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) + if (*dlp == dl) { + *dlp = dl->next; + dl->next = NULL; + bundle_LinksRemoved(bundle); + return dl; + } + + return NULL; +} + +static void +bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) +{ + struct datalink **dlp = &bundle->links; + + while (*dlp) + dlp = &(*dlp)->next; + + *dlp = dl; + dl->next = NULL; + + bundle_LinkAdded(bundle, dl); +} + +void +bundle_CleanDatalinks(struct bundle *bundle) +{ + struct datalink **dlp = &bundle->links; + int found = 0; + + while (*dlp) + if ((*dlp)->state == DATALINK_CLOSED && + (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND)) { + *dlp = datalink_Destroy(*dlp); + found++; + } else + dlp = &(*dlp)->next; + + if (found) + bundle_LinksRemoved(bundle); +} + +int +bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, + const char *name) +{ + if (bundle2datalink(bundle, name)) { + log_Printf(LogWARN, "Clone: %s: name already exists\n", name); + return 0; + } + + bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); + return 1; +} + +void +bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) +{ + dl = bundle_DatalinkLinkout(bundle, dl); + if (dl) + datalink_Destroy(dl); +} + +void +bundle_SetLabel(struct bundle *bundle, const char *label) +{ + if (label) + strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); + else + *bundle->cfg.label = '\0'; +} + +const char * +bundle_GetLabel(struct bundle *bundle) +{ + return *bundle->cfg.label ? bundle->cfg.label : NULL; +} + +void +bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) +{ + char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)]; + struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; + struct msghdr msg; + struct iovec iov[SCATTER_SEGMENTS]; + struct datalink *dl; + int niov, link_fd, expect, f; + pid_t pid; + + log_Printf(LogPHASE, "Receiving datalink\n"); + + /* Create our scatter/gather array */ + niov = 1; + iov[0].iov_len = strlen(Version) + 1; + iov[0].iov_base = (char *)malloc(iov[0].iov_len); + if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov, 0) == -1) { + close(s); + return; + } + + pid = getpid(); + write(s, &pid, sizeof pid); + + for (f = expect = 0; f < niov; f++) + expect += iov[f].iov_len; + + /* Set up our message */ + cmsg->cmsg_len = sizeof cmsgbuf; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = 0; + + memset(&msg, '\0', sizeof msg); + msg.msg_name = (caddr_t)sun; + msg.msg_namelen = sizeof *sun; + msg.msg_iov = iov; + msg.msg_iovlen = niov; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof cmsgbuf; + + log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect); + f = expect + 100; + setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f); + if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) { + if (f == -1) + log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); + else + log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect); + while (niov--) + free(iov[niov].iov_base); + close(s); + return; + } + + write(s, "!", 1); /* ACK */ + close(s); + + if (cmsg->cmsg_type != SCM_RIGHTS) { + log_Printf(LogERROR, "Recvmsg: no descriptor received !\n"); + while (niov--) + free(iov[niov].iov_base); + return; + } + + /* We've successfully received an open file descriptor through our socket */ + log_Printf(LogDEBUG, "Receiving device descriptor\n"); + link_fd = *(int *)CMSG_DATA(cmsg); + + if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { + log_Printf(LogWARN, "Cannot receive datalink, incorrect version" + " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, + (char *)iov[0].iov_base, Version); + close(link_fd); + while (niov--) + free(iov[niov].iov_base); + return; + } + + niov = 1; + dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); + if (dl) { + bundle_DatalinkLinkin(bundle, dl); + datalink_AuthOk(dl); + } else + close(link_fd); + + free(iov[0].iov_base); +} + +void +bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) +{ + char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack; + struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; + struct msghdr msg; + struct iovec iov[SCATTER_SEGMENTS]; + int niov, link_fd, f, expect, newsid; + pid_t newpid; + + log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); + + bundle_LinkClosed(dl->bundle, dl); + bundle_DatalinkLinkout(dl->bundle, dl); + + /* Build our scatter/gather array */ + iov[0].iov_len = strlen(Version) + 1; + iov[0].iov_base = strdup(Version); + niov = 1; + + read(s, &newpid, sizeof newpid); + link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov, newpid); + + if (link_fd != -1) { + memset(&msg, '\0', sizeof msg); + + msg.msg_name = (caddr_t)sun; + msg.msg_namelen = sizeof *sun; + msg.msg_iov = iov; + msg.msg_iovlen = niov; + + cmsg->cmsg_len = sizeof cmsgbuf; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = link_fd; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof cmsgbuf; + + for (f = expect = 0; f < niov; f++) + expect += iov[f].iov_len; + + log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect); + + f = expect + SOCKET_OVERHEAD; + setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f); + if (sendmsg(s, &msg, 0) == -1) + log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno)); + /* We must get the ACK before closing the descriptor ! */ + read(s, &ack, 1); + + newsid = tcgetpgrp(link_fd) == getpgrp(); + close(link_fd); + if (newsid) + bundle_setsid(dl->bundle, 1); + } + close(s); + + while (niov--) + free(iov[niov].iov_base); +} + +int +bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, + const char *name) +{ + struct datalink *dl; + + if (!strcasecmp(ndl->name, name)) + return 1; + + for (dl = bundle->links; dl; dl = dl->next) + if (!strcasecmp(dl->name, name)) + return 0; + + datalink_Rename(ndl, name); + return 1; +} + +int +bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) +{ + int omode; + + omode = dl->physical->type; + if (omode == mode) + return 1; + + if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) + /* First auto link */ + if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { + log_Printf(LogWARN, "You must `set ifaddr' or `open' before" + " changing mode to %s\n", mode2Nam(mode)); + return 0; + } + + if (!datalink_SetMode(dl, mode)) + return 0; + + if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && + bundle->phase != PHASE_NETWORK) + /* First auto link, we need an interface */ + ipcp_InterfaceUp(&bundle->ncp.ipcp); + + /* Regenerate phys_type and adjust autoload & idle timers */ + bundle_LinksRemoved(bundle); + + if (omode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && + bundle->phase != PHASE_NETWORK) + /* No auto links left */ + ipcp_CleanInterface(&bundle->ncp.ipcp); + + return 1; +} + +void +bundle_setsid(struct bundle *bundle, int holdsession) +{ + /* + * Lose the current session. This means getting rid of our pid + * too so that the tty device will really go away, and any getty + * etc will be allowed to restart. + */ + pid_t pid, orig; + int fds[2]; + char done; + struct datalink *dl; + + orig = getpid(); + if (pipe(fds) == -1) { + log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); + return; + } + switch ((pid = fork())) { + case -1: + log_Printf(LogERROR, "fork: %s\n", strerror(errno)); + close(fds[0]); + close(fds[1]); + return; + case 0: + close(fds[0]); + read(fds[1], &done, 1); /* uu_locks are mine ! */ + close(fds[1]); + if (pipe(fds) == -1) { + log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); + return; + } + switch ((pid = fork())) { + case -1: + log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); + close(fds[0]); + close(fds[1]); + return; + case 0: + close(fds[0]); + bundle_LockTun(bundle); /* update pid */ + read(fds[1], &done, 1); /* uu_locks are mine ! */ + close(fds[1]); + setsid(); + log_Printf(LogPHASE, "%d -> %d: %s session control\n", + (int)orig, (int)getpid(), + holdsession ? "Passed" : "Dropped"); + timer_InitService(); + break; + default: + close(fds[1]); + /* Give away all our modem locks (to the final process) */ + for (dl = bundle->links; dl; dl = dl->next) + if (dl->state != DATALINK_CLOSED) + modem_ChangedPid(dl->physical, pid); + write(fds[0], "!", 1); /* done */ + close(fds[0]); + exit(0); + break; + } + break; + default: + close(fds[1]); + /* Give away all our modem locks (to the intermediate process) */ + for (dl = bundle->links; dl; dl = dl->next) + if (dl->state != DATALINK_CLOSED) + modem_ChangedPid(dl->physical, pid); + write(fds[0], "!", 1); /* done */ + close(fds[0]); + if (holdsession) { + int fd, status; + + timer_TermService(); + signal(SIGPIPE, SIG_DFL); + signal(SIGALRM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + for (fd = getdtablesize(); fd >= 0; fd--) + close(fd); + setuid(geteuid()); + /* + * Reap the intermediate process. As we're not exiting but the + * intermediate is, we don't want it to become defunct. + */ + waitpid(pid, &status, 0); + /* Tweak our process arguments.... */ + bundle->argv[0] = "session owner"; + bundle->argv[1] = NULL; + /* + * Hang around for a HUP. This should happen as soon as the + * ppp that we passed our ctty descriptor to closes it. + * NOTE: If this process dies, the passed descriptor becomes + * invalid and will give a select() error by setting one + * of the error fds, aborting the other ppp. We don't + * want that to happen ! + */ + pause(); + } + exit(0); + break; + } +} diff --git a/usr.sbin/ppp/ppp/bundle.h b/usr.sbin/ppp/ppp/bundle.h new file mode 100644 index 00000000000..3299f8bad6d --- /dev/null +++ b/usr.sbin/ppp/ppp/bundle.h @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: bundle.h,v 1.1 1998/08/31 00:22:16 brian Exp $ + */ + +#define PHASE_DEAD 0 /* Link is dead */ +#define PHASE_ESTABLISH 1 /* Establishing link */ +#define PHASE_AUTHENTICATE 2 /* Being authenticated */ +#define PHASE_NETWORK 3 /* We're alive ! */ +#define PHASE_TERMINATE 4 /* Terminating link */ + +/* cfg.opt bit settings */ +#define OPT_IDCHECK 0x01 +#define OPT_LOOPBACK 0x02 +#define OPT_PASSWDAUTH 0x04 +#define OPT_PROXY 0x08 +#define OPT_SROUTES 0x10 +#define OPT_THROUGHPUT 0x20 +#define OPT_UTMP 0x40 + +#define MAX_ENDDISC_CLASS 5 + +#define Enabled(b, o) ((b)->cfg.opt & (o)) + +struct sockaddr_un; +struct datalink; +struct physical; +struct link; +struct server; +struct prompt; + +struct bundle { + struct descriptor desc; /* really all our datalinks */ + int unit; /* The device/interface unit number */ + const char **argv; /* From main() */ + + struct { + char Name[20]; /* The /dev/XXXX name */ + int fd; /* The /dev/XXXX descriptor */ + } dev; + + struct { + u_long Speed; /* struct tuninfo speed */ + int Index; /* The interface index */ + char *Name; /* The interface name */ + } ifp; + + int routing_seq; /* The current routing sequence number */ + u_int phase; /* Curent phase */ + + struct { + int all; /* Union of all physical::type's */ + int open; /* Union of all open physical::type's */ + } phys_type; + + unsigned CleaningUp : 1; /* Going to exit.... */ + unsigned AliasEnabled : 1; /* Are we using libalias ? */ + + struct fsm_parent fsm; /* Our callback functions */ + struct datalink *links; /* Our data links */ + + struct { + int idle_timeout; /* NCP Idle timeout value */ + struct { + char name[50]; /* PAP/CHAP system name */ + char key[50]; /* PAP/CHAP key */ + } auth; + unsigned opt; /* Uses OPT_ bits from above */ + char label[50]; /* last thing `load'ed */ + u_short mtu; /* Interface mtu */ + + struct { /* We need/don't need another link when */ + struct { /* more/less than */ + int packets; /* this number of packets are queued for */ + int timeout; /* this number of seconds */ + } max, min; + } autoload; + + struct { + int timeout; /* How long to leave the output queue choked */ + } choked; + } cfg; + + struct { + struct ipcp ipcp; /* Our IPCP FSM */ + struct mp mp; /* Our MP */ + } ncp; + + struct { + struct filter in; /* incoming packet filter */ + struct filter out; /* outgoing packet filter */ + struct filter dial; /* dial-out packet filter */ + struct filter alive; /* keep-alive packet filter */ + } filter; + + struct { + struct pppTimer timer; /* timeout after cfg.idle_timeout */ + time_t done; + } idle; + + struct { + int fd; /* write status here */ + } notify; + + struct { + struct pppTimer timer; + time_t done; + unsigned running : 1; + unsigned comingup : 1; + } autoload; + + struct { + struct pppTimer timer; /* choked output queue timer */ + } choked; +}; + +#define descriptor2bundle(d) \ + ((d)->type == BUNDLE_DESCRIPTOR ? (struct bundle *)(d) : NULL) + +extern struct bundle *bundle_Create(const char *, int, const char **); +extern void bundle_Destroy(struct bundle *); +extern const char *bundle_PhaseName(struct bundle *); +#define bundle_Phase(b) ((b)->phase) +extern void bundle_NewPhase(struct bundle *, u_int); +extern void bundle_LinksRemoved(struct bundle *); +extern int bundle_LinkIsUp(const struct bundle *); +extern int bundle_SetRoute(struct bundle *, int, struct in_addr, + struct in_addr, struct in_addr, int, int); +extern void bundle_Close(struct bundle *, const char *, int); +extern void bundle_Down(struct bundle *, int); +extern void bundle_Open(struct bundle *, const char *, int, int); +extern void bundle_LinkClosed(struct bundle *, struct datalink *); + +extern int bundle_FillQueues(struct bundle *); +extern int bundle_ShowLinks(struct cmdargs const *); +extern int bundle_ShowStatus(struct cmdargs const *); +extern void bundle_StartIdleTimer(struct bundle *); +extern void bundle_SetIdleTimer(struct bundle *, int); +extern void bundle_StopIdleTimer(struct bundle *); +extern int bundle_IsDead(struct bundle *); +extern struct datalink *bundle2datalink(struct bundle *, const char *); + +extern void bundle_RegisterDescriptor(struct bundle *, struct descriptor *); +extern void bundle_UnRegisterDescriptor(struct bundle *, struct descriptor *); + +extern void bundle_SetTtyCommandMode(struct bundle *, struct datalink *); + +extern int bundle_DatalinkClone(struct bundle *, struct datalink *, + const char *); +extern void bundle_DatalinkRemove(struct bundle *, struct datalink *); +extern void bundle_CleanDatalinks(struct bundle *); +extern void bundle_SetLabel(struct bundle *, const char *); +extern const char *bundle_GetLabel(struct bundle *); +extern void bundle_SendDatalink(struct datalink *, int, struct sockaddr_un *); +extern void bundle_ReceiveDatalink(struct bundle *, int, struct sockaddr_un *); +extern int bundle_SetMode(struct bundle *, struct datalink *, int); +extern int bundle_RenameDatalink(struct bundle *, struct datalink *, + const char *); +extern void bundle_setsid(struct bundle *, int); +extern void bundle_LockTun(struct bundle *); diff --git a/usr.sbin/ppp/ppp/cbcp.c b/usr.sbin/ppp/ppp/cbcp.c new file mode 100644 index 00000000000..265e75f0696 --- /dev/null +++ b/usr.sbin/ppp/ppp/cbcp.c @@ -0,0 +1,691 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: cbcp.c,v 1.1 1998/08/31 00:22:16 brian Exp $ + */ + +#include <sys/types.h> + +#include <sys/un.h> + +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "log.h" +#include "timer.h" +#include "descriptor.h" +#include "lqr.h" +#include "mbuf.h" +#include "fsm.h" +#include "lcp.h" +#include "throughput.h" +#include "hdlc.h" +#include "ccp.h" +#include "link.h" +#include "async.h" +#include "physical.h" +#include "lcpproto.h" +#include "cbcp.h" +#include "mp.h" +#include "chat.h" +#include "auth.h" +#include "chap.h" +#include "datalink.h" + +void +cbcp_Init(struct cbcp *cbcp, struct physical *p) +{ + cbcp->required = 0; + cbcp->fsm.state = CBCP_CLOSED; + cbcp->fsm.id = 0; + cbcp->fsm.delay = 0; + *cbcp->fsm.phone = '\0'; + memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer); + cbcp->p = p; +} + +static void cbcp_SendReq(struct cbcp *); +static void cbcp_SendResponse(struct cbcp *); +static void cbcp_SendAck(struct cbcp *); + +static void +cbcp_Timeout(void *v) +{ + struct cbcp *cbcp = (struct cbcp *)v; + + timer_Stop(&cbcp->fsm.timer); + if (cbcp->fsm.restart) { + switch (cbcp->fsm.state) { + case CBCP_CLOSED: + case CBCP_STOPPED: + log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", + cbcp->p->dl->name); + break; + + case CBCP_REQSENT: + cbcp_SendReq(cbcp); + break; + case CBCP_RESPSENT: + cbcp_SendResponse(cbcp); + break; + case CBCP_ACKSENT: + cbcp_SendAck(cbcp); + break; + } + } else { + const char *missed; + + switch (cbcp->fsm.state) { + case CBCP_STOPPED: + missed = "REQ"; + break; + case CBCP_REQSENT: + missed = "RESPONSE"; + break; + case CBCP_RESPSENT: + missed = "ACK"; + break; + case CBCP_ACKSENT: + missed = "Terminate REQ"; + break; + default: + log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", + cbcp->p->dl->name); + missed = NULL; + break; + } + if (missed) + log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n", + cbcp->p->dl->name, missed); + datalink_CBCPFailed(cbcp->p->dl); + } +} + +static void +cbcp_StartTimer(struct cbcp *cbcp, int timeout) +{ + timer_Stop(&cbcp->fsm.timer); + cbcp->fsm.timer.func = cbcp_Timeout; + cbcp->fsm.timer.name = "cbcp"; + cbcp->fsm.timer.load = timeout * SECTICKS; + cbcp->fsm.timer.arg = cbcp; + timer_Start(&cbcp->fsm.timer); +} + +#define CBCP_CLOSED (0) /* Not in use */ +#define CBCP_STOPPED (1) /* Waiting for a REQ */ +#define CBCP_REQSENT (2) /* Waiting for a RESP */ +#define CBCP_RESPSENT (3) /* Waiting for an ACK */ +#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ + +static const char *cbcpname[] = { + "closed", "stopped", "req-sent", "resp-sent", "ack-sent" +}; + +static const char * +cbcpstate(int s) +{ + if (s < sizeof cbcpname / sizeof cbcpname[0]) + return cbcpname[s]; + return "???"; +} + +static void +cbcp_NewPhase(struct cbcp *cbcp, int new) +{ + if (cbcp->fsm.state != new) { + log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name, + cbcpstate(cbcp->fsm.state), cbcpstate(new)); + cbcp->fsm.state = new; + } +} + +struct cbcp_header { + u_char code; + u_char id; + u_int16_t length; /* Network byte order */ +}; + + +/* cbcp_header::code values */ +#define CBCP_REQ (1) +#define CBCP_RESPONSE (2) +#define CBCP_ACK (3) + +struct cbcp_data { + u_char type; + u_char length; + u_char delay; + char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */ +}; + +/* cbcp_data::type values */ +#define CBCP_NONUM (1) +#define CBCP_CLIENTNUM (2) +#define CBCP_SERVERNUM (3) +#define CBCP_LISTNUM (4) + +static void +cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data) +{ + struct cbcp_header *head; + struct mbuf *bp; + + bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCP); + head = (struct cbcp_header *)MBUF_CTOP(bp); + head->code = code; + head->id = cbcp->fsm.id; + head->length = htons(sizeof *head + data->length); + memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length); + log_DumpBp(LogDEBUG, "cbcp_Output", bp); + hdlc_Output(&cbcp->p->link, PRI_LINK, PROTO_CBCP, bp); +} + +static const char * +cbcp_data_Type(int type) +{ + static const char *types[] = { + "No callback", "User-spec", "Server-spec", "list" + }; + + if (type < 1 || type > sizeof types / sizeof types[0]) + return "???"; + return types[type-1]; +} + +struct cbcp_addr { + u_char type; + char addr[1]; /* Really ASCIIZ */ +}; + +/* cbcp_data::type values */ +#define CBCP_ADDR_PSTN (1) + +static void +cbcp_data_Show(struct cbcp_data *data) +{ + struct cbcp_addr *addr; + char *end; + + addr = (struct cbcp_addr *)data->addr_start; + end = (char *)data + data->length; + *end = '\0'; + + log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type)); + if ((char *)&data->delay < end) { + log_Printf(LogCBCP, " DELAY %d\n", data->delay); + while (addr->addr < end) { + if (addr->type == CBCP_ADDR_PSTN) + log_Printf(LogCBCP, " ADDR %s\n", addr->addr); + else + log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type); + addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); + } + } +} + +static void +cbcp_SendReq(struct cbcp *cbcp) +{ + struct cbcp_data data; + struct cbcp_addr *addr; + char list[sizeof cbcp->fsm.phone], *next; + int len, max; + + /* Only callees send REQs */ + + log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name, + cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); + data.type = cbcp->fsm.type; + data.delay = 0; + strncpy(list, cbcp->fsm.phone, sizeof list - 1); + list[sizeof list - 1] = '\0'; + + switch (data.type) { + case CBCP_CLIENTNUM: + addr = (struct cbcp_addr *)data.addr_start; + addr->type = CBCP_ADDR_PSTN; + *addr->addr = '\0'; + data.length = addr->addr - (char *)&data; + break; + + case CBCP_LISTNUM: + addr = (struct cbcp_addr *)data.addr_start; + for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { + len = strlen(next); + max = data.addr_start + sizeof data.addr_start - addr->addr - 1; + if (len <= max) { + addr->type = CBCP_ADDR_PSTN; + strcpy(addr->addr, next); + addr = (struct cbcp_addr *)((char *)addr + len + 2); + } else + log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n", + next); + } + data.length = (char *)addr - (char *)&data; + break; + + case CBCP_SERVERNUM: + data.length = data.addr_start - (char *)&data; + break; + + default: + data.length = 2; + break; + } + + cbcp_data_Show(&data); + cbcp_Output(cbcp, CBCP_REQ, &data); + cbcp->fsm.restart--; + cbcp_StartTimer(cbcp, cbcp->fsm.delay); + cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */ +} + +void +cbcp_Up(struct cbcp *cbcp) +{ + struct lcp *lcp = &cbcp->p->link.lcp; + + cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay; + if (*cbcp->p->dl->peer.authname == '\0' || + !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone, + sizeof cbcp->fsm.phone)) { + strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone, + sizeof cbcp->fsm.phone - 1); + cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; + } + + if (lcp->want_callback.opmask) { + if (*cbcp->fsm.phone == '\0') + cbcp->fsm.type = CBCP_NONUM; + else if (!strcmp(cbcp->fsm.phone, "*")) { + cbcp->fsm.type = CBCP_SERVERNUM; + *cbcp->fsm.phone = '\0'; + } else + cbcp->fsm.type = CBCP_CLIENTNUM; + cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */ + cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_REQs); + } else { + if (*cbcp->fsm.phone == '\0') + cbcp->fsm.type = CBCP_NONUM; + else if (!strcmp(cbcp->fsm.phone, "*")) { + cbcp->fsm.type = CBCP_CLIENTNUM; + *cbcp->fsm.phone = '\0'; + } else if (strchr(cbcp->fsm.phone, ',')) + cbcp->fsm.type = CBCP_LISTNUM; + else + cbcp->fsm.type = CBCP_SERVERNUM; + cbcp->fsm.restart = DEF_REQs; + cbcp_SendReq(cbcp); + } +} + +static int +cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data) +{ + /* + * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*) + * so that we (hopefully) agree with the peer + */ + struct cbcp_addr *addr; + + switch (data->type) { + case CBCP_NONUM: + if (cbcp->fsm.type == CBCP_NONUM) + return 1; + log_Printf(LogPHASE, "CBCP: server wants no callback !\n"); + return 0; + + case CBCP_CLIENTNUM: + if (cbcp->fsm.type == CBCP_CLIENTNUM) { + char *ptr; + + if (data->length > data->addr_start - (char *)data) { + /* + * The peer has given us an address type spec - make sure we + * understand ! + */ + addr = (struct cbcp_addr *)data->addr_start; + if (addr->type != CBCP_ADDR_PSTN) { + log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", + (int)addr->type); + return 0; + } + } + /* we accept the REQ even if the peer didn't specify an addr->type */ + ptr = strchr(cbcp->fsm.phone, ','); + if (ptr) + *ptr = '\0'; /* Just use the first number in our list */ + return 1; + } + log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); + return 0; + + case CBCP_SERVERNUM: + if (cbcp->fsm.type == CBCP_SERVERNUM) { + *cbcp->fsm.phone = '\0'; + return 1; + } + if (data->length > data->addr_start - (char *)data) { + /* + * This violates the spec, but if the peer has told us the + * number it wants to call back, take advantage of this fact + * and allow things to proceed if we've specified the same + * number + */ + addr = (struct cbcp_addr *)data->addr_start; + if (addr->type != CBCP_ADDR_PSTN) { + log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", + (int)addr->type); + return 0; + } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { + /* + * If the peer's insisting on deciding the number, make sure + * it's one of the ones in our list. If it is, let the peer + * think it's in control :-) + */ + char list[sizeof cbcp->fsm.phone], *next; + + strncpy(list, cbcp->fsm.phone, sizeof list - 1); + list[sizeof list - 1] = '\0'; + for (next = strtok(list, ","); next; next = strtok(NULL, ",")) + if (!strcmp(next, addr->addr)) { + cbcp->fsm.type = CBCP_SERVERNUM; + strcpy(cbcp->fsm.phone, next); + return 1; + } + } + } + log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); + return 0; + + case CBCP_LISTNUM: + if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { + /* + * Search through ``data''s addresses and see if cbcp->fsm.phone + * contains any of them + */ + char list[sizeof cbcp->fsm.phone], *next, *end; + + addr = (struct cbcp_addr *)data->addr_start; + end = (char *)data + data->length; + + while (addr->addr < end) { + if (addr->type == CBCP_ADDR_PSTN) { + strncpy(list, cbcp->fsm.phone, sizeof list - 1); + list[sizeof list - 1] = '\0'; + for (next = strtok(list, ","); next; next = strtok(NULL, ",")) + if (!strcmp(next, addr->addr)) { + cbcp->fsm.type = CBCP_LISTNUM; + strcpy(cbcp->fsm.phone, next); + return 1; + } + } else + log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", + (int)addr->type); + addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); + } + } + log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); + return 0; + } + + log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); + return 0; +} + +static void +cbcp_SendResponse(struct cbcp *cbcp) +{ + struct cbcp_data data; + struct cbcp_addr *addr; + + /* Only callers send RESPONSEs */ + + log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, + cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); + + data.type = cbcp->fsm.type; + data.delay = cbcp->fsm.delay; + addr = (struct cbcp_addr *)data.addr_start; + if (*cbcp->fsm.phone) { + addr->type = CBCP_ADDR_PSTN; + strcpy(addr->addr, cbcp->fsm.phone); + data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; + } else + data.length = data.addr_start - (char *)&data; + + cbcp_data_Show(&data); + cbcp_Output(cbcp, CBCP_RESPONSE, &data); + cbcp->fsm.restart--; + cbcp_StartTimer(cbcp, cbcp->fsm.delay); + cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ +} + +/* What to do after checking an incoming response */ +#define CBCP_ACTION_DOWN (0) +#define CBCP_ACTION_REQ (1) +#define CBCP_ACTION_ACK (2) + +static int +cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) +{ + /* + * We've received a RESPONSE (data). Check if it agrees with + * our REQ (cbcp->fsm) + */ + struct cbcp_addr *addr; + + addr = (struct cbcp_addr *)data->addr_start; + + if (data->type == cbcp->fsm.type) { + switch (cbcp->fsm.type) { + case CBCP_NONUM: + return CBCP_ACTION_ACK; + + case CBCP_CLIENTNUM: + if ((char *)data + data->length <= addr->addr) + log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); + else if (addr->type != CBCP_ADDR_PSTN) + log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", + addr->type); + else { + strcpy(cbcp->fsm.phone, addr->addr); + cbcp->fsm.delay = data->delay; + return CBCP_ACTION_ACK; + } + return CBCP_ACTION_DOWN; + + case CBCP_SERVERNUM: + cbcp->fsm.delay = data->delay; + return CBCP_ACTION_ACK; + + case CBCP_LISTNUM: + if ((char *)data + data->length <= addr->addr) + log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); + else if (addr->type != CBCP_ADDR_PSTN) + log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", + addr->type); + else { + char list[sizeof cbcp->fsm.phone], *next; + + strncpy(list, cbcp->fsm.phone, sizeof list - 1); + list[sizeof list - 1] = '\0'; + for (next = strtok(list, ","); next; next = strtok(NULL, ",")) + if (!strcmp(addr->addr, next)) { + strcpy(cbcp->fsm.phone, next); + cbcp->fsm.delay = data->delay; + return CBCP_ACTION_ACK; + } + log_Printf(LogPHASE, "CBCP: peer didn't respond with a " + "valid number !\n"); + } + return CBCP_ACTION_DOWN; + } + log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n", + (int)cbcp->fsm.type); + return CBCP_ACTION_DOWN; + } + log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); + return CBCP_ACTION_REQ; +} + +static void +cbcp_SendAck(struct cbcp *cbcp) +{ + struct cbcp_data data; + + /* Only callees send ACKs */ + + log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, + cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); + + data.type = cbcp->fsm.type; + data.delay = cbcp->fsm.delay; + data.length = data.addr_start - (char *)&data; + + cbcp_data_Show(&data); + cbcp_Output(cbcp, CBCP_ACK, &data); + cbcp->fsm.restart--; + cbcp_StartTimer(cbcp, cbcp->fsm.delay); + cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ +} + +void +cbcp_Input(struct physical *p, struct mbuf *bp) +{ + struct cbcp_header *head; + struct cbcp_data *data; + struct cbcp *cbcp = &p->dl->cbcp; + int len; + + len = mbuf_Length(bp); + if (len < sizeof(struct cbcp_header)) { + mbuf_Free(bp); + return; + } + head = (struct cbcp_header *)MBUF_CTOP(bp); + if (ntohs(head->length) != len) { + log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)" + " - ignored\n", head->code, ntohs(head->length), len); + mbuf_Free(bp); + return; + } + + /* XXX check the id */ + + bp->offset += sizeof(struct cbcp_header); + bp->cnt -= sizeof(struct cbcp_header); + data = (struct cbcp_data *)MBUF_CTOP(bp); + + switch (head->code) { + case CBCP_REQ: + log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", + p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); + cbcp_data_Show(data); + if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { + timer_Stop(&cbcp->fsm.timer); + if (cbcp_AdjustResponse(cbcp, data)) { + cbcp->fsm.restart = DEF_REQs; + cbcp_SendResponse(cbcp); + } else + datalink_CBCPFailed(cbcp->p->dl); + } else + log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); + break; + + case CBCP_RESPONSE: + log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", + p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); + cbcp_data_Show(data); + if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { + timer_Stop(&cbcp->fsm.timer); + switch (cbcp_CheckResponse(cbcp, data)) { + case CBCP_ACTION_REQ: + cbcp_SendReq(cbcp); + break; + + case CBCP_ACTION_ACK: + cbcp->fsm.restart = DEF_REQs; + cbcp_SendAck(cbcp); + if (cbcp->fsm.type == CBCP_NONUM) { + /* + * Don't change state in case the peer doesn't get our ACK, + * just bring the layer up. + */ + timer_Stop(&cbcp->fsm.timer); + datalink_NCPUp(cbcp->p->dl); + } + break; + + default: + datalink_CBCPFailed(cbcp->p->dl); + break; + } + } else + log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); + break; + + case CBCP_ACK: + log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", + p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); + cbcp_data_Show(data); + if (cbcp->fsm.state == CBCP_RESPSENT) { + timer_Stop(&cbcp->fsm.timer); + datalink_CBCPComplete(cbcp->p->dl); + log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); + } else + log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); + break; + + default: + log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n", + head->code, len); + break; + } + + mbuf_Free(bp); +} + +void +cbcp_Down(struct cbcp *cbcp) +{ + timer_Stop(&cbcp->fsm.timer); + cbcp_NewPhase(cbcp, CBCP_CLOSED); + cbcp->required = 0; +} + +void +cbcp_ReceiveTerminateReq(struct physical *p) +{ + if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { + /* Don't change our state in case the peer doesn't get the ACK */ + p->dl->cbcp.required = 1; + log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, + p->dl->cbcp.fsm.phone); + } else + cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); +} diff --git a/usr.sbin/ppp/ppp/cbcp.h b/usr.sbin/ppp/ppp/cbcp.h new file mode 100644 index 00000000000..16f25f4b0da --- /dev/null +++ b/usr.sbin/ppp/ppp/cbcp.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: cbcp.h,v 1.1 1998/08/31 00:22:17 brian Exp $ + */ + +struct mbuf; +struct physical; +struct datalink; + +/* fsm states */ +#define CBCP_CLOSED (0) /* Not in use */ +#define CBCP_STOPPED (1) /* Waiting for a REQ */ +#define CBCP_REQSENT (2) /* Waiting for a RESP */ +#define CBCP_RESPSENT (3) /* Waiting for an ACK */ +#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ + +struct cbcpcfg { + u_char delay; + char phone[SCRIPT_LEN]; + long fsmretry; +}; + +struct cbcp { + unsigned required : 1; /* Are we gonna call back ? */ + struct physical *p; /* On this physical link */ + struct { + u_char type; /* cbcp_data::type (none/me/him/list) */ + u_char delay; /* How long to delay */ + char phone[SCRIPT_LEN]; /* What to dial */ + + int state; /* Our FSM state */ + u_char id; /* Our FSM ID */ + u_char restart; /* FSM Send again ? */ + struct pppTimer timer; /* Resend last option */ + } fsm; +}; + +extern void cbcp_Init(struct cbcp *, struct physical *); +extern void cbcp_Up(struct cbcp *); +extern void cbcp_Input(struct physical *, struct mbuf *); +extern void cbcp_Down(struct cbcp *); +extern void cbcp_ReceiveTerminateReq(struct physical *); diff --git a/usr.sbin/ppp/ppp/ccp.c b/usr.sbin/ppp/ppp/ccp.c new file mode 100644 index 00000000000..0405ca3fb25 --- /dev/null +++ b/usr.sbin/ppp/ppp/ccp.c @@ -0,0 +1,611 @@ +/* + * PPP Compression Control Protocol (CCP) Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ccp.c,v 1.1 1998/08/31 00:22:17 brian Exp $ + * + * TODO: + * o Support other compression protocols + */ +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "lcpproto.h" +#include "lcp.h" +#include "ccp.h" +#include "pred.h" +#include "deflate.h" +#include "throughput.h" +#include "iplist.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "prompt.h" +#include "link.h" +#include "mp.h" +#include "async.h" +#include "physical.h" +#include "bundle.h" + +static void CcpSendConfigReq(struct fsm *); +static void CcpSentTerminateReq(struct fsm *); +static void CcpSendTerminateAck(struct fsm *, u_char); +static void CcpDecodeConfig(struct fsm *, u_char *, int, int, + struct fsm_decode *); +static void CcpLayerStart(struct fsm *); +static void CcpLayerFinish(struct fsm *); +static int CcpLayerUp(struct fsm *); +static void CcpLayerDown(struct fsm *); +static void CcpInitRestartCounter(struct fsm *); +static void CcpRecvResetReq(struct fsm *); +static void CcpRecvResetAck(struct fsm *, u_char); + +static struct fsm_callbacks ccp_Callbacks = { + CcpLayerUp, + CcpLayerDown, + CcpLayerStart, + CcpLayerFinish, + CcpInitRestartCounter, + CcpSendConfigReq, + CcpSentTerminateReq, + CcpSendTerminateAck, + CcpDecodeConfig, + CcpRecvResetReq, + CcpRecvResetAck +}; + +static const char *ccp_TimerNames[] = + {"CCP restart", "CCP openmode", "CCP stopped"}; + +static char const *cftypes[] = { + /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ + "OUI", /* 0: OUI */ + "PRED1", /* 1: Predictor type 1 */ + "PRED2", /* 2: Predictor type 2 */ + "PUDDLE", /* 3: Puddle Jumber */ + "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", + "HWPPC", /* 16: Hewlett-Packard PPC */ + "STAC", /* 17: Stac Electronics LZS (rfc1974) */ + "MPPC", /* 18: Microsoft PPC (rfc2118) */ + "GAND", /* 19: Gandalf FZA (rfc1993) */ + "V42BIS", /* 20: ARG->DATA.42bis compression */ + "BSD", /* 21: BSD LZW Compress */ + "???", + "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ + "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ + /* 24: Deflate (according to pppd-2.3.*) */ + "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ + "DEFLATE", /* 26: Deflate (rfc1979) */ +}; + +#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) + +static const char * +protoname(int proto) +{ + if (proto < 0 || proto > NCFTYPES) + return "none"; + return cftypes[proto]; +} + +/* We support these algorithms, and Req them in the given order */ +static const struct ccp_algorithm *algorithm[] = { + &DeflateAlgorithm, + &Pred1Algorithm, + &PppdDeflateAlgorithm +}; + +#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) + +int +ccp_ReportStatus(struct cmdargs const *arg) +{ + struct link *l; + struct ccp *ccp; + + l = command_ChooseLink(arg); + ccp = &l->ccp; + + prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, + State2Nam(ccp->fsm.state)); + prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", + protoname(ccp->my_proto), protoname(ccp->his_proto)); + prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", + ccp->uncompout, ccp->compout, + ccp->compin, ccp->uncompin); + + prompt_Printf(arg->prompt, "\n Defaults: "); + prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry); + prompt_Printf(arg->prompt, " deflate windows: "); + prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); + prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); + prompt_Printf(arg->prompt, " DEFLATE: %s\n", + command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); + prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", + command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); + prompt_Printf(arg->prompt, " DEFLATE24: %s\n", + command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); + return 0; +} + +void +ccp_SetupCallbacks(struct ccp *ccp) +{ + ccp->fsm.fn = &ccp_Callbacks; + ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; + ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; + ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; +} + +void +ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, + const struct fsm_parent *parent) +{ + /* Initialise ourselves */ + + fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP, + bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); + + ccp->cfg.deflate.in.winsize = 0; + ccp->cfg.deflate.out.winsize = 15; + ccp->cfg.fsmretry = DEF_FSMRETRY; + ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; + ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; + ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; + + ccp_Setup(ccp); +} + +void +ccp_Setup(struct ccp *ccp) +{ + /* Set ourselves up for a startup */ + ccp->fsm.open_mode = 0; + ccp->fsm.maxconfig = 10; + ccp->his_proto = ccp->my_proto = -1; + ccp->reset_sent = ccp->last_reset = -1; + ccp->in.algorithm = ccp->out.algorithm = -1; + ccp->in.state = ccp->out.state = NULL; + ccp->in.opt.id = -1; + ccp->out.opt = NULL; + ccp->his_reject = ccp->my_reject = 0; + ccp->uncompout = ccp->compout = 0; + ccp->uncompin = ccp->compin = 0; +} + +static void +CcpInitRestartCounter(struct fsm *fp) +{ + /* Set fsm timer load */ + struct ccp *ccp = fsm2ccp(fp); + + fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS; + fp->restart = DEF_REQs; +} + +static void +CcpSendConfigReq(struct fsm *fp) +{ + /* Send config REQ please */ + struct ccp *ccp = fsm2ccp(fp); + struct ccp_opt **o; + u_char *cp, buff[100]; + int f, alloc; + + cp = buff; + o = &ccp->out.opt; + alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; + ccp->my_proto = -1; + ccp->out.algorithm = -1; + for (f = 0; f < NALGORITHMS; f++) + if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && + !REJECTED(ccp, algorithm[f]->id)) { + + if (!alloc) + for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) + if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) + break; + + if (alloc || *o == NULL) { + *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); + (*o)->val.id = algorithm[f]->id; + (*o)->val.len = 2; + (*o)->next = NULL; + (*o)->algorithm = f; + (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); + } + + if (cp + (*o)->val.len > buff + sizeof buff) { + log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); + break; + } + memcpy(cp, &(*o)->val, (*o)->val.len); + cp += (*o)->val.len; + + ccp->my_proto = (*o)->val.id; + ccp->out.algorithm = f; + + if (alloc) + o = &(*o)->next; + } + + fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); +} + +void +ccp_SendResetReq(struct fsm *fp) +{ + /* We can't read our input - ask peer to reset */ + struct ccp *ccp = fsm2ccp(fp); + + ccp->reset_sent = fp->reqid; + ccp->last_reset = -1; + fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0); +} + +static void +CcpSentTerminateReq(struct fsm *fp) +{ + /* Term REQ just sent by FSM */ +} + +static void +CcpSendTerminateAck(struct fsm *fp, u_char id) +{ + /* Send Term ACK please */ + fsm_Output(fp, CODE_TERMACK, id, NULL, 0); +} + +static void +CcpRecvResetReq(struct fsm *fp) +{ + /* Got a reset REQ, reset outgoing dictionary */ + struct ccp *ccp = fsm2ccp(fp); + if (ccp->out.state != NULL) + (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); +} + +static void +CcpLayerStart(struct fsm *fp) +{ + /* We're about to start up ! */ + log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); +} + +static void +CcpLayerDown(struct fsm *fp) +{ + /* About to come down */ + struct ccp *ccp = fsm2ccp(fp); + struct ccp_opt *next; + + log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); + if (ccp->in.state != NULL) { + (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); + ccp->in.state = NULL; + ccp->in.algorithm = -1; + } + if (ccp->out.state != NULL) { + (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); + ccp->out.state = NULL; + ccp->out.algorithm = -1; + } + ccp->his_reject = ccp->my_reject = 0; + + while (ccp->out.opt) { + next = ccp->out.opt->next; + free(ccp->out.opt); + ccp->out.opt = next; + } + ccp_Setup(ccp); +} + +static void +CcpLayerFinish(struct fsm *fp) +{ + /* We're now down */ + log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); +} + +/* + * Called when CCP has reached the OPEN state + */ +static int +CcpLayerUp(struct fsm *fp) +{ + /* We're now up */ + struct ccp *ccp = fsm2ccp(fp); + log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); + if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && + ccp->in.algorithm < NALGORITHMS) { + ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); + if (ccp->in.state == NULL) { + log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", + fp->link->name, protoname(ccp->his_proto)); + ccp->his_proto = ccp->my_proto = -1; + fsm_Close(fp); + } + } + + if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && + ccp->out.algorithm < NALGORITHMS) { + ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) + (&ccp->out.opt->val); + if (ccp->out.state == NULL) { + log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", + fp->link->name, protoname(ccp->my_proto)); + ccp->his_proto = ccp->my_proto = -1; + fsm_Close(fp); + } + } + + log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", + fp->link->name, protoname(ccp->my_proto), ccp->my_proto, + protoname(ccp->his_proto), ccp->his_proto); + return 1; +} + +static void +CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, + struct fsm_decode *dec) +{ + /* Deal with incoming data */ + struct ccp *ccp = fsm2ccp(fp); + int type, length; + int f; + const char *end; + + while (plen >= sizeof(struct fsmconfig)) { + type = *cp; + length = cp[1]; + + if (length == 0) { + log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); + break; + } + + if (length > sizeof(struct lcp_opt)) { + length = sizeof(struct lcp_opt); + log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", + fp->link->name, length); + } + + for (f = NALGORITHMS-1; f > -1; f--) + if (algorithm[f]->id == type) + break; + + end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); + if (end == NULL) + end = ""; + + if (type < NCFTYPES) + log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); + else + log_Printf(LogCCP, " ???[%d] %s\n", length, end); + + if (f == -1) { + /* Don't understand that :-( */ + if (mode_type == MODE_REQ) { + ccp->my_reject |= (1 << type); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } + } else { + struct ccp_opt *o; + + switch (mode_type) { + case MODE_REQ: + if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && + ccp->in.algorithm == -1) { + memcpy(&ccp->in.opt, cp, length); + switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { + case MODE_REJ: + memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); + dec->rejend += ccp->in.opt.len; + break; + case MODE_NAK: + memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); + dec->nakend += ccp->in.opt.len; + break; + case MODE_ACK: + memcpy(dec->ackend, cp, length); + dec->ackend += length; + ccp->his_proto = type; + ccp->in.algorithm = f; /* This one'll do :-) */ + break; + } + } else { + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } + break; + case MODE_NAK: + for (o = ccp->out.opt; o != NULL; o = o->next) + if (o->val.id == cp[0]) + break; + if (o == NULL) + log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", + fp->link->name); + else { + memcpy(&o->val, cp, length); + if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) + ccp->my_proto = algorithm[f]->id; + else { + ccp->his_reject |= (1 << type); + ccp->my_proto = -1; + } + } + break; + case MODE_REJ: + ccp->his_reject |= (1 << type); + ccp->my_proto = -1; + break; + } + } + + plen -= cp[1]; + cp += cp[1]; + } + + if (mode_type != MODE_NOP) { + if (dec->rejend != dec->rej) { + /* rejects are preferred */ + dec->ackend = dec->ack; + dec->nakend = dec->nak; + if (ccp->in.state == NULL) { + ccp->his_proto = -1; + ccp->in.algorithm = -1; + } + } else if (dec->nakend != dec->nak) { + /* then NAKs */ + dec->ackend = dec->ack; + if (ccp->in.state == NULL) { + ccp->his_proto = -1; + ccp->in.algorithm = -1; + } + } + } +} + +void +ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) +{ + /* Got PROTO_CCP from link */ + if (bundle_Phase(bundle) == PHASE_NETWORK) + fsm_Input(&ccp->fsm, bp); + else { + if (bundle_Phase(bundle) < PHASE_NETWORK) + log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", + ccp->fsm.link->name, bundle_PhaseName(bundle)); + mbuf_Free(bp); + } +} + +static void +CcpRecvResetAck(struct fsm *fp, u_char id) +{ + /* Got a reset ACK, reset incoming dictionary */ + struct ccp *ccp = fsm2ccp(fp); + + if (ccp->reset_sent != -1) { + if (id != ccp->reset_sent) { + log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" + " ignored\n", fp->link->name, id, ccp->reset_sent); + return; + } + /* Whaddaya know - a correct reset ack */ + } else if (id == ccp->last_reset) + log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", + fp->link->name); + else { + log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", + fp->link->name, id); + return; + } + + ccp->last_reset = ccp->reset_sent; + ccp->reset_sent = -1; + if (ccp->in.state != NULL) + (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); +} + +int +ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, + struct mbuf *m) +{ + /* + * Compress outgoing data. It's already deemed to be suitable Network + * Layer data. + */ + if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL) + return (*algorithm[ccp->out.algorithm]->o.Write) + (ccp->out.state, ccp, l, pri, proto, m); + return 0; +} + +struct mbuf * +ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) +{ + /* + * If proto isn't PROTO_[I]COMPD, we still want to pass it to the + * decompression routines so that the dictionary's updated + */ + if (ccp->fsm.state == ST_OPENED) { + if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { + /* Decompress incoming data */ + if (ccp->reset_sent != -1) + /* Send another REQ and put the packet in the bit bucket */ + fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); + else if (ccp->in.state != NULL) + return (*algorithm[ccp->in.algorithm]->i.Read) + (ccp->in.state, ccp, proto, bp); + mbuf_Free(bp); + bp = NULL; + } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL) + /* Add incoming Network Layer traffic to our dictionary */ + (*algorithm[ccp->in.algorithm]->i.DictSetup) + (ccp->in.state, ccp, *proto, bp); + } + + return bp; +} + +u_short +ccp_Proto(struct ccp *ccp) +{ + return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? + PROTO_COMPD : PROTO_ICOMPD; +} + +int +ccp_SetOpenMode(struct ccp *ccp) +{ + int f; + + for (f = 0; f < CCP_NEG_TOTAL; f++) + if (IsEnabled(ccp->cfg.neg[f])) { + ccp->fsm.open_mode = 0; + return 1; + } + + ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ + + for (f = 0; f < CCP_NEG_TOTAL; f++) + if (IsAccepted(ccp->cfg.neg[f])) + return 1; + + return 0; /* No CCP at all */ +} diff --git a/usr.sbin/ppp/ppp/ccp.h b/usr.sbin/ppp/ppp/ccp.h new file mode 100644 index 00000000000..3ebefefc68d --- /dev/null +++ b/usr.sbin/ppp/ppp/ccp.h @@ -0,0 +1,128 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ccp.h,v 1.1 1998/08/31 00:22:17 brian Exp $ + * + * TODO: + */ + +#define CCP_MAXCODE CODE_RESETACK + +#define TY_OUI 0 /* OUI */ +#define TY_PRED1 1 /* Predictor type 1 */ +#define TY_PRED2 2 /* Predictor type 2 */ +#define TY_PUDDLE 3 /* Puddle Jumper */ +#define TY_HWPPC 16 /* Hewlett-Packard PPC */ +#define TY_STAC 17 /* Stac Electronics LZS */ +#define TY_MSPPC 18 /* Microsoft PPC */ +#define TY_GAND 19 /* Gandalf FZA */ +#define TY_V42BIS 20 /* V.42bis compression */ +#define TY_BSD 21 /* BSD LZW Compress */ +#define TY_PPPD_DEFLATE 24 /* Deflate (gzip) - (mis) numbered by pppd */ +#define TY_DEFLATE 26 /* Deflate (gzip) - rfc 1979 */ + +#define CCP_NEG_DEFLATE 0 +#define CCP_NEG_PRED1 1 +#define CCP_NEG_DEFLATE24 2 +#define CCP_NEG_TOTAL 3 + +struct mbuf; +struct link; + +struct ccp_config { + struct { + struct { + int winsize; + } in, out; + } deflate; + u_int fsmretry; /* FSM retry frequency */ + unsigned neg[CCP_NEG_TOTAL]; +}; + +struct ccp_opt { + struct ccp_opt *next; + int algorithm; + struct lcp_opt val; +}; + +struct ccp { + struct fsm fsm; /* The finite state machine */ + + int his_proto; /* peer's compression protocol */ + int my_proto; /* our compression protocol */ + + int reset_sent; /* If != -1, ignore compressed 'till ack */ + int last_reset; /* We can receive more (dups) w/ this id */ + + struct { + int algorithm; /* Algorithm in use */ + void *state; /* Returned by implementations Init() */ + struct lcp_opt opt; /* Set by implementations OptInit() */ + } in; + + struct { + int algorithm; /* Algorithm in use */ + void *state; /* Returned by implementations Init() */ + struct ccp_opt *opt; /* Set by implementations OptInit() */ + } out; + + u_int32_t his_reject; /* Request codes rejected by peer */ + u_int32_t my_reject; /* Request codes I have rejected */ + + u_long uncompout, compout; /* Outgoing bytes before/after compression */ + u_long uncompin, compin; /* Incoming bytes after/before decompression */ + + struct ccp_config cfg; +}; + +#define fsm2ccp(fp) (fp->proto == PROTO_CCP ? (struct ccp *)fp : NULL) + +struct ccp_algorithm { + int id; + int Neg; /* ccp_config neg array item */ + const char *(*Disp)(struct lcp_opt *); /* Use result immediately ! */ + struct { + int (*Set)(struct lcp_opt *, const struct ccp_config *); + void *(*Init)(struct lcp_opt *); + void (*Term)(void *); + void (*Reset)(void *); + struct mbuf *(*Read)(void *, struct ccp *, u_short *, struct mbuf *); + void (*DictSetup)(void *, struct ccp *, u_short, struct mbuf *); + } i; + struct { + void (*OptInit)(struct lcp_opt *, const struct ccp_config *); + int (*Set)(struct lcp_opt *); + void *(*Init)(struct lcp_opt *); + void (*Term)(void *); + void (*Reset)(void *); + int (*Write)(void *, struct ccp *, struct link *, int, u_short, + struct mbuf *); + } o; +}; + +extern void ccp_Init(struct ccp *, struct bundle *, struct link *, + const struct fsm_parent *); +extern void ccp_Setup(struct ccp *); + +extern void ccp_SendResetReq(struct fsm *); +extern void ccp_Input(struct ccp *, struct bundle *, struct mbuf *); +extern int ccp_ReportStatus(struct cmdargs const *); +extern int ccp_Compress(struct ccp *, struct link *, int, u_short, struct mbuf *); +extern struct mbuf *ccp_Decompress(struct ccp *, u_short *, struct mbuf *); +extern u_short ccp_Proto(struct ccp *); +extern void ccp_SetupCallbacks(struct ccp *); +extern int ccp_SetOpenMode(struct ccp *); diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/ppp/chap.c index 257d32d59da..996ef62f8ff 100644 --- a/usr.sbin/ppp/chap.c +++ b/usr.sbin/ppp/ppp/chap.c @@ -17,53 +17,61 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.c,v 1.5 1998/03/13 01:25:52 brian Exp $ + * $Id: chap.c,v 1.1 1998/08/31 00:22:17 brian Exp $ * * TODO: */ -#include <sys/param.h> +#include <sys/types.h> #include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> -#include <ctype.h> #ifdef HAVE_DES #include <md4.h> #endif #include <md5.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> -#include <unistd.h> -#ifdef __OpenBSD__ -#include <util.h> -#else -#include <libutil.h> -#endif -#include <utmp.h> +#include <termios.h> -#include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" -#include "chap.h" -#include "chap_ms.h" #include "lcpproto.h" #include "lcp.h" +#include "lqr.h" #include "hdlc.h" -#include "phase.h" -#include "loadalias.h" -#include "vars.h" #include "auth.h" -#include "id.h" +#include "chap.h" +#include "async.h" +#include "throughput.h" +#include "descriptor.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "chat.h" +#include "cbcp.h" +#include "datalink.h" +#ifdef HAVE_DES +#include "chap_ms.h" +#endif static const char *chapcodes[] = { "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" }; static void -ChapOutput(u_int code, u_int id, const u_char * ptr, int count) +ChapOutput(struct physical *physical, u_int code, u_int id, + const u_char * ptr, int count, const char *text) { int plen; struct fsmheader lh; @@ -73,42 +81,40 @@ ChapOutput(u_int code, u_int id, const u_char * ptr, int count) lh.code = code; lh.id = id; lh.length = htons(plen); - bp = mballoc(plen, MB_FSM); + bp = mbuf_Alloc(plen, MB_FSM); memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); if (count) memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); - LogDumpBp(LogDEBUG, "ChapOutput", bp); - LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); - HdlcOutput(PRI_LINK, PROTO_CHAP, bp); + log_DumpBp(LogDEBUG, "ChapOutput", bp); + if (text == NULL) + log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); + else + log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); + hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); } - -static char challenge_data[80]; -static int challenge_len; - -static void -SendChapChallenge(int chapid) +void +chap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) { + struct chap *chap = auth2chap(auth); int len, i; char *cp; randinit(); - cp = challenge_data; - *cp++ = challenge_len = random() % 32 + 16; - for (i = 0; i < challenge_len; i++) + cp = chap->challenge_data; + *cp++ = chap->challenge_len = random() % 32 + 16; + for (i = 0; i < chap->challenge_len; i++) *cp++ = random() & 0xff; - len = strlen(VarAuthName); - memcpy(cp, VarAuthName, len); + len = strlen(physical->dl->bundle->cfg.auth.name); + memcpy(cp, physical->dl->bundle->cfg.auth.name, len); cp += len; - ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); + ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, + cp - chap->challenge_data, NULL); } -struct authinfo AuthChapInfo = { - SendChapChallenge, -}; - static void -RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) +RecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, + struct physical *physical) { int valsize, len; int arglen, keylen, namelen; @@ -123,35 +129,37 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) #endif len = ntohs(chp->length); - LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); + log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); arglen = len - sizeof(struct fsmheader); cp = (char *) MBUF_CTOP(bp); valsize = *cp++ & 255; name = cp + valsize; namelen = arglen - valsize - 1; name[namelen] = 0; - LogPrintf(LogLCP, " Valsize = %d, Name = \"%s\"\n", valsize, name); + + log_Printf(LogPHASE, "Chap Input: %s (from %s)\n", + chapcodes[chp->code], name); switch (chp->code) { case CHAP_CHALLENGE: - keyp = VarAuthKey; - keylen = strlen(VarAuthKey); - name = VarAuthName; - namelen = strlen(VarAuthName); + keyp = bundle->cfg.auth.key; + keylen = strlen(bundle->cfg.auth.key); + name = bundle->cfg.auth.name; + namelen = strlen(bundle->cfg.auth.name); #ifdef HAVE_DES - if (VarMSChap) + if (physical->dl->chap.using_MSChap) argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); else #endif argp = malloc(1 + valsize + namelen + 16); if (argp == NULL) { - ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14); + ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14, NULL); return; } #ifdef HAVE_DES - if (VarMSChap) { + if (physical->dl->chap.using_MSChap) { digest = argp; /* this is the response */ *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ memset(digest, '\0', 24); @@ -161,7 +169,7 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) memcpy(ap, keyp, keylen); ap += 2 * keylen; memcpy(ap, cp, valsize); - LogDumpBuff(LogDEBUG, "recv", ap, valsize); + log_DumpBuff(LogDEBUG, "recv", ap, valsize); ap += valsize; for (ix = keylen; ix > 0 ; ix--) { answer[2*ix-2] = answer[ix-1]; @@ -172,9 +180,10 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) MD4Final(digest, &MD4context); memcpy(digest + 25, name, namelen); ap += 2 * keylen; - ChapMS(digest, answer + 2 * keylen, valsize); - LogDumpBuff(LogDEBUG, "answer", digest, 24); - ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + MS_CHAP_RESPONSE_LEN + 1); + chap_MS(digest, answer + 2 * keylen, valsize); + log_DumpBuff(LogDEBUG, "answer", digest, 24); + ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, + namelen + MS_CHAP_RESPONSE_LEN + 1, name); } else { #endif digest = argp; @@ -184,26 +193,28 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) memcpy(ap, keyp, keylen); ap += keylen; memcpy(ap, cp, valsize); - LogDumpBuff(LogDEBUG, "recv", ap, valsize); + log_DumpBuff(LogDEBUG, "recv", ap, valsize); ap += valsize; MD5Init(&MD5context); MD5Update(&MD5context, answer, ap - answer); MD5Final(digest, &MD5context); - LogDumpBuff(LogDEBUG, "answer", digest, 16); + log_DumpBuff(LogDEBUG, "answer", digest, 16); memcpy(digest + 16, name, namelen); ap += namelen; /* Send answer to the peer */ - ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); + ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17, name); #ifdef HAVE_DES } #endif free(argp); + if (*name == '\0') + log_Printf(LogWARN, "Sending empty CHAP authname!\n"); break; case CHAP_RESPONSE: /* * Get a secret key corresponds to the peer */ - keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); + keyp = auth_GetSecret(bundle, name, namelen, physical); if (keyp) { /* * Compute correct digest value @@ -215,31 +226,29 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) ap += keylen; MD5Init(&MD5context); MD5Update(&MD5context, answer, ap - answer); - MD5Update(&MD5context, challenge_data + 1, challenge_len); + MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, + physical->dl->chap.challenge_len); MD5Final(cdigest, &MD5context); - LogDumpBuff(LogDEBUG, "got", cp, 16); - LogDumpBuff(LogDEBUG, "expect", cdigest, 16); + log_DumpBuff(LogDEBUG, "got", cp, 16); + log_DumpBuff(LogDEBUG, "expect", cdigest, 16); /* * Compare with the response */ if (memcmp(cp, cdigest, 16) == 0) { - ChapOutput(CHAP_SUCCESS, chp->id, "Welcome!!", 10); - if ((mode & MODE_DIRECT) && isatty(modem) && Enabled(ConfUtmp)) { - if (Utmp) - LogPrintf(LogERROR, "Oops, already logged in on %s\n", - VarBaseDevice); - else { - struct utmp ut; - memset(&ut, 0, sizeof ut); - time(&ut.ut_time); - strncpy(ut.ut_name, name, sizeof ut.ut_name); - strncpy(ut.ut_line, VarBaseDevice, sizeof ut.ut_line - 1); - ID0login(&ut); - Utmp = 1; - } - } - NewPhase(PHASE_NETWORK); + datalink_GotAuthname(physical->dl, name, namelen); + ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10, NULL); + physical->link.lcp.auth_ineed = 0; + if (Enabled(bundle, OPT_UTMP)) + physical_Login(physical, name); + + if (physical->link.lcp.auth_iwait == 0) + /* + * Either I didn't need to authenticate, or I've already been + * told that I got the answer right. + */ + datalink_AuthOk(physical->dl); + break; } } @@ -247,40 +256,42 @@ RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) /* * Peer is not registerd, or response digest is wrong. */ - ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); - reconnect(RECON_FALSE); - LcpClose(); + ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9, NULL); + datalink_AuthNotOk(physical->dl); break; } } static void -RecvChapResult(struct fsmheader *chp, struct mbuf *bp) +RecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, + struct physical *physical) { int len; - struct lcpstate *lcp = &LcpInfo; len = ntohs(chp->length); - LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); + log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); if (chp->code == CHAP_SUCCESS) { - if (lcp->auth_iwait == PROTO_CHAP) { - lcp->auth_iwait = 0; - if (lcp->auth_ineed == 0) - NewPhase(PHASE_NETWORK); + if (physical->link.lcp.auth_iwait == PROTO_CHAP) { + physical->link.lcp.auth_iwait = 0; + if (physical->link.lcp.auth_ineed == 0) + /* + * We've succeeded in our ``login'' + * If we're not expecting the peer to authenticate (or he already + * has), proceed to network phase. + */ + datalink_AuthOk(physical->dl); } } else { - - /* - * Maybe, we shoud close LCP. Of cause, peer may take close action, too. - */ - ; + /* CHAP failed - it's not going to get any better */ + log_Printf(LogPHASE, "Chap Input: Giving up after name/key FAILURE\n"); + datalink_AuthNotOk(physical->dl); } } void -ChapInput(struct mbuf *bp) +chap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) { - int len = plength(bp); + int len = mbuf_Length(bp); struct fsmheader *chp; if (len >= sizeof(struct fsmheader)) { @@ -288,24 +299,23 @@ ChapInput(struct mbuf *bp) if (len >= ntohs(chp->length)) { if (chp->code < 1 || chp->code > 4) chp->code = 0; - LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); - bp->offset += sizeof(struct fsmheader); bp->cnt -= sizeof(struct fsmheader); switch (chp->code) { case CHAP_RESPONSE: - StopAuthTimer(&AuthChapInfo); + auth_StopTimer(&physical->dl->chap.auth); /* Fall into.. */ case CHAP_CHALLENGE: - RecvChapTalk(chp, bp); + RecvChapTalk(bundle, chp, bp, physical); break; case CHAP_SUCCESS: case CHAP_FAILURE: - RecvChapResult(chp, bp); + log_Printf(LogPHASE, "Chap Input: %s\n", chapcodes[chp->code]); + RecvChapResult(bundle, chp, bp, physical); break; } } } - pfree(bp); + mbuf_Free(bp); } diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/ppp/chap.h index c41ecde74a4..f95a10d18fc 100644 --- a/usr.sbin/ppp/chap.h +++ b/usr.sbin/ppp/ppp/chap.h @@ -15,16 +15,28 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * $Id: chap.h,v 1.1 1998/08/31 00:22:17 brian Exp $ * * TODO: */ +struct mbuf; +struct physical; +struct bundle; + #define CHAP_CHALLENGE 1 #define CHAP_RESPONSE 2 #define CHAP_SUCCESS 3 #define CHAP_FAILURE 4 -extern struct authinfo AuthChapInfo; +struct chap { + struct authinfo auth; + char challenge_data[80]; + int challenge_len; + unsigned using_MSChap : 1; /* A combination of MD4 & DES */ +}; + +#define auth2chap(a) ((struct chap *)(a)) -extern void ChapInput(struct mbuf *); +extern void chap_Input(struct bundle *, struct mbuf *, struct physical *); +extern void chap_SendChallenge(struct authinfo *, int, struct physical *); diff --git a/usr.sbin/ppp/chap_ms.c b/usr.sbin/ppp/ppp/chap_ms.c index 00c3383477d..ec2c8b873f8 100644 --- a/usr.sbin/ppp/chap_ms.c +++ b/usr.sbin/ppp/ppp/chap_ms.c @@ -19,28 +19,24 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap_ms.c,v 1.3 1998/01/21 02:13:30 brian Exp $ + * $Id: chap_ms.c,v 1.1 1998/08/31 00:22:17 brian Exp $ * */ #include <sys/types.h> #include <des.h> -#include <stdio.h> #include <string.h> -#include <sys/time.h> -#include "command.h" -#include "mbuf.h" #include "chap_ms.h" /* unused, for documentation only */ /* only NTResp is filled in for FreeBSD */ -typedef struct { +struct MS_ChapResponse { u_char LANManResp[24]; u_char NTResp[24]; u_char UseNT; /* If 1, ignore the LANMan response field */ -} MS_ChapResponse; +}; static void DesEncrypt(u_char *, u_char *, u_char *); static void MakeKey(u_char *, u_char *); @@ -101,7 +97,7 @@ static void MakeKey(u_char *key, u_char *des_key) challenge 8-bytes peer CHAP challenge since passwordHash is in a 24-byte buffer, response is written in there */ void -ChapMS(char *passwordHash, char *challenge, int challenge_len) +chap_MS(char *passwordHash, char *challenge, int challenge_len) { u_char response[24]; diff --git a/usr.sbin/ppp/chap_ms.h b/usr.sbin/ppp/ppp/chap_ms.h index 74ddc3b5e85..7b2e2870744 100644 --- a/usr.sbin/ppp/chap_ms.h +++ b/usr.sbin/ppp/ppp/chap_ms.h @@ -19,7 +19,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap_ms.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * $Id: chap_ms.h,v 1.1 1998/08/31 00:22:17 brian Exp $ */ /* Max # of (Unicode) chars in an NT password */ @@ -28,4 +28,4 @@ /* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */ #define MS_CHAP_RESPONSE_LEN 49 -extern void ChapMS(char *, char *, int); +extern void chap_MS(char *, char *, int); diff --git a/usr.sbin/ppp/ppp/chat.c b/usr.sbin/ppp/ppp/chat.c new file mode 100644 index 00000000000..eb8f36c58c9 --- /dev/null +++ b/usr.sbin/ppp/ppp/chat.c @@ -0,0 +1,797 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: chat.c,v 1.1 1998/08/31 00:22:18 brian Exp $ + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> + +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "lqr.h" +#include "hdlc.h" +#include "throughput.h" +#include "fsm.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "async.h" +#include "descriptor.h" +#include "physical.h" +#include "chat.h" +#include "mp.h" +#include "auth.h" +#include "chap.h" +#include "slcompress.h" +#include "iplist.h" +#include "ipcp.h" +#include "filter.h" +#include "cbcp.h" +#include "datalink.h" +#include "bundle.h" + +#define BUFLEFT(c) (sizeof (c)->buf - ((c)->bufend - (c)->buf)) +#define issep(c) ((c) == '\t' || (c) == ' ') + +static void ExecStr(struct physical *, char *, char *, int); +static char *ExpandString(struct chat *, const char *, char *, int, int); + +static void +chat_PauseTimer(void *v) +{ + struct chat *c = (struct chat *)v; + timer_Stop(&c->pause); + c->pause.load = 0; +} + +static void +chat_Pause(struct chat *c, u_long load) +{ + timer_Stop(&c->pause); + c->pause.load += load; + c->pause.func = chat_PauseTimer; + c->pause.name = "chat pause"; + c->pause.arg = c; + timer_Start(&c->pause); +} + +static void +chat_TimeoutTimer(void *v) +{ + struct chat *c = (struct chat *)v; + timer_Stop(&c->timeout); + c->TimedOut = 1; +} + +static void +chat_SetTimeout(struct chat *c) +{ + timer_Stop(&c->timeout); + if (c->TimeoutSec > 0) { + c->timeout.load = SECTICKS * c->TimeoutSec; + c->timeout.func = chat_TimeoutTimer; + c->timeout.name = "chat timeout"; + c->timeout.arg = c; + timer_Start(&c->timeout); + } +} + +static char * +chat_NextChar(char *ptr, char ch) +{ + for (; *ptr; ptr++) + if (*ptr == ch) + return ptr; + else if (*ptr == '\\') + if (*++ptr == '\0') + return NULL; + + return NULL; +} + +static int +chat_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + struct chat *c = descriptor2chat(d); + int special, gotabort, gottimeout, needcr; + int TimedOut = c->TimedOut; + static char arg_term; /* An empty string */ + + if (c->pause.state == TIMER_RUNNING) + return 0; + + if (TimedOut) { + log_Printf(LogCHAT, "Expect timeout\n"); + if (c->nargptr == NULL) + c->state = CHAT_FAILED; + else { + /* c->state = CHAT_EXPECT; */ + c->argptr = &arg_term; + } + c->TimedOut = 0; + } + + if (c->state != CHAT_EXPECT && c->state != CHAT_SEND) + return 0; + + gottimeout = gotabort = 0; + + if (c->arg < c->argc && (c->arg < 0 || *c->argptr == '\0')) { + /* Go get the next string */ + if (c->arg < 0 || c->state == CHAT_SEND) + c->state = CHAT_EXPECT; + else + c->state = CHAT_SEND; + + special = 1; + while (special && (c->nargptr || c->arg < c->argc - 1)) { + if (c->arg < 0 || (!TimedOut && c->state == CHAT_SEND)) + c->nargptr = NULL; + + if (c->nargptr != NULL) { + /* We're doing expect-send-expect.... */ + c->argptr = c->nargptr; + /* Put the '-' back in case we ever want to rerun our script */ + c->nargptr[-1] = '-'; + c->nargptr = chat_NextChar(c->nargptr, '-'); + if (c->nargptr != NULL) + *c->nargptr++ = '\0'; + } else { + int minus; + + c->argptr = c->argv[++c->arg]; + + if (c->state == CHAT_EXPECT) { + /* Look for expect-send-expect sequence */ + c->nargptr = c->argptr; + minus = 0; + while ((c->nargptr = chat_NextChar(c->nargptr, '-'))) { + c->nargptr++; + minus++; + } + + if (minus % 2) + log_Printf(LogWARN, "chat_UpdateSet: \"%s\": Uneven number of" + " '-' chars, all ignored\n", c->argptr); + else if (minus) { + c->nargptr = chat_NextChar(c->argptr, '-'); + *c->nargptr++ = '\0'; + } + } + } + + /* + * c->argptr now temporarily points into c->script (via c->argv) + * If it's an expect-send-expect sequence, we've just got the correct + * portion of that sequence. + */ + + needcr = c->state == CHAT_SEND && *c->argptr != '!'; + + /* We leave room for a potential HDLC header in the target string */ + ExpandString(c, c->argptr, c->exp + 2, sizeof c->exp - 2, needcr); + + if (gotabort) { + if (c->abort.num < MAXABORTS) { + int len, i; + + len = strlen(c->exp+2); + for (i = 0; i < c->abort.num; i++) + if (len > c->abort.string[i].len) { + int last; + + for (last = c->abort.num; last > i; last--) { + c->abort.string[last].data = c->abort.string[last-1].data; + c->abort.string[last].len = c->abort.string[last-1].len; + } + break; + } + c->abort.string[i].len = len; + c->abort.string[i].data = (char *)malloc(len+1); + memcpy(c->abort.string[i].data, c->exp+2, len+1); + c->abort.num++; + } else + log_Printf(LogERROR, "chat_UpdateSet: too many abort strings\n"); + gotabort = 0; + } else if (gottimeout) { + c->TimeoutSec = atoi(c->exp + 2); + if (c->TimeoutSec <= 0) + c->TimeoutSec = 30; + gottimeout = 0; + } else if (c->nargptr == NULL && !strcmp(c->exp+2, "ABORT")) + gotabort = 1; + else if (c->nargptr == NULL && !strcmp(c->exp+2, "TIMEOUT")) + gottimeout = 1; + else { + if (c->exp[2] == '!') + ExecStr(c->physical, c->exp + 3, c->exp + 2, sizeof c->exp - 2); + + if (c->exp[2] == '\0') { + /* Empty string, reparse (this may be better as a `goto start') */ + c->argptr = &arg_term; + return chat_UpdateSet(d, r, w, e, n); + } + + special = 0; + } + } + + if (special) { + if (gottimeout) + log_Printf(LogWARN, "chat_UpdateSet: TIMEOUT: Argument expected\n"); + else if (gotabort) + log_Printf(LogWARN, "chat_UpdateSet: ABORT: Argument expected\n"); + + /* End of script - all ok */ + c->state = CHAT_DONE; + return 0; + } + + /* set c->argptr to point in the right place */ + c->argptr = c->exp + 2; + c->arglen = strlen(c->argptr); + + if (c->state == CHAT_EXPECT) { + /* We must check to see if the string's already been found ! */ + char *begin, *end; + + end = c->bufend - c->arglen + 1; + if (end < c->bufstart) + end = c->bufstart; + for (begin = c->bufstart; begin < end; begin++) + if (!strncmp(begin, c->argptr, c->arglen)) { + c->bufstart = begin + c->arglen; + c->argptr += c->arglen; + c->arglen = 0; + /* Continue - we've already read our expect string */ + return chat_UpdateSet(d, r, w, e, n); + } + + log_Printf(LogCHAT, "Expect(%d): %s\n", c->TimeoutSec, c->argptr); + chat_SetTimeout(c); + } + } + + /* + * We now have c->argptr pointing at what we want to expect/send and + * c->state saying what we want to do... we now know what to put in + * the fd_set :-) + */ + + if (c->state == CHAT_EXPECT) + return physical_UpdateSet(&c->physical->desc, r, NULL, e, n, 1); + else + return physical_UpdateSet(&c->physical->desc, NULL, w, e, n, 1); +} + +static int +chat_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct chat *c = descriptor2chat(d); + return physical_IsSet(&c->physical->desc, fdset); +} + +static void +chat_UpdateLog(struct chat *c, int in) +{ + if (log_IsKept(LogCHAT) || log_IsKept(LogCONNECT)) { + /* + * If a linefeed appears in the last `in' characters of `c's input + * buffer, output from there, all the way back to the last linefeed. + * This is called for every read of `in' bytes. + */ + char *ptr, *end, *stop, ch; + int level; + + level = log_IsKept(LogCHAT) ? LogCHAT : LogCONNECT; + if (in == -1) + end = ptr = c->bufend; + else { + ptr = c->bufend - in; + for (end = c->bufend - 1; end >= ptr; end--) + if (*end == '\n') + break; + } + + if (end >= ptr) { + for (ptr = c->bufend - (in == -1 ? 1 : in + 1); ptr >= c->bufstart; ptr--) + if (*ptr == '\n') + break; + ptr++; + stop = NULL; + while (stop < end) { + if ((stop = memchr(ptr, '\n', end - ptr)) == NULL) + stop = end; + ch = *stop; + *stop = '\0'; + if (level == LogCHAT || strstr(ptr, "CONNECT")) + log_Printf(level, "Received: %s\n", ptr); + *stop = ch; + ptr = stop + 1; + } + } + } +} + +static void +chat_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct chat *c = descriptor2chat(d); + + if (c->state == CHAT_EXPECT) { + ssize_t in; + char *abegin, *ebegin, *begin, *aend, *eend, *end; + int n; + + /* + * XXX - should this read only 1 byte to guarantee that we don't + * swallow any ppp talk from the peer ? + */ + in = BUFLEFT(c); + if (in > sizeof c->buf / 2) + in = sizeof c->buf / 2; + + in = physical_Read(c->physical, c->bufend, in); + if (in <= 0) + return; + + /* `begin' and `end' delimit where we're going to strncmp() from */ + ebegin = c->bufend - c->arglen + 1; + eend = ebegin + in; + if (ebegin < c->bufstart) + ebegin = c->bufstart; + + if (c->abort.num) { + abegin = c->bufend - c->abort.string[0].len + 1; + aend = c->bufend - c->abort.string[c->abort.num-1].len + in + 1; + if (abegin < c->bufstart) + abegin = c->bufstart; + } else { + abegin = ebegin; + aend = eend; + } + begin = abegin < ebegin ? abegin : ebegin; + end = aend < eend ? eend : aend; + + c->bufend += in; + + chat_UpdateLog(c, in); + + if (c->bufend > c->buf + sizeof c->buf / 2) { + /* Shuffle our receive buffer back a bit */ + int chop; + + for (chop = begin - c->buf; chop; chop--) + if (c->buf[chop] == '\n') + /* found some already-logged garbage to remove :-) */ + break; + + if (!chop) + chop = begin - c->buf; + + if (chop) { + char *from, *to; + + to = c->buf; + from = to + chop; + while (from < c->bufend) + *to++ = *from++; + c->bufstart -= chop; + c->bufend -= chop; + begin -= chop; + end -= chop; + abegin -= chop; + aend -= chop; + ebegin -= chop; + eend -= chop; + } + } + + for (; begin < end; begin++) + if (begin >= ebegin && begin < eend && + !strncmp(begin, c->argptr, c->arglen)) { + /* Got it ! */ + if (memchr(begin + c->arglen - 1, '\n', + c->bufend - begin - c->arglen + 1) == NULL) { + /* force it into the log */ + end = c->bufend; + c->bufend = begin + c->arglen; + chat_UpdateLog(c, -1); + c->bufend = end; + } + c->bufstart = begin + c->arglen; + c->argptr += c->arglen; + c->arglen = 0; + break; + } else if (begin >= abegin && begin < aend) { + for (n = c->abort.num - 1; n >= 0; n--) { + if (begin + c->abort.string[n].len > c->bufend) + break; + if (!strncmp(begin, c->abort.string[n].data, + c->abort.string[n].len)) { + if (memchr(begin + c->abort.string[n].len - 1, '\n', + c->bufend - begin - c->abort.string[n].len + 1) == NULL) { + /* force it into the log */ + end = c->bufend; + c->bufend = begin + c->abort.string[n].len; + chat_UpdateLog(c, -1); + c->bufend = end; + } + c->bufstart = begin + c->abort.string[n].len; + c->state = CHAT_FAILED; + return; + } + } + } + } +} + +static int +chat_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct chat *c = descriptor2chat(d); + int result = 0; + + if (c->state == CHAT_SEND) { + int wrote; + + if (strstr(c->argv[c->arg], "\\P")) /* Don't log the password */ + log_Printf(LogCHAT, "Send: %s\n", c->argv[c->arg]); + else { + int sz; + + sz = c->arglen - 1; + while (sz >= 0 && c->argptr[sz] == '\n') + sz--; + log_Printf(LogCHAT, "Send: %.*s\n", sz + 1, c->argptr); + } + + if (physical_IsSync(c->physical)) { + /* There's always room for the HDLC header */ + c->argptr -= 2; + c->arglen += 2; + memcpy(c->argptr, "\377\003", 2); /* Prepend HDLC header */ + } + + wrote = physical_Write(c->physical, c->argptr, c->arglen); + result = wrote ? 1 : 0; + if (wrote == -1) { + if (errno != EINTR) + log_Printf(LogERROR, "chat_Write: %s\n", strerror(errno)); + if (physical_IsSync(c->physical)) { + c->argptr += 2; + c->arglen -= 2; + } + } else if (wrote < 2 && physical_IsSync(c->physical)) { + /* Oops - didn't even write our HDLC header ! */ + c->argptr += 2; + c->arglen -= 2; + } else { + c->argptr += wrote; + c->arglen -= wrote; + } + } + + return result; +} + +void +chat_Init(struct chat *c, struct physical *p, const char *data, int emptybuf, + const char *phone) +{ + c->desc.type = CHAT_DESCRIPTOR; + c->desc.UpdateSet = chat_UpdateSet; + c->desc.IsSet = chat_IsSet; + c->desc.Read = chat_Read; + c->desc.Write = chat_Write; + c->physical = p; + + c->state = CHAT_EXPECT; + + if (data == NULL) { + *c->script = '\0'; + c->argc = 0; + } else { + strncpy(c->script, data, sizeof c->script - 1); + c->script[sizeof c->script - 1] = '\0'; + c->argc = MakeArgs(c->script, c->argv, VECSIZE(c->argv)); + } + + c->arg = -1; + c->argptr = NULL; + c->nargptr = NULL; + + if (emptybuf) + c->bufstart = c->bufend = c->buf; + + c->TimeoutSec = 30; + c->TimedOut = 0; + c->phone = phone; + c->abort.num = 0; + + memset(&c->pause, '\0', sizeof c->pause); + memset(&c->timeout, '\0', sizeof c->timeout); +} + +void +chat_Destroy(struct chat *c) +{ + timer_Stop(&c->pause); + timer_Stop(&c->timeout); + while (c->abort.num) + free(c->abort.string[--c->abort.num].data); + c->abort.num = 0; +} + +static char * +findblank(char *p, int instring) +{ + if (instring) { + while (*p) { + if (*p == '\\') { + strcpy(p, p + 1); + if (!*p) + break; + } else if (*p == '"') + return (p); + p++; + } + } else { + while (*p) { + if (issep(*p)) + return (p); + p++; + } + } + return p; +} + +int +MakeArgs(char *script, char **pvect, int maxargs) +{ + int nargs, nb; + int instring; + + nargs = 0; + while (*script) { + nb = strspn(script, " \t"); + script += nb; + if (*script) { + if (*script == '"') { + instring = 1; + script++; + if (*script == '\0') + break; /* Shouldn't return here. Need to null + * terminate below */ + } else + instring = 0; + if (nargs >= maxargs - 1) + break; + *pvect++ = script; + nargs++; + script = findblank(script, instring); + if (*script) + *script++ = '\0'; + } + } + *pvect = NULL; + return nargs; +} + +/* + * \c don't add a cr + * \d Sleep a little (delay 2 seconds + * \n Line feed character + * \P Auth Key password + * \p pause 0.25 sec + * \r Carrige return character + * \s Space character + * \T Telephone number(s) (defined via `set phone') + * \t Tab character + * \U Auth User + */ +static char * +ExpandString(struct chat *c, const char *str, char *result, int reslen, + int sendmode) +{ + int addcr = 0; + + result[--reslen] = '\0'; + if (sendmode) + addcr = 1; + while (*str && reslen > 0) { + switch (*str) { + case '\\': + str++; + switch (*str) { + case 'c': + if (sendmode) + addcr = 0; + break; + case 'd': /* Delay 2 seconds */ + chat_Pause(c, 2 * SECTICKS); + break; + case 'p': + chat_Pause(c, SECTICKS / 4); + break; /* Pause 0.25 sec */ + case 'n': + *result++ = '\n'; + reslen--; + break; + case 'r': + *result++ = '\r'; + reslen--; + break; + case 's': + *result++ = ' '; + reslen--; + break; + case 't': + *result++ = '\t'; + reslen--; + break; + case 'P': + strncpy(result, c->physical->dl->bundle->cfg.auth.key, reslen); + reslen -= strlen(result); + result += strlen(result); + break; + case 'T': + if (c->phone) { + strncpy(result, c->phone, reslen); + reslen -= strlen(result); + result += strlen(result); + } + break; + case 'U': + strncpy(result, c->physical->dl->bundle->cfg.auth.name, reslen); + reslen -= strlen(result); + result += strlen(result); + break; + default: + reslen--; + *result++ = *str; + break; + } + if (*str) + str++; + break; + case '^': + str++; + if (*str) { + *result++ = *str++ & 0x1f; + reslen--; + } + break; + default: + *result++ = *str++; + reslen--; + break; + } + } + if (--reslen > 0) { + if (addcr) + *result++ = '\r'; + } + if (--reslen > 0) + *result++ = '\0'; + return (result); +} + +static void +ExecStr(struct physical *physical, char *command, char *out, int olen) +{ + pid_t pid; + int fids[2]; + char *vector[MAXARGS], *startout, *endout; + int stat, nb; + + log_Printf(LogCHAT, "Exec: %s\n", command); + MakeArgs(command, vector, VECSIZE(vector)); + + if (pipe(fids) < 0) { + log_Printf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", + strerror(errno)); + *out = '\0'; + return; + } + if ((pid = fork()) == 0) { + close(fids[0]); + timer_TermService(); + fids[1] = fcntl(fids[1], F_DUPFD, 4); + dup2(physical_GetFD(physical), STDIN_FILENO); + dup2(STDIN_FILENO, STDOUT_FILENO); + dup2(fids[1], STDERR_FILENO); + close(3); + if (open(_PATH_TTY, O_RDWR) == 3) + fcntl(3, F_SETFD, 0); /* Clear close-on-exec flag */ + else + fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ + setuid(geteuid()); + execvp(vector[0], vector); + fprintf(stderr, "execvp failed: %s: %s\n", vector[0], strerror(errno)); + exit(127); + } else { + char *name = strdup(vector[0]); + + close(fids[1]); + endout = out + olen - 1; + startout = out; + while (out < endout) { + nb = read(fids[0], out, 1); + if (nb <= 0) + break; + out++; + } + *out = '\0'; + close(fids[0]); + close(fids[1]); + waitpid(pid, &stat, WNOHANG); + if (WIFSIGNALED(stat)) { + log_Printf(LogWARN, "%s: signal %d\n", name, WTERMSIG(stat)); + free(name); + *out = '\0'; + return; + } else if (WIFEXITED(stat)) { + switch (WEXITSTATUS(stat)) { + case 0: + free(name); + break; + case 127: + log_Printf(LogWARN, "%s: %s\n", name, startout); + free(name); + *out = '\0'; + return; + break; + default: + log_Printf(LogWARN, "%s: exit %d\n", name, WEXITSTATUS(stat)); + free(name); + *out = '\0'; + return; + break; + } + } else { + log_Printf(LogWARN, "%s: Unexpected exit result\n", name); + free(name); + *out = '\0'; + return; + } + } +} diff --git a/usr.sbin/ppp/ppp/chat.h b/usr.sbin/ppp/ppp/chat.h new file mode 100644 index 00000000000..9c2fdb75d9c --- /dev/null +++ b/usr.sbin/ppp/ppp/chat.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: chat.h,v 1.1 1998/08/31 00:22:18 brian Exp $ + */ + +#define CHAT_EXPECT 0 +#define CHAT_SEND 1 +#define CHAT_DONE 2 +#define CHAT_FAILED 3 + +#define MAXABORTS 50 + +struct physical; + +struct chat { + struct descriptor desc; + struct physical *physical; + + int state; /* Our CHAT_* status */ + + char script[LINE_LEN]; /* Our arg buffer */ + char *argv[MAXARGS]; /* Our arguments (pointing to script) */ + int argc; /* Number of argv's */ + + int arg; /* Our current arg number */ + char exp[LINE_LEN]; /* Our translated current argument */ + char *argptr; /* Our current arg pointer */ + int arglen; /* The length of argptr */ + char *nargptr; /* Our next for expect-send-expect */ + + char buf[LINE_LEN*2]; /* Our input */ + char *bufstart; /* start of relevent data */ + char *bufend; /* end of relevent data */ + + int TimeoutSec; /* Expect timeout value */ + int TimedOut; /* We timed out */ + + const char *phone; /* Our phone number */ + + struct { + struct { + char *data; /* Abort the dial if we get one */ + int len; + } string[MAXABORTS]; + int num; /* How many AbortStrings */ + } abort; + + struct pppTimer pause; /* Inactivity timer */ + struct pppTimer timeout; /* TimeoutSec timer */ +}; + +#define descriptor2chat(d) \ + ((d)->type == CHAT_DESCRIPTOR ? (struct chat *)(d) : NULL) +#define VECSIZE(v) (sizeof(v) / sizeof(v[0])) + +extern void chat_Init(struct chat *, struct physical *, const char *, int, + const char *); +extern void chat_Destroy(struct chat *); +extern int MakeArgs(char *, char **, int); /* Mangles the first arg ! */ diff --git a/usr.sbin/ppp/ppp/command.c b/usr.sbin/ppp/ppp/command.c new file mode 100644 index 00000000000..772a94c9b43 --- /dev/null +++ b/usr.sbin/ppp/ppp/command.c @@ -0,0 +1,2254 @@ +/* + * PPP User command processing module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: command.c,v 1.1 1998/08/31 00:22:18 brian Exp $ + * + */ +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <net/route.h> +#include <netdb.h> +#include <sys/un.h> + +#ifndef NOALIAS +#include <alias.h> +#endif +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "lcp.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "modem.h" +#ifndef NOALIAS +#include "alias_cmd.h" +#endif +#include "systems.h" +#include "filter.h" +#include "descriptor.h" +#include "main.h" +#include "route.h" +#include "ccp.h" +#include "auth.h" +#include "async.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "server.h" +#include "prompt.h" +#include "chat.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" + +/* ``set'' values */ +#define VAR_AUTHKEY 0 +#define VAR_DIAL 1 +#define VAR_LOGIN 2 +#define VAR_AUTHNAME 3 +#define VAR_AUTOLOAD 4 +#define VAR_WINSIZE 5 +#define VAR_DEVICE 6 +#define VAR_ACCMAP 7 +#define VAR_MRRU 8 +#define VAR_MRU 9 +#define VAR_MTU 10 +#define VAR_OPENMODE 11 +#define VAR_PHONE 12 +#define VAR_HANGUP 13 +#define VAR_IDLETIMEOUT 14 +#define VAR_LQRPERIOD 15 +#define VAR_LCPRETRY 16 +#define VAR_CHAPRETRY 17 +#define VAR_PAPRETRY 18 +#define VAR_CCPRETRY 19 +#define VAR_IPCPRETRY 20 +#define VAR_DNS 21 +#define VAR_NBNS 22 +#define VAR_MODE 23 +#define VAR_CALLBACK 24 +#define VAR_CBCP 25 +#define VAR_CHOKED 26 + +/* ``accept|deny|disable|enable'' masks */ +#define NEG_HISMASK (1) +#define NEG_MYMASK (2) + +/* ``accept|deny|disable|enable'' values */ +#define NEG_ACFCOMP 40 +#define NEG_CHAP 41 +#define NEG_DEFLATE 42 +#define NEG_LQR 43 +#define NEG_PAP 44 +#define NEG_PPPDDEFLATE 45 +#define NEG_PRED1 46 +#define NEG_PROTOCOMP 47 +#define NEG_SHORTSEQ 48 +#define NEG_VJCOMP 49 +#define NEG_DNS 50 + +const char Version[] = "2.0"; +const char VersionDate[] = "$Date: 1998/08/31 00:22:18 $"; + +static int ShowCommand(struct cmdargs const *); +static int TerminalCommand(struct cmdargs const *); +static int QuitCommand(struct cmdargs const *); +static int OpenCommand(struct cmdargs const *); +static int CloseCommand(struct cmdargs const *); +static int DownCommand(struct cmdargs const *); +static int AllowCommand(struct cmdargs const *); +static int SetCommand(struct cmdargs const *); +static int LinkCommand(struct cmdargs const *); +static int AddCommand(struct cmdargs const *); +static int DeleteCommand(struct cmdargs const *); +static int NegotiateCommand(struct cmdargs const *); +static int ClearCommand(struct cmdargs const *); +#ifndef NOALIAS +static int AliasCommand(struct cmdargs const *); +static int AliasEnable(struct cmdargs const *); +static int AliasOption(struct cmdargs const *); +#endif + +static const char * +showcx(struct cmdtab const *cmd) +{ + if (cmd->lauth & LOCAL_CX) + return "(c)"; + else if (cmd->lauth & LOCAL_CX_OPT) + return "(o)"; + + return ""; +} + +static int +HelpCommand(struct cmdargs const *arg) +{ + struct cmdtab const *cmd; + int n, cmax, dmax, cols, cxlen; + const char *cx; + + if (!arg->prompt) { + log_Printf(LogWARN, "help: Cannot help without a prompt\n"); + return 0; + } + + if (arg->argc > arg->argn) { + for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) + if ((cmd->lauth & arg->prompt->auth) && + ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || + (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { + prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); + return 0; + } + return -1; + } + + cmax = dmax = 0; + for (cmd = arg->cmdtab; cmd->func; cmd++) + if (cmd->name && (cmd->lauth & arg->prompt->auth)) { + if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) + cmax = n; + if ((n = strlen(cmd->helpmes)) > dmax) + dmax = n; + } + + cols = 80 / (dmax + cmax + 3); + n = 0; + prompt_Printf(arg->prompt, "(o) = Optional context," + " (c) = Context required\n"); + for (cmd = arg->cmdtab; cmd->func; cmd++) + if (cmd->name && (cmd->lauth & arg->prompt->auth)) { + cx = showcx(cmd); + cxlen = cmax - strlen(cmd->name); + prompt_Printf(arg->prompt, " %s%-*.*s: %-*.*s", + cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); + if (++n % cols == 0) + prompt_Printf(arg->prompt, "\n"); + } + if (n % cols != 0) + prompt_Printf(arg->prompt, "\n"); + + return 0; +} + +static int +CloneCommand(struct cmdargs const *arg) +{ + char namelist[LINE_LEN]; + char *name; + int f; + + if (arg->argc == arg->argn) + return -1; + + namelist[sizeof namelist - 1] = '\0'; + for (f = arg->argn; f < arg->argc; f++) { + strncpy(namelist, arg->argv[f], sizeof namelist - 1); + for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) + bundle_DatalinkClone(arg->bundle, arg->cx, name); + } + + return 0; +} + +static int +RemoveCommand(struct cmdargs const *arg) +{ + if (arg->argc != arg->argn) + return -1; + + if (arg->cx->state != DATALINK_CLOSED) { + log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); + return 2; + } + + bundle_DatalinkRemove(arg->bundle, arg->cx); + return 0; +} + +static int +RenameCommand(struct cmdargs const *arg) +{ + if (arg->argc != arg->argn + 1) + return -1; + + if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) + return 0; + + log_Printf(LogWARN, "%s -> %s: target name already exists\n", + arg->cx->name, arg->argv[arg->argn]); + return 1; +} + +int +LoadCommand(struct cmdargs const *arg) +{ + const char *name; + + if (arg->argc > arg->argn) + name = arg->argv[arg->argn]; + else + name = "default"; + + if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) { + log_Printf(LogWARN, "%s: Label not allowed\n", name); + return 1; + } else { + /* + * Set the label before & after so that `set enddisc' works and + * we handle nested `load' commands. + */ + bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL); + if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) { + bundle_SetLabel(arg->bundle, NULL); + log_Printf(LogWARN, "%s: label not found.\n", name); + return -1; + } + bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL); + } + return 0; +} + +int +SaveCommand(struct cmdargs const *arg) +{ + log_Printf(LogWARN, "save command is not implemented (yet).\n"); + return 1; +} + +static int +DialCommand(struct cmdargs const *arg) +{ + int res; + + if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) + || (!arg->cx && + (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { + log_Printf(LogWARN, "Manual dial is only available for auto and" + " interactive links\n"); + return 1; + } + + if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) + return res; + + bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); + + return 0; +} + +#define isinword(ch) (isalnum(ch) || (ch) == '_') + +static char * +strstrword(char *big, const char *little) +{ + /* Get the first occurance of the word ``little'' in ``big'' */ + char *pos; + int len; + + pos = big; + len = strlen(little); + + while ((pos = strstr(pos, little)) != NULL) + if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len])) + break; + else + pos++; + + return pos; +} + +static char * +subst(char *tgt, const char *oldstr, const char *newstr) +{ + /* tgt is a malloc()d area... realloc() as necessary */ + char *word, *ntgt; + int ltgt, loldstr, lnewstr, pos; + + if ((word = strstrword(tgt, oldstr)) == NULL) + return tgt; + + ltgt = strlen(tgt) + 1; + loldstr = strlen(oldstr); + lnewstr = strlen(newstr); + do { + pos = word - tgt; + if (loldstr > lnewstr) + bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); + if (loldstr != lnewstr) { + ntgt = realloc(tgt, ltgt += lnewstr - loldstr); + if (ntgt == NULL) + break; /* Oh wonderful ! */ + word = ntgt + pos; + tgt = ntgt; + } + if (lnewstr > loldstr) + bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); + bcopy(newstr, word, lnewstr); + } while ((word = strstrword(word, oldstr))); + + return tgt; +} + +static void +expand(char **nargv, int argc, char const *const *oargv, struct bundle *bundle) +{ + int arg; + + nargv[0] = strdup(oargv[0]); + for (arg = 1; arg < argc; arg++) { + nargv[arg] = strdup(oargv[arg]); + nargv[arg] = subst(nargv[arg], "HISADDR", + inet_ntoa(bundle->ncp.ipcp.peer_ip)); + nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); + nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->ifp.Name); + nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip)); + nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); + nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", + mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, + bundle->ncp.mp.peer.enddisc.address, + bundle->ncp.mp.peer.enddisc.len)); + nargv[arg] = subst(nargv[arg], "ENDDISC", + mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, + bundle->ncp.mp.cfg.enddisc.address, + bundle->ncp.mp.cfg.enddisc.len)); + nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); + } + nargv[arg] = NULL; +} + +static int +ShellCommand(struct cmdargs const *arg, int bg) +{ + const char *shell; + pid_t shpid; + +#ifdef SHELL_ONLY_INTERACTIVELY + /* we're only allowed to shell when we run ppp interactively */ + if (arg->prompt && arg->prompt->owner) { + log_Printf(LogWARN, "Can't start a shell from a network connection\n"); + return 1; + } +#endif + + if (arg->argc == arg->argn) { + if (!arg->prompt) { + log_Printf(LogWARN, "Can't start an interactive shell from" + " a config file\n"); + return 1; + } else if (arg->prompt->owner) { + log_Printf(LogWARN, "Can't start an interactive shell from" + " a socket connection\n"); + return 1; + } else if (bg) { + log_Printf(LogWARN, "Can only start an interactive shell in" + " the foreground mode\n"); + return 1; + } + } + + if ((shpid = fork()) == 0) { + int i, fd; + + if ((shell = getenv("SHELL")) == 0) + shell = _PATH_BSHELL; + + timer_TermService(); + + if (arg->prompt) + fd = arg->prompt->fd_out; + else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { + log_Printf(LogALERT, "Failed to open %s: %s\n", + _PATH_DEVNULL, strerror(errno)); + exit(1); + } + for (i = 0; i < 3; i++) + dup2(fd, i); + + fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ + + setuid(geteuid()); + if (arg->argc > arg->argn) { + /* substitute pseudo args */ + char *argv[MAXARGS]; + int argc = arg->argc - arg->argn; + + if (argc >= sizeof argv / sizeof argv[0]) { + argc = sizeof argv / sizeof argv[0] - 1; + log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); + } + expand(argv, argc, arg->argv + arg->argn, arg->bundle); + if (bg) { + pid_t p; + + p = getpid(); + if (daemon(1, 1) == -1) { + log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno)); + exit(1); + } + } else if (arg->prompt) + printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); + execvp(argv[0], argv); + } else { + if (arg->prompt) + printf("ppp: Pausing until %s finishes\n", shell); + prompt_TtyOldMode(arg->prompt); + execl(shell, shell, NULL); + } + + log_Printf(LogWARN, "exec() of %s failed\n", + arg->argc > arg->argn ? arg->argv[arg->argn] : shell); + exit(255); + } + + if (shpid == (pid_t) - 1) + log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); + else { + int status; + waitpid(shpid, &status, 0); + } + + if (arg->prompt && !arg->prompt->owner) + prompt_TtyCommandMode(arg->prompt); + + return 0; +} + +static int +BgShellCommand(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn) + return -1; + return ShellCommand(arg, 1); +} + +static int +FgShellCommand(struct cmdargs const *arg) +{ + return ShellCommand(arg, 0); +} + +static struct cmdtab const Commands[] = { + {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "accept option request", "accept option .."}, + {"add", NULL, AddCommand, LOCAL_AUTH, + "add route", "add dest mask gateway", NULL}, + {NULL, "add!", AddCommand, LOCAL_AUTH, + "add or change route", "add! dest mask gateway", (void *)1}, +#ifndef NOALIAS + {"alias", NULL, AliasCommand, LOCAL_AUTH, + "alias control", "alias option [yes|no]"}, +#endif + {"allow", "auth", AllowCommand, LOCAL_AUTH, + "Allow ppp access", "allow users|modes ...."}, + {"bg", "!bg", BgShellCommand, LOCAL_AUTH, + "Run a background command", "[!]bg command"}, + {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."}, + {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, + "Clone a link", "clone newname..."}, + {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Close an FSM", "close [lcp|ccp]"}, + {"delete", NULL, DeleteCommand, LOCAL_AUTH, + "delete route", "delete dest", NULL}, + {NULL, "delete!", DeleteCommand, LOCAL_AUTH, + "delete a route if it exists", "delete! dest", (void *)1}, + {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Deny option request", "deny option .."}, + {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Dial and login", "dial|call [remote]", NULL}, + {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Disable option", "disable option .."}, + {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Generate a down event", "down"}, + {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Enable option", "enable option .."}, + {"link", "datalink", LinkCommand, LOCAL_AUTH, + "Link specific commands", "link name command ..."}, + {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Load settings", "load [remote]"}, + {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, + {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, + "Password for manipulation", "passwd LocalPassword"}, + {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Quit PPP program", "quit|bye [all]"}, + {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, + "Remove a link", "remove"}, + {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, + "Rename a link", "rename name"}, + {"save", NULL, SaveCommand, LOCAL_AUTH, + "Save settings", "save"}, + {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Set parameters", "set[up] var value"}, + {"shell", "!", FgShellCommand, LOCAL_AUTH, + "Run a subshell", "shell|! [sh command]"}, + {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, + "Show status and stats", "show var"}, + {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, + "Enter terminal mode", "term"}, + {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Display this message", "help|? [command]", Commands}, + {NULL, NULL, NULL}, +}; + +static int +ShowEscape(struct cmdargs const *arg) +{ + if (arg->cx->physical->async.cfg.EscMap[32]) { + int code, bit; + const char *sep = ""; + + for (code = 0; code < 32; code++) + if (arg->cx->physical->async.cfg.EscMap[code]) + for (bit = 0; bit < 8; bit++) + if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { + prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); + sep = ", "; + } + prompt_Printf(arg->prompt, "\n"); + } + return 0; +} + +static int +ShowTimerList(struct cmdargs const *arg) +{ + timer_Show(0, arg->prompt); + return 0; +} + +static int +ShowStopped(struct cmdargs const *arg) +{ + prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); + if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) + prompt_Printf(arg->prompt, "Disabled"); + else + prompt_Printf(arg->prompt, "%ld secs", + arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); + + prompt_Printf(arg->prompt, ", CCP: "); + if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) + prompt_Printf(arg->prompt, "Disabled"); + else + prompt_Printf(arg->prompt, "%ld secs", + arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); + + prompt_Printf(arg->prompt, "\n"); + + return 0; +} + +static int +ShowVersion(struct cmdargs const *arg) +{ + prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate); + return 0; +} + +static int +ShowProtocolStats(struct cmdargs const *arg) +{ + struct link *l = command_ChooseLink(arg); + + prompt_Printf(arg->prompt, "%s:\n", l->name); + link_ReportProtocolStatus(l, arg->prompt); + return 0; +} + +static struct cmdtab const ShowCommands[] = { + {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, + "bundle details", "show bundle"}, + {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, + "CCP status", "show cpp"}, + {"compress", NULL, sl_Show, LOCAL_AUTH, + "VJ compression stats", "show compress"}, + {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, + "escape characters", "show escape"}, + {"filter", NULL, filter_Show, LOCAL_AUTH, + "packet filters", "show filter [in|out|dial|alive]"}, + {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, + "HDLC errors", "show hdlc"}, + {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, + "IPCP status", "show ipcp"}, + {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, + "LCP status", "show lcp"}, + {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, + "(high-level) link info", "show link"}, + {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, + "available link names", "show links"}, + {"log", NULL, log_ShowLevel, LOCAL_AUTH, + "log levels", "show log"}, + {"mem", NULL, mbuf_Show, LOCAL_AUTH, + "mbuf allocations", "show mem"}, + {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX, + "(low-level) link info", "show modem"}, + {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, + "multilink setup", "show mp"}, + {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, + "protocol summary", "show proto"}, + {"route", NULL, route_Show, LOCAL_AUTH, + "routing table", "show route"}, + {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, + "STOPPED timeout", "show stopped"}, + {"timers", NULL, ShowTimerList, LOCAL_AUTH, + "alarm timers", "show timers"}, + {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, + "version string", "show version"}, + {"who", NULL, log_ShowWho, LOCAL_AUTH, + "client list", "show who"}, + {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, + "Display this message", "show help|? [command]", ShowCommands}, + {NULL, NULL, NULL}, +}; + +static struct cmdtab const * +FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) +{ + int nmatch; + int len; + struct cmdtab const *found; + + found = NULL; + len = strlen(str); + nmatch = 0; + while (cmds->func) { + if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { + if (cmds->name[len] == '\0') { + *pmatch = 1; + return cmds; + } + nmatch++; + found = cmds; + } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { + if (cmds->alias[len] == '\0') { + *pmatch = 1; + return cmds; + } + nmatch++; + found = cmds; + } + cmds++; + } + *pmatch = nmatch; + return found; +} + +static const char * +mkPrefix(int argc, char const *const *argv, char *tgt, int sz) +{ + int f, tlen, len; + + tlen = 0; + for (f = 0; f < argc && tlen < sz - 2; f++) { + if (f) + tgt[tlen++] = ' '; + len = strlen(argv[f]); + if (len > sz - tlen - 1) + len = sz - tlen - 1; + strncpy(tgt+tlen, argv[f], len); + tlen += len; + } + tgt[tlen] = '\0'; + return tgt; +} + +static int +FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, + char const *const *argv, struct prompt *prompt, struct datalink *cx) +{ + struct cmdtab const *cmd; + int val = 1; + int nmatch; + struct cmdargs arg; + char prefix[100]; + + cmd = FindCommand(cmds, argv[argn], &nmatch); + if (nmatch > 1) + log_Printf(LogWARN, "%s: Ambiguous command\n", + mkPrefix(argn+1, argv, prefix, sizeof prefix)); + else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { + if ((cmd->lauth & LOCAL_CX) && !cx) + /* We've got no context, but we require it */ + cx = bundle2datalink(bundle, NULL); + + if ((cmd->lauth & LOCAL_CX) && !cx) + log_Printf(LogWARN, "%s: No context (use the `link' command)\n", + mkPrefix(argn+1, argv, prefix, sizeof prefix)); + else { + if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { + log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", + mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); + cx = NULL; + } + arg.cmdtab = cmds; + arg.cmd = cmd; + arg.argc = argc; + arg.argn = argn+1; + arg.argv = argv; + arg.bundle = bundle; + arg.cx = cx; + arg.prompt = prompt; + val = (*cmd->func) (&arg); + } + } else + log_Printf(LogWARN, "%s: Invalid command\n", + mkPrefix(argn+1, argv, prefix, sizeof prefix)); + + if (val == -1) + log_Printf(LogWARN, "Usage: %s\n", cmd->syntax); + else if (val) + log_Printf(LogWARN, "%s: Failed %d\n", + mkPrefix(argn+1, argv, prefix, sizeof prefix), val); + + return val; +} + +int +command_Interpret(char *buff, int nb, char *argv[MAXARGS]) +{ + char *cp; + + if (nb > 0) { + cp = buff + strcspn(buff, "\r\n"); + if (cp) + *cp = '\0'; + return MakeArgs(buff, argv, MAXARGS); + } + return 0; +} + +static int +arghidden(int argc, char const *const *argv, int n) +{ + /* Is arg n of the given command to be hidden from the log ? */ + + /* set authkey xxxxx */ + /* set key xxxxx */ + if (n == 2 && !strncasecmp(argv[0], "se", 2) && + (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) + return 1; + + /* passwd xxxxx */ + if (n == 1 && !strncasecmp(argv[0], "p", 1)) + return 1; + + /* set server port xxxxx .... */ + if (n == 3 && !strncasecmp(argv[0], "se", 2) && + !strncasecmp(argv[1], "se", 2)) + return 1; + + return 0; +} + +void +command_Run(struct bundle *bundle, int argc, char const *const *argv, + struct prompt *prompt, const char *label, struct datalink *cx) +{ + if (argc > 0) { + if (log_IsKept(LogCOMMAND)) { + static char buf[LINE_LEN]; + int f, n; + + *buf = '\0'; + if (label) { + strncpy(buf, label, sizeof buf - 3); + buf[sizeof buf - 3] = '\0'; + strcat(buf, ": "); + } + n = strlen(buf); + for (f = 0; f < argc; f++) { + if (n < sizeof buf - 1 && f) + buf[n++] = ' '; + if (arghidden(argc, argv, f)) + strncpy(buf+n, "********", sizeof buf - n - 1); + else + strncpy(buf+n, argv[f], sizeof buf - n - 1); + n += strlen(buf+n); + } + log_Printf(LogCOMMAND, "%s\n", buf); + } + FindExec(bundle, Commands, argc, 0, argv, prompt, cx); + } +} + +void +command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, + const char *label) +{ + int argc; + char *argv[MAXARGS]; + + argc = command_Interpret(buff, nb, argv); + command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); +} + +static int +ShowCommand(struct cmdargs const *arg) +{ + if (!arg->prompt) + log_Printf(LogWARN, "show: Cannot show without a prompt\n"); + else if (arg->argc > arg->argn) + FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, + arg->prompt, arg->cx); + else + prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); + + return 0; +} + +static int +TerminalCommand(struct cmdargs const *arg) +{ + if (!arg->prompt) { + log_Printf(LogWARN, "term: Need a prompt\n"); + return 1; + } + + if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { + prompt_Printf(arg->prompt, "LCP state is [%s]\n", + State2Nam(arg->cx->physical->link.lcp.fsm.state)); + return 1; + } + + datalink_Up(arg->cx, 0, 0); + prompt_TtyTermMode(arg->prompt, arg->cx); + return 0; +} + +static int +QuitCommand(struct cmdargs const *arg) +{ + if (!arg->prompt || prompt_IsController(arg->prompt) || + (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && + (arg->prompt->auth & LOCAL_AUTH))) + Cleanup(EX_NORMAL); + if (arg->prompt) + prompt_Destroy(arg->prompt, 1); + + return 0; +} + +static int +OpenCommand(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn) + bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); + else if (arg->argc == arg->argn + 1) { + if (!strcasecmp(arg->argv[arg->argn], "lcp")) { + struct datalink *cx = arg->cx ? + arg->cx : bundle2datalink(arg->bundle, NULL); + if (cx) { + if (cx->physical->link.lcp.fsm.state == ST_OPENED) + fsm_Reopen(&cx->physical->link.lcp.fsm); + else + bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); + } else + log_Printf(LogWARN, "open lcp: You must specify a link\n"); + } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { + struct fsm *fp; + + fp = &command_ChooseLink(arg)->ccp.fsm; + if (fp->link->lcp.fsm.state != ST_OPENED) + log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); + else if (fp->state == ST_OPENED) + fsm_Reopen(fp); + else { + fp->open_mode = 0; /* Not passive any more */ + if (fp->state == ST_STOPPED) { + fsm_Down(fp); + fsm_Up(fp); + } else { + fsm_Up(fp); + fsm_Open(fp); + } + } + } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { + if (arg->cx) + log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); + if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) + fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); + else + bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); + } else + return -1; + } else + return -1; + + return 0; +} + +static int +CloseCommand(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn) + bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); + else if (arg->argc == arg->argn + 1) { + if (!strcasecmp(arg->argv[arg->argn], "lcp")) + bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); + else if (!strcasecmp(arg->argv[arg->argn], "ccp") || + !strcasecmp(arg->argv[arg->argn], "ccp!")) { + struct fsm *fp; + + fp = &command_ChooseLink(arg)->ccp.fsm; + if (fp->state == ST_OPENED) { + fsm_Close(fp); + if (arg->argv[arg->argn][3] == '!') + fp->open_mode = 0; /* Stay ST_CLOSED */ + else + fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ + } + } else + return -1; + } else + return -1; + + return 0; +} + +static int +DownCommand(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn) { + if (arg->cx) + datalink_Down(arg->cx, CLOSE_STAYDOWN); + else + bundle_Down(arg->bundle, CLOSE_STAYDOWN); + } else if (arg->argc == arg->argn + 1) { + if (!strcasecmp(arg->argv[arg->argn], "lcp")) { + if (arg->cx) + datalink_Down(arg->cx, CLOSE_LCP); + else + bundle_Down(arg->bundle, CLOSE_LCP); + } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { + struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : + &arg->bundle->ncp.mp.link.ccp.fsm; + fsm2initial(fp); + } else + return -1; + } else + return -1; + + return 0; +} + +static int +SetModemSpeed(struct cmdargs const *arg) +{ + long speed; + char *end; + + if (arg->argc > arg->argn && *arg->argv[arg->argn]) { + if (arg->argc > arg->argn+1) { + log_Printf(LogWARN, "SetModemSpeed: Too many arguments"); + return -1; + } + if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { + physical_SetSync(arg->cx->physical); + return 0; + } + end = NULL; + speed = strtol(arg->argv[arg->argn], &end, 10); + if (*end) { + log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", + arg->argv[arg->argn]); + return -1; + } + if (physical_SetSpeed(arg->cx->physical, speed)) + return 0; + log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); + } else + log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); + + return -1; +} + +static int +SetStoppedTimeout(struct cmdargs const *arg) +{ + struct link *l = &arg->cx->physical->link; + + l->lcp.fsm.StoppedTimer.load = 0; + l->ccp.fsm.StoppedTimer.load = 0; + if (arg->argc <= arg->argn+2) { + if (arg->argc > arg->argn) { + l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; + if (arg->argc > arg->argn+1) + l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; + } + return 0; + } + return -1; +} + +#define ismask(x) \ + (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3) + +static int +SetServer(struct cmdargs const *arg) +{ + int res = -1; + + if (arg->argc > arg->argn && arg->argc < arg->argn+4) { + const char *port, *passwd, *mask; + + /* What's what ? */ + port = arg->argv[arg->argn]; + if (arg->argc == arg->argn + 2) { + passwd = arg->argv[arg->argn+1]; + mask = NULL; + } else if (arg->argc == arg->argn + 3) { + passwd = arg->argv[arg->argn+1]; + mask = arg->argv[arg->argn+2]; + if (!ismask(mask)) + return -1; + } else if (strcasecmp(port, "none") == 0) { + if (server_Close(arg->bundle)) + log_Printf(LogPHASE, "Disabled server port.\n"); + return 0; + } else + return -1; + + strncpy(server.passwd, passwd, sizeof server.passwd - 1); + server.passwd[sizeof server.passwd - 1] = '\0'; + + if (*port == '/') { + mode_t imask; + char *ptr, name[LINE_LEN + 12]; + + if (mask != NULL) { + unsigned m; + + if (sscanf(mask, "%o", &m) == 1) + imask = m; + else + return -1; + } else + imask = (mode_t)-1; + + ptr = strstr(port, "%d"); + if (ptr) { + snprintf(name, sizeof name, "%.*s%d%s", + (int)(ptr - port), port, arg->bundle->unit, ptr + 2); + port = name; + } + res = server_LocalOpen(arg->bundle, port, imask); + } else { + int iport, add = 0; + + if (mask != NULL) + return -1; + + if (*port == '+') { + port++; + add = 1; + } + if (strspn(port, "0123456789") != strlen(port)) { + struct servent *s; + + if ((s = getservbyname(port, "tcp")) == NULL) { + iport = 0; + log_Printf(LogWARN, "%s: Invalid port or service\n", port); + } else + iport = ntohs(s->s_port); + } else + iport = atoi(port); + + if (iport) { + if (add) + iport += arg->bundle->unit; + res = server_TcpOpen(arg->bundle, iport); + } else + res = -1; + } + } + + return res; +} + +static int +SetModemParity(struct cmdargs const *arg) +{ + return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical, + arg->argv[arg->argn]) : -1; +} + +static int +SetEscape(struct cmdargs const *arg) +{ + int code; + int argc = arg->argc - arg->argn; + char const *const *argv = arg->argv + arg->argn; + + for (code = 0; code < 33; code++) + arg->cx->physical->async.cfg.EscMap[code] = 0; + + while (argc-- > 0) { + sscanf(*argv++, "%x", &code); + code &= 0xff; + arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); + arg->cx->physical->async.cfg.EscMap[32] = 1; + } + return 0; +} + +static struct in_addr +GetIpAddr(const char *cp) +{ + struct hostent *hp; + struct in_addr ipaddr; + + if (inet_aton(cp, &ipaddr) == 0) { + hp = gethostbyname(cp); + if (hp && hp->h_addrtype == AF_INET) + memcpy(&ipaddr, hp->h_addr, hp->h_length); + else + ipaddr.s_addr = 0; + } + return (ipaddr); +} + +static int +SetInterfaceAddr(struct cmdargs const *arg) +{ + struct ipcp *ipcp = &arg->bundle->ncp.ipcp; + const char *hisaddr; + + hisaddr = NULL; + ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; + ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; + + if (arg->argc > arg->argn + 4) + return -1; + + ipcp->cfg.HaveTriggerAddress = 0; + ipcp->cfg.netmask.s_addr = INADDR_ANY; + iplist_reset(&ipcp->cfg.peer_list); + + if (arg->argc > arg->argn) { + if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn, + &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask, + &ipcp->cfg.my_range.width)) + return 1; + if (arg->argc > arg->argn+1) { + hisaddr = arg->argv[arg->argn+1]; + if (arg->argc > arg->argn+2) { + ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]); + if (arg->argc > arg->argn+3) { + ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); + ipcp->cfg.HaveTriggerAddress = 1; + } + } + } + } + + /* + * For backwards compatibility, 0.0.0.0 means any address. + */ + if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) { + ipcp->cfg.my_range.mask.s_addr = INADDR_ANY; + ipcp->cfg.my_range.width = 0; + } + ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr; + + if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { + ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY; + ipcp->cfg.peer_range.width = 0; + } + + if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, + arg->bundle->phys_type.all & PHYS_AUTO)) + return 4; + + return 0; +} + +static int +SetVariable(struct cmdargs const *arg) +{ + long long_val, param = (long)arg->cmd->args; + int mode, dummyint; + const char *argp; + struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ + const char *err = NULL; + struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ + struct in_addr dummyaddr, *addr; + + if (arg->argc > arg->argn) + argp = arg->argv[arg->argn]; + else + argp = ""; + + if ((arg->cmd->lauth & LOCAL_CX) && !cx) { + log_Printf(LogWARN, "set %s: No context (use the `link' command)\n", + arg->cmd->name); + return 1; + } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { + log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", + arg->cmd->name, cx->name); + cx = NULL; + } + + switch (param) { + case VAR_AUTHKEY: + if (bundle_Phase(arg->bundle) == PHASE_DEAD) { + strncpy(arg->bundle->cfg.auth.key, argp, + sizeof arg->bundle->cfg.auth.key - 1); + arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; + } else { + err = "set authkey: Only available at phase DEAD\n"; + log_Printf(LogWARN, err); + } + break; + + case VAR_AUTHNAME: + if (bundle_Phase(arg->bundle) == PHASE_DEAD) { + strncpy(arg->bundle->cfg.auth.name, argp, + sizeof arg->bundle->cfg.auth.name - 1); + arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0'; + } else { + err = "set authname: Only available at phase DEAD\n"; + log_Printf(LogWARN, err); + } + break; + + case VAR_AUTOLOAD: + if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) { + arg->bundle->autoload.running = 1; + arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]); + arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]); + if (arg->argc == arg->argn + 4) { + arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]); + arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]); + } else { + arg->bundle->cfg.autoload.min.timeout = 0; + arg->bundle->cfg.autoload.min.packets = 0; + } + } else { + err = "Set autoload requires two or four arguments\n"; + log_Printf(LogWARN, err); + } + break; + + case VAR_DIAL: + strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); + cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; + break; + + case VAR_LOGIN: + strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); + cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; + break; + + case VAR_WINSIZE: + if (arg->argc > arg->argn) { + l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); + if (l->ccp.cfg.deflate.out.winsize < 8 || + l->ccp.cfg.deflate.out.winsize > 15) { + log_Printf(LogWARN, "%d: Invalid outgoing window size\n", + l->ccp.cfg.deflate.out.winsize); + l->ccp.cfg.deflate.out.winsize = 15; + } + if (arg->argc > arg->argn+1) { + l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); + if (l->ccp.cfg.deflate.in.winsize < 8 || + l->ccp.cfg.deflate.in.winsize > 15) { + log_Printf(LogWARN, "%d: Invalid incoming window size\n", + l->ccp.cfg.deflate.in.winsize); + l->ccp.cfg.deflate.in.winsize = 15; + } + } else + l->ccp.cfg.deflate.in.winsize = 0; + } else { + err = "No window size specified\n"; + log_Printf(LogWARN, err); + } + break; + + case VAR_DEVICE: + physical_SetDeviceList(cx->physical, arg->argc - arg->argn, + arg->argv + arg->argn); + break; + + case VAR_ACCMAP: + if (arg->argc > arg->argn) { + u_long ulong_val; + sscanf(argp, "%lx", &ulong_val); + cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; + } else { + err = "No accmap specified\n"; + log_Printf(LogWARN, err); + } + break; + + case VAR_MODE: + mode = Nam2mode(argp); + if (mode == PHYS_NONE || mode == PHYS_ALL) { + log_Printf(LogWARN, "%s: Invalid mode\n", argp); + return -1; + } + bundle_SetMode(arg->bundle, cx, mode); + break; + + case VAR_MRRU: + if (bundle_Phase(arg->bundle) != PHASE_DEAD) { + log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n"); + return 1; + } + long_val = atol(argp); + if (long_val && long_val < MIN_MRU) { + log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); + return 1; + } else if (long_val > MAX_MRU) { + log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); + return 1; + } else + arg->bundle->ncp.mp.cfg.mrru = long_val; + break; + + case VAR_MRU: + long_val = atol(argp); + if (long_val == 0) + l->lcp.cfg.mru = DEF_MRU; + else if (long_val < MIN_MRU) { + log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); + return 1; + } else if (long_val > MAX_MRU) { + log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); + return 1; + } else + l->lcp.cfg.mru = long_val; + break; + + case VAR_MTU: + long_val = atol(argp); + if (long_val && long_val < MIN_MTU) { + log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); + return 1; + } else if (long_val > MAX_MTU) { + log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); + return 1; + } else + arg->bundle->cfg.mtu = long_val; + break; + + case VAR_OPENMODE: + if (strcasecmp(argp, "active") == 0) + cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? + atoi(arg->argv[arg->argn+1]) : 1; + else if (strcasecmp(argp, "passive") == 0) + cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; + else { + err = "%s: Invalid openmode\n"; + log_Printf(LogWARN, err, argp); + } + break; + + case VAR_PHONE: + strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); + cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; + cx->phone.alt = cx->phone.next = NULL; + break; + + case VAR_HANGUP: + strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); + cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; + break; + + case VAR_IDLETIMEOUT: + if (arg->argc > arg->argn+1) + err = "Too many idle timeout values\n"; + else if (arg->argc == arg->argn+1) + bundle_SetIdleTimer(arg->bundle, atoi(argp)); + if (err) + log_Printf(LogWARN, err); + break; + + case VAR_LQRPERIOD: + long_val = atol(argp); + if (long_val < MIN_LQRPERIOD) { + log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", + long_val, MIN_LQRPERIOD); + return 1; + } else + l->lcp.cfg.lqrperiod = long_val; + break; + + case VAR_LCPRETRY: + long_val = atol(argp); + if (long_val < MIN_FSMRETRY) { + log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + return 1; + } else + cx->physical->link.lcp.cfg.fsmretry = long_val; + break; + + case VAR_CHAPRETRY: + long_val = atol(argp); + if (long_val < MIN_FSMRETRY) { + log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + return 1; + } else + cx->chap.auth.cfg.fsmretry = long_val; + break; + + case VAR_PAPRETRY: + long_val = atol(argp); + if (long_val < MIN_FSMRETRY) { + log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + return 1; + } else + cx->pap.cfg.fsmretry = long_val; + break; + + case VAR_CCPRETRY: + long_val = atol(argp); + if (long_val < MIN_FSMRETRY) { + log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + return 1; + } else + l->ccp.cfg.fsmretry = long_val; + break; + + case VAR_IPCPRETRY: + long_val = atol(argp); + if (long_val < MIN_FSMRETRY) { + log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + return 1; + } else + arg->bundle->ncp.ipcp.cfg.fsmretry = long_val; + break; + + case VAR_NBNS: + case VAR_DNS: + if (param == VAR_DNS) + addr = arg->bundle->ncp.ipcp.cfg.ns.dns; + else + addr = arg->bundle->ncp.ipcp.cfg.ns.nbns; + + addr[0].s_addr = addr[1].s_addr = INADDR_ANY; + + if (arg->argc > arg->argn) { + ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn, + addr, &dummyaddr, &dummyint); + if (arg->argc > arg->argn+1) + ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1, + addr + 1, &dummyaddr, &dummyint); + + if (addr[1].s_addr == INADDR_ANY) + addr[1].s_addr = addr[0].s_addr; + if (addr[0].s_addr == INADDR_ANY) + addr[0].s_addr = addr[1].s_addr; + } + break; + + case VAR_CALLBACK: + cx->cfg.callback.opmask = 0; + for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { + if (!strcasecmp(arg->argv[dummyint], "auth")) + cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); + else if (!strcasecmp(arg->argv[dummyint], "cbcp")) + cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); + else if (!strcasecmp(arg->argv[dummyint], "e.164")) { + if (dummyint == arg->argc - 1) + log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); + else { + cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); + strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], + sizeof cx->cfg.callback.msg - 1); + cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; + } + } else if (!strcasecmp(arg->argv[dummyint], "none")) + cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); + else + return -1; + } + if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) + cx->cfg.callback.opmask = 0; + break; + + case VAR_CBCP: + cx->cfg.cbcp.delay = 0; + *cx->cfg.cbcp.phone = '\0'; + cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; + if (arg->argc > arg->argn) { + strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], + sizeof cx->cfg.cbcp.phone - 1); + cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; + if (arg->argc > arg->argn + 1) { + cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); + if (arg->argc > arg->argn + 2) { + long_val = atol(arg->argv[arg->argn + 2]); + if (long_val < MIN_FSMRETRY) + log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", + long_val, MIN_FSMRETRY); + else + cx->cfg.cbcp.fsmretry = long_val; + } + } + } + break; + + case VAR_CHOKED: + arg->bundle->cfg.choked.timeout = atoi(argp); + if (arg->bundle->cfg.choked.timeout <= 0) + arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; + break; + + } + + return err ? 1 : 0; +} + +static int +SetCtsRts(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn+1) { + if (strcmp(arg->argv[arg->argn], "on") == 0) + physical_SetRtsCts(arg->cx->physical, 1); + else if (strcmp(arg->argv[arg->argn], "off") == 0) + physical_SetRtsCts(arg->cx->physical, 0); + else + return -1; + return 0; + } + return -1; +} + +static struct cmdtab const SetCommands[] = { + {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, + {"authkey", "key", SetVariable, LOCAL_AUTH, + "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, + {"authname", NULL, SetVariable, LOCAL_AUTH, + "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, + {"autoload", NULL, SetVariable, LOCAL_AUTH, + "auto link [de]activation", "set autoload maxtime maxload mintime minload", + (const void *)VAR_AUTOLOAD}, + {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "callback control", "set callback [none|auth|cbcp|" + "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, + {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", + (const void *)VAR_CBCP}, + {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, + "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY}, + {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY}, + {"choked", NULL, SetVariable, LOCAL_AUTH, + "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, + {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX, + "Use hardware flow control", "set ctsrts [on|off]"}, + {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, + "deflate window sizes", "set deflate out-winsize in-winsize", + (const void *) VAR_WINSIZE}, + {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, + "modem device name", "set device|line device-name[,device-name]", + (const void *) VAR_DEVICE}, + {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, + {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", + "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, + {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, + "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, + {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, + "escape characters", "set escape hex-digit ..."}, + {"filter", NULL, filter_Set, LOCAL_AUTH, + "packet filters", "set filter alive|dial|in|out rule-no permit|deny " + "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] " + "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, + {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, + {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", + "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, + {"ipcpretry", NULL, SetVariable, LOCAL_AUTH, + "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY}, + {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY}, + {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", + "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|" + "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."}, + {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "login script", "set login chat-script", (const void *) VAR_LOGIN}, + {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, + "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, + {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", + "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, + {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", + "set mrru value", (const void *)VAR_MRRU}, + {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, + "MRU value", "set mru value", (const void *)VAR_MRU}, + {"mtu", NULL, SetVariable, LOCAL_AUTH, + "interface MTU value", "set mtu value", (const void *)VAR_MTU}, + {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", + "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, + {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", + "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, + {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, + "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY}, + {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX, + "modem parity", "set parity [odd|even|none]"}, + {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", + "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, + {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, + "Reconnect timeout", "set reconnect value ntries"}, + {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, + "Redial timeout", "set redial value|random[.value|random] [attempts]"}, + {"server", "socket", SetServer, LOCAL_AUTH, + "server port", "set server|socket TcpPort|LocalName|none password [mask]"}, + {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, + "modem speed", "set speed value"}, + {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, + "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, + {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", + "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, + {"vj", NULL, ipcp_vjset, LOCAL_AUTH, + "vj values", "set vj slots|slotcomp [value]"}, + {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX, + "datalink weighting", "set weight n"}, + {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Display this message", "set help|? [command]", SetCommands}, + {NULL, NULL, NULL}, +}; + +static int +SetCommand(struct cmdargs const *arg) +{ + if (arg->argc > arg->argn) + FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, + arg->prompt, arg->cx); + else if (arg->prompt) + prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for" + " syntax help.\n"); + else + log_Printf(LogWARN, "set command must have arguments\n"); + + return 0; +} + + +static int +AddCommand(struct cmdargs const *arg) +{ + struct in_addr dest, gateway, netmask; + int gw, addrs; + + if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) + return -1; + + addrs = 0; + if (arg->argc == arg->argn+2) { + if (!strcasecmp(arg->argv[arg->argn], "default")) + dest.s_addr = netmask.s_addr = INADDR_ANY; + else { + int width; + + if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn, + &dest, &netmask, &width)) + return -1; + if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) + addrs = ROUTE_DSTMYADDR; + else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) + addrs = ROUTE_DSTHISADDR; + } + gw = 1; + } else { + if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { + addrs = ROUTE_DSTMYADDR; + dest = arg->bundle->ncp.ipcp.my_ip; + } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { + addrs = ROUTE_DSTHISADDR; + dest = arg->bundle->ncp.ipcp.peer_ip; + } else + dest = GetIpAddr(arg->argv[arg->argn]); + netmask = GetIpAddr(arg->argv[arg->argn+1]); + gw = 2; + } + + if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) { + gateway = arg->bundle->ncp.ipcp.peer_ip; + addrs |= ROUTE_GWHISADDR; + } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0) + gateway.s_addr = INADDR_ANY; + else + gateway = GetIpAddr(arg->argv[arg->argn+gw]); + + if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask, + arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)) + route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway); + + return 0; +} + +static int +DeleteCommand(struct cmdargs const *arg) +{ + struct in_addr dest, none; + int addrs; + + if (arg->argc == arg->argn+1) { + if(strcasecmp(arg->argv[arg->argn], "all") == 0) { + route_IfDelete(arg->bundle, 0); + route_DeleteAll(&arg->bundle->ncp.ipcp.route); + } else { + addrs = 0; + if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { + dest = arg->bundle->ncp.ipcp.my_ip; + addrs = ROUTE_DSTMYADDR; + } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { + dest = arg->bundle->ncp.ipcp.peer_ip; + addrs = ROUTE_DSTHISADDR; + } else { + if (strcasecmp(arg->argv[arg->argn], "default") == 0) + dest.s_addr = INADDR_ANY; + else + dest = GetIpAddr(arg->argv[arg->argn]); + addrs = ROUTE_STATIC; + } + none.s_addr = INADDR_ANY; + bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none, + arg->cmd->args ? 1 : 0, 0); + route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest); + } + } else + return -1; + + return 0; +} + +#ifndef NOALIAS +static struct cmdtab const AliasCommands[] = +{ + {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH, + "static address translation", "alias addr [addr_local addr_alias]"}, + {"deny_incoming", NULL, AliasOption, LOCAL_AUTH, + "stop incoming connections", "alias deny_incoming [yes|no]", + (const void *) PKT_ALIAS_DENY_INCOMING}, + {"enable", NULL, AliasEnable, LOCAL_AUTH, + "enable IP aliasing", "alias enable [yes|no]"}, + {"log", NULL, AliasOption, LOCAL_AUTH, + "log aliasing link creation", "alias log [yes|no]", + (const void *) PKT_ALIAS_LOG}, + {"port", NULL, alias_RedirectPort, LOCAL_AUTH, + "port redirection", "alias port [proto addr_local:port_local port_alias]"}, + {"same_ports", NULL, AliasOption, LOCAL_AUTH, + "try to leave port numbers unchanged", "alias same_ports [yes|no]", + (const void *) PKT_ALIAS_SAME_PORTS}, + {"unregistered_only", NULL, AliasOption, LOCAL_AUTH, + "alias unregistered (private) IP address space only", + "alias unregistered_only [yes|no]", + (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, + {"use_sockets", NULL, AliasOption, LOCAL_AUTH, + "allocate host sockets", "alias use_sockets [yes|no]", + (const void *) PKT_ALIAS_USE_SOCKETS}, + {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Display this message", "alias help|? [command]", AliasCommands}, + {NULL, NULL, NULL}, +}; + + +static int +AliasCommand(struct cmdargs const *arg) +{ + if (arg->argc > arg->argn) + FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv, + arg->prompt, arg->cx); + else if (arg->prompt) + prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help" + " <option>' for syntax help.\n"); + else + log_Printf(LogWARN, "alias command must have arguments\n"); + + return 0; +} + +static int +AliasEnable(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn+1) { + if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { + arg->bundle->AliasEnabled = 1; + return 0; + } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { + arg->bundle->AliasEnabled = 0; + return 0; + } + } + + return -1; +} + + +static int +AliasOption(struct cmdargs const *arg) +{ + long param = (long)arg->cmd->args; + + if (arg->argc == arg->argn+1) { + if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { + if (arg->bundle->AliasEnabled) { + PacketAliasSetMode(param, param); + return 0; + } + log_Printf(LogWARN, "alias not enabled\n"); + } else if (strcmp(arg->argv[arg->argn], "no") == 0) { + if (arg->bundle->AliasEnabled) { + PacketAliasSetMode(0, param); + return 0; + } + log_Printf(LogWARN, "alias not enabled\n"); + } + } + return -1; +} +#endif /* #ifndef NOALIAS */ + +static struct cmdtab const AllowCommands[] = { + {"modes", "mode", AllowModes, LOCAL_AUTH, + "Only allow certain ppp modes", "allow modes mode..."}, + {"users", "user", AllowUsers, LOCAL_AUTH, + "Allow users access to ppp", "allow users logname..."}, + {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Display this message", "allow help|? [command]", AllowCommands}, + {NULL, NULL, NULL}, +}; + +static int +AllowCommand(struct cmdargs const *arg) +{ + /* arg->bundle may be NULL (see system_IsValid()) ! */ + if (arg->argc > arg->argn) + FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv, + arg->prompt, arg->cx); + else if (arg->prompt) + prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'" + " for syntax help.\n"); + else + log_Printf(LogWARN, "allow command must have arguments\n"); + + return 0; +} + +static int +LinkCommand(struct cmdargs const *arg) +{ + if (arg->argc > arg->argn+1) { + char namelist[LINE_LEN]; + struct datalink *cx; + char *name; + int result = 0; + + if (!strcmp(arg->argv[arg->argn], "*")) { + struct datalink *dl; + + cx = arg->bundle->links; + while (cx) { + /* Watch it, the command could be a ``remove'' */ + dl = cx->next; + FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, + arg->prompt, cx); + for (cx = arg->bundle->links; cx; cx = cx->next) + if (cx == dl) + break; /* Pointer's still valid ! */ + } + } else { + strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); + namelist[sizeof namelist - 1] = '\0'; + for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) + if (!bundle2datalink(arg->bundle, name)) { + log_Printf(LogWARN, "link: %s: Invalid link name\n", name); + return 1; + } + + strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); + namelist[sizeof namelist - 1] = '\0'; + for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { + cx = bundle2datalink(arg->bundle, name); + if (cx) + FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, + arg->prompt, cx); + else { + log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); + result++; + } + } + } + return result; + } + + log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax); + return 2; +} + +struct link * +command_ChooseLink(struct cmdargs const *arg) +{ + if (arg->cx) + return &arg->cx->physical->link; + else if (!arg->bundle->ncp.mp.cfg.mrru) { + struct datalink *dl = bundle2datalink(arg->bundle, NULL); + if (dl) + return &dl->physical->link; + } + return &arg->bundle->ncp.mp.link; +} + +static const char * +ident_cmd(const char *cmd, unsigned *keep, unsigned *add) +{ + const char *result; + + switch (*cmd) { + case 'A': + case 'a': + result = "accept"; + *keep = NEG_MYMASK; + *add = NEG_ACCEPTED; + break; + case 'D': + case 'd': + switch (cmd[1]) { + case 'E': + case 'e': + result = "deny"; + *keep = NEG_MYMASK; + *add = 0; + break; + case 'I': + case 'i': + result = "disable"; + *keep = NEG_HISMASK; + *add = 0; + break; + default: + return NULL; + } + break; + case 'E': + case 'e': + result = "enable"; + *keep = NEG_HISMASK; + *add = NEG_ENABLED; + break; + default: + return NULL; + } + + return result; +} + +static int +OptSet(struct cmdargs const *arg) +{ + int bit = (int)(long)arg->cmd->args; + const char *cmd; + unsigned keep; /* Keep these bits */ + unsigned add; /* Add these bits */ + + if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) + return 1; + + if (add) + arg->bundle->cfg.opt |= bit; + else + arg->bundle->cfg.opt &= ~bit; + return 0; +} + +static int +NegotiateSet(struct cmdargs const *arg) +{ + long param = (long)arg->cmd->args; + struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ + struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ + const char *cmd; + unsigned keep; /* Keep these bits */ + unsigned add; /* Add these bits */ + + if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) + return 1; + + if ((arg->cmd->lauth & LOCAL_CX) && !cx) { + log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", + cmd, arg->cmd->name); + return 2; + } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { + log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", + cmd, arg->cmd->name, cx->name); + cx = NULL; + } + + switch (param) { + case NEG_ACFCOMP: + cx->physical->link.lcp.cfg.acfcomp &= keep; + cx->physical->link.lcp.cfg.acfcomp |= add; + break; + case NEG_CHAP: + cx->physical->link.lcp.cfg.chap &= keep; + cx->physical->link.lcp.cfg.chap |= add; + break; + case NEG_DEFLATE: + l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; + l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; + break; + case NEG_DNS: + arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; + arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; + break; + case NEG_LQR: + cx->physical->link.lcp.cfg.lqr &= keep; + cx->physical->link.lcp.cfg.lqr |= add; + break; + case NEG_PAP: + cx->physical->link.lcp.cfg.pap &= keep; + cx->physical->link.lcp.cfg.pap |= add; + break; + case NEG_PPPDDEFLATE: + l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; + l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; + break; + case NEG_PRED1: + l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; + l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; + break; + case NEG_PROTOCOMP: + cx->physical->link.lcp.cfg.protocomp &= keep; + cx->physical->link.lcp.cfg.protocomp |= add; + break; + case NEG_SHORTSEQ: + if (bundle_Phase(arg->bundle) != PHASE_DEAD) + log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n"); + else { + arg->bundle->ncp.mp.cfg.shortseq &= keep; + arg->bundle->ncp.mp.cfg.shortseq |= add; + } + break; + case NEG_VJCOMP: + arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; + arg->bundle->ncp.ipcp.cfg.vj.neg |= add; + break; + } + + return 0; +} + +static struct cmdtab const NegotiateCommands[] = { + {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", + "disable|enable", (const void *)OPT_IDCHECK}, + {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", + "disable|enable", (const void *)OPT_LOOPBACK}, + {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", + "disable|enable", (const void *)OPT_PASSWDAUTH}, + {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry", + "disable|enable", (const void *)OPT_PROXY}, + {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", + "disable|enable", (const void *)OPT_SROUTES}, + {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", + "disable|enable", (const void *)OPT_THROUGHPUT}, + {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", + "disable|enable", (const void *)OPT_UTMP}, + +#define OPT_MAX 7 /* accept/deny allowed below and not above */ + + {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, + "Address & Control field compression", "accept|deny|disable|enable", + (const void *)NEG_ACFCOMP}, + {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, + "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", + (const void *)NEG_CHAP}, + {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, + "Deflate compression", "accept|deny|disable|enable", + (const void *)NEG_DEFLATE}, + {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, + "Deflate (type 24) compression", "accept|deny|disable|enable", + (const void *)NEG_PPPDDEFLATE}, + {"dns", NULL, NegotiateSet, LOCAL_AUTH, + "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, + {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, + "Link Quality Reports", "accept|deny|disable|enable", + (const void *)NEG_LQR}, + {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, + "Password Authentication protocol", "accept|deny|disable|enable", + (const void *)NEG_PAP}, + {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, + "Predictor 1 compression", "accept|deny|disable|enable", + (const void *)NEG_PRED1}, + {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, + "Protocol field compression", "accept|deny|disable|enable", + (const void *)NEG_PROTOCOMP}, + {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, + "MP Short Sequence Numbers", "accept|deny|disable|enable", + (const void *)NEG_SHORTSEQ}, + {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, + "Van Jacobson header compression", "accept|deny|disable|enable", + (const void *)NEG_VJCOMP}, + {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, + "Display this message", "accept|deny|disable|enable help|? [value]", + NegotiateCommands}, + {NULL, NULL, NULL}, +}; + +static int +NegotiateCommand(struct cmdargs const *arg) +{ + if (arg->argc > arg->argn) { + char const *argv[3]; + unsigned keep, add; + int n; + + if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) + return -1; + argv[2] = NULL; + + for (n = arg->argn; n < arg->argc; n++) { + argv[1] = arg->argv[n]; + FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? + 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); + } + } else if (arg->prompt) + prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", + arg->argv[arg->argn-1]); + else + log_Printf(LogWARN, "%s command must have arguments\n", + arg->argv[arg->argn] ); + + return 0; +} + +const char * +command_ShowNegval(unsigned val) +{ + switch (val&3) { + case 1: return "disabled & accepted"; + case 2: return "enabled & denied"; + case 3: return "enabled & accepted"; + } + return "disabled & denied"; +} + +static int +ClearCommand(struct cmdargs const *arg) +{ + struct pppThroughput *t; + struct datalink *cx; + int i, clear_type; + + if (arg->argc < arg->argn + 1) + return -1; + + if (strcasecmp(arg->argv[arg->argn], "modem") == 0) { + cx = arg->cx; + if (!cx) + cx = bundle2datalink(arg->bundle, NULL); + if (!cx) { + log_Printf(LogWARN, "A link must be specified for ``clear modem''\n"); + return 1; + } + t = &cx->physical->link.throughput; + } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) + t = &arg->bundle->ncp.ipcp.throughput; + else + return -1; + + if (arg->argc > arg->argn + 1) { + clear_type = 0; + for (i = arg->argn + 1; i < arg->argc; i++) + if (strcasecmp(arg->argv[i], "overall") == 0) + clear_type |= THROUGHPUT_OVERALL; + else if (strcasecmp(arg->argv[i], "current") == 0) + clear_type |= THROUGHPUT_CURRENT; + else if (strcasecmp(arg->argv[i], "peak") == 0) + clear_type |= THROUGHPUT_PEAK; + else + return -1; + } else + clear_type = THROUGHPUT_ALL; + + throughput_clear(t, clear_type, arg->prompt); + return 0; +} diff --git a/usr.sbin/ppp/ppp/command.h b/usr.sbin/ppp/ppp/command.h new file mode 100644 index 00000000000..3907b92953d --- /dev/null +++ b/usr.sbin/ppp/ppp/command.h @@ -0,0 +1,63 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: command.h,v 1.1 1998/08/31 00:22:18 brian Exp $ + * + * TODO: + */ + +struct cmdtab; +struct bundle; +struct datalink; +struct prompt; + +struct cmdargs { + struct cmdtab const *cmdtab; /* The entire command table */ + struct cmdtab const *cmd; /* This command entry */ + int argc; /* Number of arguments (excluding cmd */ + int argn; /* Argument to start processing from */ + char const *const *argv; /* Arguments */ + struct bundle *bundle; /* Our bundle */ + struct datalink *cx; /* Our context */ + struct prompt *prompt; /* Who executed us */ +}; + +struct cmdtab { + const char *name; + const char *alias; + int (*func) (struct cmdargs const *); + u_char lauth; + const char *helpmes; + const char *syntax; + const void *args; +}; + +#define NEG_ACCEPTED (1) +#define NEG_ENABLED (2) +#define IsAccepted(x) ((x) & NEG_ACCEPTED) +#define IsEnabled(x) ((x) & NEG_ENABLED) + +extern const char Version[]; +extern const char VersionDate[]; + +extern int command_Interpret(char *, int, char *vector[MAXARGS]); +extern void command_Run(struct bundle *, int, char const *const *, + struct prompt *, const char *, struct datalink *); +extern void command_Decode(struct bundle *, char *, int, struct prompt *, + const char *); +extern struct link *command_ChooseLink(struct cmdargs const *); +extern const char *command_ShowNegval(unsigned); diff --git a/usr.sbin/ppp/ppp/datalink.c b/usr.sbin/ppp/ppp/datalink.c new file mode 100644 index 00000000000..d8a1bf24aea --- /dev/null +++ b/usr.sbin/ppp/ppp/datalink.c @@ -0,0 +1,1271 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: datalink.c,v 1.1 1998/08/31 00:22:19 brian Exp $ + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/uio.h> +#include <termios.h> + +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "lcp.h" +#include "descriptor.h" +#include "lqr.h" +#include "hdlc.h" +#include "async.h" +#include "throughput.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "mp.h" +#include "bundle.h" +#include "chat.h" +#include "auth.h" +#include "modem.h" +#include "prompt.h" +#include "lcpproto.h" +#include "pap.h" +#include "chap.h" +#include "command.h" +#include "cbcp.h" +#include "datalink.h" + +static void datalink_LoginDone(struct datalink *); +static void datalink_NewState(struct datalink *, int); + +static void +datalink_OpenTimeout(void *v) +{ + struct datalink *dl = (struct datalink *)v; + + timer_Stop(&dl->dial_timer); + if (dl->state == DATALINK_OPENING) + log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); +} + +static void +datalink_StartDialTimer(struct datalink *dl, int Timeout) +{ + timer_Stop(&dl->dial_timer); + + if (Timeout) { + if (Timeout > 0) + dl->dial_timer.load = Timeout * SECTICKS; + else + dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; + dl->dial_timer.func = datalink_OpenTimeout; + dl->dial_timer.name = "dial"; + dl->dial_timer.arg = dl; + timer_Start(&dl->dial_timer); + if (dl->state == DATALINK_OPENING) + log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", + dl->name, Timeout); + } +} + +static void +datalink_HangupDone(struct datalink *dl) +{ + if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && + physical_GetFD(dl->physical) != -1) { + /* Don't close our modem if the link is dedicated */ + datalink_LoginDone(dl); + return; + } + + modem_Close(dl->physical); + dl->phone.chosen = "N/A"; + + if (dl->cbcp.required) { + log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); + dl->cfg.callback.opmask = 0; + strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, + sizeof dl->cfg.phone.list - 1); + dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; + dl->phone.alt = dl->phone.next = NULL; + dl->reconnect_tries = dl->cfg.reconnect.max; + dl->dial_tries = dl->cfg.dial.max; + dl->script.run = 1; + dl->script.packetmode = 1; + if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) + log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); + bundle_LinksRemoved(dl->bundle); + if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) + dl->cbcp.fsm.delay = dl->cfg.dial.timeout; + datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); + cbcp_Down(&dl->cbcp); + datalink_NewState(dl, DATALINK_OPENING); + } else if (dl->bundle->CleaningUp || + (dl->physical->type == PHYS_DIRECT) || + ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && + !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { + datalink_NewState(dl, DATALINK_CLOSED); + dl->dial_tries = -1; + dl->reconnect_tries = 0; + bundle_LinkClosed(dl->bundle, dl); + if (!dl->bundle->CleaningUp) + datalink_StartDialTimer(dl, dl->cfg.dial.timeout); + } else { + datalink_NewState(dl, DATALINK_OPENING); + if (dl->dial_tries < 0) { + datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); + dl->dial_tries = dl->cfg.dial.max; + dl->reconnect_tries--; + } else { + if (dl->phone.next == NULL) + datalink_StartDialTimer(dl, dl->cfg.dial.timeout); + else + datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); + } + } +} + +static const char * +datalink_ChoosePhoneNumber(struct datalink *dl) +{ + char *phone; + + if (dl->phone.alt == NULL) { + if (dl->phone.next == NULL) { + strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); + dl->phone.list[sizeof dl->phone.list - 1] = '\0'; + dl->phone.next = dl->phone.list; + } + dl->phone.alt = strsep(&dl->phone.next, ":"); + } + phone = strsep(&dl->phone.alt, "|"); + dl->phone.chosen = *phone ? phone : "[NONE]"; + if (*phone) + log_Printf(LogPHASE, "Phone: %s\n", phone); + return phone; +} + +static void +datalink_LoginDone(struct datalink *dl) +{ + if (!dl->script.packetmode) { + dl->dial_tries = -1; + datalink_NewState(dl, DATALINK_READY); + } else if (modem_Raw(dl->physical, dl->bundle) < 0) { + dl->dial_tries = 0; + log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); + if (dl->script.run) { + datalink_NewState(dl, DATALINK_HANGUP); + modem_Offline(dl->physical); + chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); + } else { + timer_Stop(&dl->physical->Timer); + if (dl->physical->type == PHYS_DEDICATED) + /* force a redial timeout */ + modem_Close(dl->physical); + datalink_HangupDone(dl); + } + } else { + dl->dial_tries = -1; + + hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); + async_Init(&dl->physical->async); + + lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? + 0 : dl->physical->link.lcp.cfg.openmode); + ccp_Setup(&dl->physical->link.ccp); + + datalink_NewState(dl, DATALINK_LCP); + fsm_Up(&dl->physical->link.lcp.fsm); + fsm_Open(&dl->physical->link.lcp.fsm); + } +} + +static int +datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, + int *n) +{ + struct datalink *dl = descriptor2datalink(d); + int result; + + result = 0; + switch (dl->state) { + case DATALINK_CLOSED: + if ((dl->physical->type & + (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && + !bundle_IsDead(dl->bundle)) + /* + * Our first time in - DEDICATED & DDIAL never come down, and + * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. + * Go to DATALINK_OPENING via datalink_Up() and fall through. + */ + datalink_Up(dl, 1, 1); + else + break; + /* fall through */ + + case DATALINK_OPENING: + if (dl->dial_timer.state != TIMER_RUNNING) { + if (--dl->dial_tries < 0) + dl->dial_tries = 0; + if (modem_Open(dl->physical, dl->bundle) >= 0) { + log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" + "Type `~?' for help\r\n", dl->name, + dl->physical->name.full); + if (dl->script.run) { + datalink_NewState(dl, DATALINK_DIAL); + chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, + datalink_ChoosePhoneNumber(dl)); + if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && + dl->cfg.dial.max) + log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", + dl->name, dl->cfg.dial.max - dl->dial_tries, + dl->cfg.dial.max); + return datalink_UpdateSet(d, r, w, e, n); + } else + datalink_LoginDone(dl); + } else { + if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && + dl->cfg.dial.max) + log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", + dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); + else + log_Printf(LogCHAT, "Failed to open modem\n"); + + if (dl->bundle->CleaningUp || + (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && + dl->cfg.dial.max && dl->dial_tries == 0)) { + datalink_NewState(dl, DATALINK_CLOSED); + dl->reconnect_tries = 0; + dl->dial_tries = -1; + log_WritePrompts(dl, "Failed to open %s\n", + dl->physical->name.full); + bundle_LinkClosed(dl->bundle, dl); + } + if (!dl->bundle->CleaningUp) { + log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", + dl->physical->name.full, dl->cfg.dial.timeout); + datalink_StartDialTimer(dl, dl->cfg.dial.timeout); + } + } + } + break; + + case DATALINK_HANGUP: + case DATALINK_DIAL: + case DATALINK_LOGIN: + result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); + switch (dl->chat.state) { + case CHAT_DONE: + /* script succeeded */ + chat_Destroy(&dl->chat); + switch(dl->state) { + case DATALINK_HANGUP: + datalink_HangupDone(dl); + break; + case DATALINK_DIAL: + datalink_NewState(dl, DATALINK_LOGIN); + chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); + return datalink_UpdateSet(d, r, w, e, n); + case DATALINK_LOGIN: + datalink_LoginDone(dl); + break; + } + break; + case CHAT_FAILED: + /* Going down - script failed */ + log_Printf(LogWARN, "Chat script failed\n"); + chat_Destroy(&dl->chat); + switch(dl->state) { + case DATALINK_HANGUP: + datalink_HangupDone(dl); + break; + case DATALINK_DIAL: + case DATALINK_LOGIN: + datalink_NewState(dl, DATALINK_HANGUP); + modem_Offline(dl->physical); /* Is this required ? */ + chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); + return datalink_UpdateSet(d, r, w, e, n); + } + break; + } + break; + + case DATALINK_READY: + case DATALINK_LCP: + case DATALINK_AUTH: + case DATALINK_CBCP: + case DATALINK_OPEN: + result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); + break; + } + return result; +} + +int +datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) +{ + return physical_RemoveFromSet(dl->physical, r, w, e); +} + +static int +datalink_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct datalink *dl = descriptor2datalink(d); + + switch (dl->state) { + case DATALINK_CLOSED: + case DATALINK_OPENING: + break; + + case DATALINK_HANGUP: + case DATALINK_DIAL: + case DATALINK_LOGIN: + return descriptor_IsSet(&dl->chat.desc, fdset); + + case DATALINK_READY: + case DATALINK_LCP: + case DATALINK_AUTH: + case DATALINK_CBCP: + case DATALINK_OPEN: + return descriptor_IsSet(&dl->physical->desc, fdset); + } + return 0; +} + +static void +datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct datalink *dl = descriptor2datalink(d); + + switch (dl->state) { + case DATALINK_CLOSED: + case DATALINK_OPENING: + break; + + case DATALINK_HANGUP: + case DATALINK_DIAL: + case DATALINK_LOGIN: + descriptor_Read(&dl->chat.desc, bundle, fdset); + break; + + case DATALINK_READY: + case DATALINK_LCP: + case DATALINK_AUTH: + case DATALINK_CBCP: + case DATALINK_OPEN: + descriptor_Read(&dl->physical->desc, bundle, fdset); + break; + } +} + +static int +datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct datalink *dl = descriptor2datalink(d); + int result = 0; + + switch (dl->state) { + case DATALINK_CLOSED: + case DATALINK_OPENING: + break; + + case DATALINK_HANGUP: + case DATALINK_DIAL: + case DATALINK_LOGIN: + result = descriptor_Write(&dl->chat.desc, bundle, fdset); + break; + + case DATALINK_READY: + case DATALINK_LCP: + case DATALINK_AUTH: + case DATALINK_CBCP: + case DATALINK_OPEN: + result = descriptor_Write(&dl->physical->desc, bundle, fdset); + break; + } + + return result; +} + +static void +datalink_ComeDown(struct datalink *dl, int how) +{ + if (how != CLOSE_NORMAL) { + dl->dial_tries = -1; + dl->reconnect_tries = 0; + if (dl->state >= DATALINK_READY && how == CLOSE_LCP) + dl->stayonline = 1; + } + + if (dl->state >= DATALINK_READY && dl->stayonline) { + dl->stayonline = 0; + timer_Stop(&dl->physical->Timer); + datalink_NewState(dl, DATALINK_READY); + } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { + modem_Offline(dl->physical); + chat_Destroy(&dl->chat); + if (dl->script.run && dl->state != DATALINK_OPENING) { + datalink_NewState(dl, DATALINK_HANGUP); + chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); + } else + datalink_HangupDone(dl); + } +} + +static void +datalink_LayerStart(void *v, struct fsm *fp) +{ + /* The given FSM is about to start up ! */ + struct datalink *dl = (struct datalink *)v; + + if (fp->proto == PROTO_LCP) + (*dl->parent->LayerStart)(dl->parent->object, fp); +} + +static void +datalink_LayerUp(void *v, struct fsm *fp) +{ + /* The given fsm is now up */ + struct datalink *dl = (struct datalink *)v; + + if (fp->proto == PROTO_LCP) { + datalink_GotAuthname(dl, "", 0); + dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; + dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; + if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { + if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) + bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); + log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, + Auth2Nam(dl->physical->link.lcp.his_auth), + Auth2Nam(dl->physical->link.lcp.want_auth)); + if (dl->physical->link.lcp.his_auth == PROTO_PAP) + auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); + if (dl->physical->link.lcp.want_auth == PROTO_CHAP) + auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); + } else + datalink_AuthOk(dl); + } +} + +void +datalink_GotAuthname(struct datalink *dl, const char *name, int len) +{ + if (len >= sizeof dl->peer.authname) + len = sizeof dl->peer.authname - 1; + strncpy(dl->peer.authname, name, len); + dl->peer.authname[len] = '\0'; +} + +void +datalink_NCPUp(struct datalink *dl) +{ + int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); + + if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { + /* we've authenticated in multilink mode ! */ + switch (mp_Up(&dl->bundle->ncp.mp, dl)) { + case MP_LINKSENT: + /* We've handed the link off to another ppp (well, we will soon) ! */ + return; + case MP_UP: + /* First link in the bundle */ + auth_Select(dl->bundle, dl->peer.authname); + /* fall through */ + case MP_ADDED: + /* We're in multilink mode ! */ + dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ + break; + case MP_FAILED: + datalink_AuthNotOk(dl); + return; + } + } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { + log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); + datalink_NewState(dl, DATALINK_OPEN); + (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); + return; + } else { + dl->bundle->ncp.mp.peer = dl->peer; + ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); + auth_Select(dl->bundle, dl->peer.authname); + } + + if (ccpok) { + fsm_Up(&dl->physical->link.ccp.fsm); + fsm_Open(&dl->physical->link.ccp.fsm); + } + datalink_NewState(dl, DATALINK_OPEN); + bundle_NewPhase(dl->bundle, PHASE_NETWORK); + (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); +} + +void +datalink_CBCPComplete(struct datalink *dl) +{ + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); +} + +void +datalink_CBCPFailed(struct datalink *dl) +{ + cbcp_Down(&dl->cbcp); + datalink_CBCPComplete(dl); +} + +void +datalink_AuthOk(struct datalink *dl) +{ + if (dl->physical->link.lcp.his_callback.opmask == + CALLBACK_BIT(CALLBACK_CBCP) || + dl->physical->link.lcp.want_callback.opmask == + CALLBACK_BIT(CALLBACK_CBCP)) { + datalink_NewState(dl, DATALINK_CBCP); + cbcp_Up(&dl->cbcp); + } else if (dl->physical->link.lcp.want_callback.opmask) { + log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); + } else + switch (dl->physical->link.lcp.his_callback.opmask) { + case 0: + datalink_NCPUp(dl); + break; + + case CALLBACK_BIT(CALLBACK_AUTH): + auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, + sizeof dl->cbcp.fsm.phone); + if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { + log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, + dl->peer.authname); + *dl->cbcp.fsm.phone = '\0'; + } else { + char *ptr = strchr(dl->cbcp.fsm.phone, ','); + if (ptr) + *ptr = '\0'; /* Call back on the first number */ + log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, + dl->cbcp.fsm.phone); + dl->cbcp.required = 1; + } + dl->cbcp.fsm.delay = 0; + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); + break; + + case CALLBACK_BIT(CALLBACK_E164): + strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, + sizeof dl->cbcp.fsm.phone - 1); + dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; + log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, + dl->cbcp.fsm.phone); + dl->cbcp.required = 1; + dl->cbcp.fsm.delay = 0; + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); + break; + + default: + log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", + dl->name); + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); + break; + } +} + +void +datalink_AuthNotOk(struct datalink *dl) +{ + datalink_NewState(dl, DATALINK_LCP); + fsm_Close(&dl->physical->link.lcp.fsm); +} + +static void +datalink_LayerDown(void *v, struct fsm *fp) +{ + /* The given FSM has been told to come down */ + struct datalink *dl = (struct datalink *)v; + + if (fp->proto == PROTO_LCP) { + switch (dl->state) { + case DATALINK_OPEN: + peerid_Init(&dl->peer); + fsm2initial(&dl->physical->link.ccp.fsm); + datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ + (*dl->parent->LayerDown)(dl->parent->object, fp); + /* fall through (just in case) */ + + case DATALINK_CBCP: + if (!dl->cbcp.required) + cbcp_Down(&dl->cbcp); + /* fall through (just in case) */ + + case DATALINK_AUTH: + timer_Stop(&dl->pap.authtimer); + timer_Stop(&dl->chap.auth.authtimer); + } + datalink_NewState(dl, DATALINK_LCP); + } +} + +static void +datalink_LayerFinish(void *v, struct fsm *fp) +{ + /* The given fsm is now down */ + struct datalink *dl = (struct datalink *)v; + + if (fp->proto == PROTO_LCP) { + fsm2initial(fp); + (*dl->parent->LayerFinish)(dl->parent->object, fp); + datalink_ComeDown(dl, CLOSE_NORMAL); + } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) + fsm_Open(fp); /* CCP goes to ST_STOPPED */ +} + +struct datalink * +datalink_Create(const char *name, struct bundle *bundle, int type) +{ + struct datalink *dl; + + dl = (struct datalink *)malloc(sizeof(struct datalink)); + if (dl == NULL) + return dl; + + dl->desc.type = DATALINK_DESCRIPTOR; + dl->desc.UpdateSet = datalink_UpdateSet; + dl->desc.IsSet = datalink_IsSet; + dl->desc.Read = datalink_Read; + dl->desc.Write = datalink_Write; + + dl->state = DATALINK_CLOSED; + + *dl->cfg.script.dial = '\0'; + *dl->cfg.script.login = '\0'; + *dl->cfg.script.hangup = '\0'; + *dl->cfg.phone.list = '\0'; + *dl->phone.list = '\0'; + dl->phone.next = NULL; + dl->phone.alt = NULL; + dl->phone.chosen = "N/A"; + dl->stayonline = 0; + dl->script.run = 1; + dl->script.packetmode = 1; + mp_linkInit(&dl->mp); + + dl->bundle = bundle; + dl->next = NULL; + + memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); + + dl->dial_tries = 0; + dl->cfg.dial.max = 1; + dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; + dl->cfg.dial.timeout = DIAL_TIMEOUT; + + dl->reconnect_tries = 0; + dl->cfg.reconnect.max = 0; + dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; + + dl->cfg.callback.opmask = 0; + dl->cfg.cbcp.delay = 0; + *dl->cfg.cbcp.phone = '\0'; + dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; + + dl->name = strdup(name); + peerid_Init(&dl->peer); + dl->parent = &bundle->fsm; + dl->fsmp.LayerStart = datalink_LayerStart; + dl->fsmp.LayerUp = datalink_LayerUp; + dl->fsmp.LayerDown = datalink_LayerDown; + dl->fsmp.LayerFinish = datalink_LayerFinish; + dl->fsmp.object = dl; + + auth_Init(&dl->pap); + auth_Init(&dl->chap.auth); + + if ((dl->physical = modem_Create(dl, type)) == NULL) { + free(dl->name); + free(dl); + return NULL; + } + cbcp_Init(&dl->cbcp, dl->physical); + chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); + + log_Printf(LogPHASE, "%s: Created in %s state\n", + dl->name, datalink_State(dl)); + + return dl; +} + +struct datalink * +datalink_Clone(struct datalink *odl, const char *name) +{ + struct datalink *dl; + + dl = (struct datalink *)malloc(sizeof(struct datalink)); + if (dl == NULL) + return dl; + + dl->desc.type = DATALINK_DESCRIPTOR; + dl->desc.UpdateSet = datalink_UpdateSet; + dl->desc.IsSet = datalink_IsSet; + dl->desc.Read = datalink_Read; + dl->desc.Write = datalink_Write; + + dl->state = DATALINK_CLOSED; + + memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); + mp_linkInit(&dl->mp); + *dl->phone.list = '\0'; + dl->phone.next = NULL; + dl->phone.alt = NULL; + dl->phone.chosen = "N/A"; + dl->bundle = odl->bundle; + dl->next = NULL; + memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); + dl->dial_tries = 0; + dl->reconnect_tries = 0; + dl->name = strdup(name); + peerid_Init(&dl->peer); + dl->parent = odl->parent; + memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); + dl->fsmp.object = dl; + auth_Init(&dl->pap); + dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; + + auth_Init(&dl->chap.auth); + dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; + + if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { + free(dl->name); + free(dl); + return NULL; + } + memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); + memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, + sizeof dl->physical->link.lcp.cfg); + memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, + sizeof dl->physical->link.ccp.cfg); + memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, + sizeof dl->physical->async.cfg); + + cbcp_Init(&dl->cbcp, dl->physical); + chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); + + log_Printf(LogPHASE, "%s: Cloned in %s state\n", + dl->name, datalink_State(dl)); + + return dl; +} + +struct datalink * +datalink_Destroy(struct datalink *dl) +{ + struct datalink *result; + + if (dl->state != DATALINK_CLOSED) { + log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", + datalink_State(dl)); + switch (dl->state) { + case DATALINK_HANGUP: + case DATALINK_DIAL: + case DATALINK_LOGIN: + chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ + break; + } + } + + result = dl->next; + modem_Destroy(dl->physical); + free(dl->name); + free(dl); + + return result; +} + +void +datalink_Up(struct datalink *dl, int runscripts, int packetmode) +{ + if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) + /* Ignore scripts */ + runscripts = 0; + + switch (dl->state) { + case DATALINK_CLOSED: + if (bundle_Phase(dl->bundle) == PHASE_DEAD || + bundle_Phase(dl->bundle) == PHASE_TERMINATE) + bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); + datalink_NewState(dl, DATALINK_OPENING); + dl->reconnect_tries = + dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; + dl->dial_tries = dl->cfg.dial.max; + dl->script.run = runscripts; + dl->script.packetmode = packetmode; + break; + + case DATALINK_OPENING: + if (!dl->script.run && runscripts) + dl->script.run = 1; + /* fall through */ + + case DATALINK_DIAL: + case DATALINK_LOGIN: + case DATALINK_READY: + if (!dl->script.packetmode && packetmode) { + dl->script.packetmode = 1; + if (dl->state == DATALINK_READY) + datalink_LoginDone(dl); + } + break; + } +} + +void +datalink_Close(struct datalink *dl, int how) +{ + /* Please close */ + switch (dl->state) { + case DATALINK_OPEN: + peerid_Init(&dl->peer); + fsm2initial(&dl->physical->link.ccp.fsm); + /* fall through */ + + case DATALINK_CBCP: + case DATALINK_AUTH: + case DATALINK_LCP: + fsm_Close(&dl->physical->link.lcp.fsm); + if (how != CLOSE_NORMAL) { + dl->dial_tries = -1; + dl->reconnect_tries = 0; + if (how == CLOSE_LCP) + dl->stayonline = 1; + } + break; + + default: + datalink_ComeDown(dl, how); + } +} + +void +datalink_Down(struct datalink *dl, int how) +{ + /* Carrier is lost */ + switch (dl->state) { + case DATALINK_OPEN: + peerid_Init(&dl->peer); + fsm2initial(&dl->physical->link.ccp.fsm); + /* fall through */ + + case DATALINK_CBCP: + case DATALINK_AUTH: + case DATALINK_LCP: + fsm2initial(&dl->physical->link.lcp.fsm); + /* fall through */ + + default: + datalink_ComeDown(dl, how); + } +} + +void +datalink_StayDown(struct datalink *dl) +{ + dl->reconnect_tries = 0; +} + +void +datalink_DontHangup(struct datalink *dl) +{ + if (dl->state >= DATALINK_LCP) + dl->stayonline = 1; +} + +int +datalink_Show(struct cmdargs const *arg) +{ + prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); + prompt_Printf(arg->prompt, " State: %s\n", + datalink_State(arg->cx)); + prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", + arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); + prompt_Printf(arg->prompt, " Peer name: "); + if (*arg->cx->peer.authname) + prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); + else if (arg->cx->state == DATALINK_OPEN) + prompt_Printf(arg->prompt, "None requested\n"); + else + prompt_Printf(arg->prompt, "N/A\n"); + prompt_Printf(arg->prompt, " Discriminator: %s\n", + mp_Enddisc(arg->cx->peer.enddisc.class, + arg->cx->peer.enddisc.address, + arg->cx->peer.enddisc.len)); + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + prompt_Printf(arg->prompt, " Phone List: %s\n", + arg->cx->cfg.phone.list); + if (arg->cx->cfg.dial.max) + prompt_Printf(arg->prompt, " Dial tries: %d, delay ", + arg->cx->cfg.dial.max); + else + prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); + if (arg->cx->cfg.dial.next_timeout > 0) + prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); + else + prompt_Printf(arg->prompt, "random/"); + if (arg->cx->cfg.dial.timeout > 0) + prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); + else + prompt_Printf(arg->prompt, "random\n"); + prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", + arg->cx->cfg.reconnect.max); + if (arg->cx->cfg.reconnect.timeout > 0) + prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); + else + prompt_Printf(arg->prompt, "random\n"); + prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == + PHYS_DIRECT ? "accepted: " : "requested:"); + if (!arg->cx->cfg.callback.opmask) + prompt_Printf(arg->prompt, "none\n"); + else { + int comma = 0; + + if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { + prompt_Printf(arg->prompt, "none"); + comma = 1; + } + if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { + prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); + comma = 1; + } + if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { + prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); + if (arg->cx->physical->type != PHYS_DIRECT) + prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); + comma = 1; + } + if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { + prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); + prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", + arg->cx->cfg.cbcp.delay); + prompt_Printf(arg->prompt, " phone: %s\n", + arg->cx->cfg.cbcp.phone); + prompt_Printf(arg->prompt, " timeout: %lds\n", + arg->cx->cfg.cbcp.fsmretry); + } else + prompt_Printf(arg->prompt, "\n"); + } + + prompt_Printf(arg->prompt, " Dial Script: %s\n", + arg->cx->cfg.script.dial); + prompt_Printf(arg->prompt, " Login Script: %s\n", + arg->cx->cfg.script.login); + prompt_Printf(arg->prompt, " Hangup Script: %s\n", + arg->cx->cfg.script.hangup); + return 0; +} + +int +datalink_SetReconnect(struct cmdargs const *arg) +{ + if (arg->argc == arg->argn+2) { + arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); + arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); + return 0; + } + return -1; +} + +int +datalink_SetRedial(struct cmdargs const *arg) +{ + int timeout; + int tries; + char *dot; + + if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { + if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && + (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { + arg->cx->cfg.dial.timeout = -1; + randinit(); + } else { + timeout = atoi(arg->argv[arg->argn]); + + if (timeout >= 0) + arg->cx->cfg.dial.timeout = timeout; + else { + log_Printf(LogWARN, "Invalid redial timeout\n"); + return -1; + } + } + + dot = strchr(arg->argv[arg->argn], '.'); + if (dot) { + if (strcasecmp(++dot, "random") == 0) { + arg->cx->cfg.dial.next_timeout = -1; + randinit(); + } else { + timeout = atoi(dot); + if (timeout >= 0) + arg->cx->cfg.dial.next_timeout = timeout; + else { + log_Printf(LogWARN, "Invalid next redial timeout\n"); + return -1; + } + } + } else + /* Default next timeout */ + arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; + + if (arg->argc == arg->argn+2) { + tries = atoi(arg->argv[arg->argn+1]); + + if (tries >= 0) { + arg->cx->cfg.dial.max = tries; + } else { + log_Printf(LogWARN, "Invalid retry value\n"); + return 1; + } + } + return 0; + } + return -1; +} + +static const char *states[] = { + "closed", + "opening", + "hangup", + "dial", + "login", + "ready", + "lcp", + "auth", + "cbcp", + "open" +}; + +const char * +datalink_State(struct datalink *dl) +{ + if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) + return "unknown"; + return states[dl->state]; +} + +static void +datalink_NewState(struct datalink *dl, int state) +{ + if (state != dl->state) { + if (state >= 0 && state < sizeof states / sizeof states[0]) { + log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), + states[state]); + dl->state = state; + } else + log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); + } +} + +struct datalink * +iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, + int fd) +{ + struct datalink *dl, *cdl; + u_int retry; + char *oname; + + dl = (struct datalink *)iov[(*niov)++].iov_base; + dl->name = iov[*niov].iov_base; + + if (dl->name[DATALINK_MAXNAME-1]) { + dl->name[DATALINK_MAXNAME-1] = '\0'; + if (strlen(dl->name) == DATALINK_MAXNAME - 1) + log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); + } + + /* Make sure the name is unique ! */ + oname = NULL; + do { + for (cdl = bundle->links; cdl; cdl = cdl->next) + if (!strcasecmp(dl->name, cdl->name)) { + if (oname) + free(datalink_NextName(dl)); + else + oname = datalink_NextName(dl); + break; /* Keep renaming 'till we have no conflicts */ + } + } while (cdl); + + if (oname) { + log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); + free(oname); + } else { + dl->name = strdup(dl->name); + free(iov[*niov].iov_base); + } + (*niov)++; + + dl->desc.type = DATALINK_DESCRIPTOR; + dl->desc.UpdateSet = datalink_UpdateSet; + dl->desc.IsSet = datalink_IsSet; + dl->desc.Read = datalink_Read; + dl->desc.Write = datalink_Write; + + mp_linkInit(&dl->mp); + *dl->phone.list = '\0'; + dl->phone.next = NULL; + dl->phone.alt = NULL; + dl->phone.chosen = "N/A"; + + dl->bundle = bundle; + dl->next = NULL; + memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); + dl->dial_tries = 0; + dl->reconnect_tries = 0; + dl->parent = &bundle->fsm; + dl->fsmp.LayerStart = datalink_LayerStart; + dl->fsmp.LayerUp = datalink_LayerUp; + dl->fsmp.LayerDown = datalink_LayerDown; + dl->fsmp.LayerFinish = datalink_LayerFinish; + dl->fsmp.object = dl; + + retry = dl->pap.cfg.fsmretry; + auth_Init(&dl->pap); + dl->pap.cfg.fsmretry = retry; + + retry = dl->chap.auth.cfg.fsmretry; + auth_Init(&dl->chap.auth); + dl->chap.auth.cfg.fsmretry = retry; + + dl->physical = iov2modem(dl, iov, niov, maxiov, fd); + + if (!dl->physical) { + free(dl->name); + free(dl); + dl = NULL; + } else { + cbcp_Init(&dl->cbcp, dl->physical); + chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); + + log_Printf(LogPHASE, "%s: Transferred in %s state\n", + dl->name, datalink_State(dl)); + } + + return dl; +} + +int +datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, + pid_t newpid) +{ + /* If `dl' is NULL, we're allocating before a Fromiov() */ + int link_fd; + + if (dl) { + timer_Stop(&dl->dial_timer); + /* The following is purely for the sake of paranoia */ + cbcp_Down(&dl->cbcp); + timer_Stop(&dl->pap.authtimer); + timer_Stop(&dl->chap.auth.authtimer); + } + + if (*niov >= maxiov - 1) { + log_Printf(LogERROR, "Toiov: No room for datalink !\n"); + if (dl) { + free(dl->name); + free(dl); + } + return -1; + } + + iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); + iov[(*niov)++].iov_len = sizeof *dl; + iov[*niov].iov_base = + dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); + iov[(*niov)++].iov_len = DATALINK_MAXNAME; + + link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); + + if (link_fd == -1 && dl) { + free(dl->name); + free(dl); + } + + return link_fd; +} + +void +datalink_Rename(struct datalink *dl, const char *name) +{ + free(dl->name); + dl->physical->link.name = dl->name = strdup(name); +} + +char * +datalink_NextName(struct datalink *dl) +{ + int f, n; + char *name, *oname; + + n = strlen(dl->name); + name = (char *)malloc(n+3); + for (f = n - 1; f >= 0; f--) + if (!isdigit(dl->name[f])) + break; + n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); + sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); + oname = dl->name; + dl->name = name; + /* our physical link name isn't updated (it probably isn't created yet) */ + return oname; +} + +int +datalink_SetMode(struct datalink *dl, int mode) +{ + if (!physical_SetMode(dl->physical, mode)) + return 0; + if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) + dl->script.run = 0; + if (dl->physical->type == PHYS_DIRECT) + dl->reconnect_tries = 0; + if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) + datalink_Up(dl, 1, 1); + return 1; +} diff --git a/usr.sbin/ppp/ppp/datalink.h b/usr.sbin/ppp/ppp/datalink.h new file mode 100644 index 00000000000..047ed10cd41 --- /dev/null +++ b/usr.sbin/ppp/ppp/datalink.h @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: datalink.h,v 1.1 1998/08/31 00:22:19 brian Exp $ + */ + +#define DATALINK_CLOSED (0) +#define DATALINK_OPENING (1) +#define DATALINK_HANGUP (2) +#define DATALINK_DIAL (3) +#define DATALINK_LOGIN (4) +#define DATALINK_READY (5) +#define DATALINK_LCP (6) +#define DATALINK_AUTH (7) +#define DATALINK_CBCP (8) +#define DATALINK_OPEN (9) + +#define DATALINK_MAXNAME (20) /* Maximum datalink::name length */ + +/* How to close the link */ +#define CLOSE_NORMAL 0 +#define CLOSE_STAYDOWN 1 +#define CLOSE_LCP 2 + +struct iovec; +struct prompt; +struct physical; +struct bundle; + +struct datalink { + struct descriptor desc; /* We play either a physical or a chat */ + int state; /* Our DATALINK_* state */ + struct physical *physical; /* Our link */ + + struct chat chat; /* For bringing the link up & down */ + + unsigned stayonline : 1; /* stay online when LCP is closed ? */ + struct { + unsigned run : 1; /* run scripts ? */ + unsigned packetmode : 1; /* Go into packet mode after login ? */ + } script; + + struct pppTimer dial_timer; /* For timing between close & open */ + + struct { + struct { + char dial[SCRIPT_LEN]; /* dial */ + char login[SCRIPT_LEN]; /* login */ + char hangup[SCRIPT_LEN]; /* hangup */ + } script; + struct { + char list[SCRIPT_LEN]; /* Telephone Numbers */ + } phone; + struct { + int max; /* initially try again this number of times */ + int next_timeout; /* Redial next timeout value */ + int timeout; /* Redial timeout value (end of phone list) */ + } dial; + struct { + int max; /* initially try again this number of times */ + int timeout; /* Timeout before reconnect on carrier loss */ + } reconnect; + struct callback callback; /* Direction depends on physical type */ + struct cbcpcfg cbcp; /* Direction depends on phys type & callback */ + } cfg; /* All our config data is in here */ + + struct { + char list[SCRIPT_LEN]; /* copy of cfg.list for strsep() */ + char *next; /* Next phone from the list */ + char *alt; /* Next phone from the list */ + const char *chosen; /* Chosen phone number after DIAL */ + } phone; + + struct cbcp cbcp; + + int dial_tries; /* currently try again this number of times */ + unsigned reconnect_tries; /* currently try again this number of times */ + + char *name; /* Our name */ + + struct peerid peer; /* Peer identification */ + + struct fsm_parent fsmp; /* Our callback functions */ + const struct fsm_parent *parent; /* Our parent */ + + struct authinfo pap; /* Authentication using pap */ + struct chap chap; /* Authentication using chap */ + + struct mp_link mp; /* multilink data */ + + struct bundle *bundle; /* for the moment */ + struct datalink *next; /* Next in the list */ +}; + +#define descriptor2datalink(d) \ + ((d)->type == DATALINK_DESCRIPTOR ? (struct datalink *)(d) : NULL) + +extern struct datalink *datalink_Create(const char *name, struct bundle *, int); +extern struct datalink *datalink_Clone(struct datalink *, const char *); +extern struct datalink *iov2datalink(struct bundle *, struct iovec *, int *, + int, int); +extern int datalink2iov(struct datalink *, struct iovec *, int *, int, pid_t); +extern struct datalink *datalink_Destroy(struct datalink *); +extern void datalink_GotAuthname(struct datalink *, const char *, int); +extern void datalink_Up(struct datalink *, int, int); +extern void datalink_Close(struct datalink *, int); +extern void datalink_Down(struct datalink *, int); +extern void datalink_StayDown(struct datalink *); +extern void datalink_DontHangup(struct datalink *); +extern void datalink_AuthOk(struct datalink *); +extern void datalink_AuthNotOk(struct datalink *); +extern void datalink_NCPUp(struct datalink *); +extern void datalink_CBCPComplete(struct datalink *); +extern void datalink_CBCPFailed(struct datalink *); +extern int datalink_Show(struct cmdargs const *); +extern int datalink_SetRedial(struct cmdargs const *); +extern int datalink_SetReconnect(struct cmdargs const *); +extern const char *datalink_State(struct datalink *); +extern void datalink_Rename(struct datalink *, const char *); +extern char *datalink_NextName(struct datalink *); +extern int datalink_RemoveFromSet(struct datalink *, fd_set *, fd_set *, + fd_set *); +extern int datalink_SetMode(struct datalink *, int); diff --git a/usr.sbin/ppp/ppp/deflate.c b/usr.sbin/ppp/ppp/deflate.c new file mode 100644 index 00000000000..499734b49c7 --- /dev/null +++ b/usr.sbin/ppp/ppp/deflate.c @@ -0,0 +1,593 @@ +/*- + * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: deflate.c,v 1.1 1998/08/31 00:22:19 brian Exp $ + */ + +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#include <zlib.h> + +#include "defs.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "lqr.h" +#include "hdlc.h" +#include "fsm.h" +#include "lcp.h" +#include "ccp.h" +#include "deflate.h" + +/* Our state */ +struct deflate_state { + u_short seqno; + int uncomp_rec; + int winsize; + z_stream cx; +}; + +static char garbage[10]; +static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; + +#define DEFLATE_CHUNK_LEN 1024 /* Allocate mbufs this size */ + +static void +DeflateResetOutput(void *v) +{ + struct deflate_state *state = (struct deflate_state *)v; + + state->seqno = 0; + state->uncomp_rec = 0; + deflateReset(&state->cx); + log_Printf(LogCCP, "Deflate: Output channel reset\n"); +} + +static int +DeflateOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, + struct mbuf *mp) +{ + struct deflate_state *state = (struct deflate_state *)v; + u_char *wp, *rp; + int olen, ilen, len, res, flush; + struct mbuf *mo_head, *mo, *mi_head, *mi; + + ilen = mbuf_Length(mp); + log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", proto, ilen); + log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp); + + /* Stuff the protocol in front of the input */ + mi_head = mi = mbuf_Alloc(2, MB_HDLCOUT); + mi->next = mp; + rp = MBUF_CTOP(mi); + if (proto < 0x100) { /* Compress the protocol */ + rp[0] = proto & 0377; + mi->cnt = 1; + } else { /* Don't compress the protocol */ + rp[0] = proto >> 8; + rp[1] = proto & 0377; + mi->cnt = 2; + } + + /* Allocate the initial output mbuf */ + mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); + mo->cnt = 2; + wp = MBUF_CTOP(mo); + *wp++ = state->seqno >> 8; + *wp++ = state->seqno & 0377; + log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno); + state->seqno++; + + /* Set up the deflation context */ + state->cx.next_out = wp; + state->cx.avail_out = DEFLATE_CHUNK_LEN - 2; + state->cx.next_in = MBUF_CTOP(mi); + state->cx.avail_in = mi->cnt; + flush = Z_NO_FLUSH; + + olen = 0; + while (1) { + if ((res = deflate(&state->cx, flush)) != Z_OK) { + if (res == Z_STREAM_END) + break; /* Done */ + log_Printf(LogWARN, "DeflateOutput: deflate returned %d (%s)\n", + res, state->cx.msg ? state->cx.msg : ""); + mbuf_Free(mo_head); + mbuf_FreeSeg(mi_head); + state->seqno--; + return 1; /* packet dropped */ + } + + if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) + break; + + if (state->cx.avail_in == 0 && mi->next != NULL) { + mi = mi->next; + state->cx.next_in = MBUF_CTOP(mi); + state->cx.avail_in = mi->cnt; + if (mi->next == NULL) + flush = Z_SYNC_FLUSH; + } + + if (state->cx.avail_out == 0) { + mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_HDLCOUT); + olen += (mo->cnt = DEFLATE_CHUNK_LEN); + mo = mo->next; + mo->cnt = 0; + state->cx.next_out = MBUF_CTOP(mo); + state->cx.avail_out = DEFLATE_CHUNK_LEN; + } + } + + olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); + olen -= 4; /* exclude the trailing EMPTY_BLOCK */ + + /* + * If the output packet (including seqno and excluding the EMPTY_BLOCK) + * got bigger, send the original. + */ + if (olen >= ilen) { + mbuf_Free(mo_head); + mbuf_FreeSeg(mi_head); + log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n", + ilen, olen, proto); + ccp->uncompout += ilen; + ccp->compout += ilen; /* We measure this stuff too */ + return 0; + } + + mbuf_Free(mi_head); + + /* + * Lose the last four bytes of our output. + * XXX: We should probably assert that these are the same as the + * contents of EMPTY_BLOCK. + */ + for (mo = mo_head, len = mo->cnt; len < olen; mo = mo->next, len += mo->cnt) + ; + mo->cnt -= len - olen; + if (mo->next != NULL) { + mbuf_Free(mo->next); + mo->next = NULL; + } + + ccp->uncompout += ilen; + ccp->compout += olen; + + log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n", + ilen, olen, proto); + + hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mo_head); + return 1; +} + +static void +DeflateResetInput(void *v) +{ + struct deflate_state *state = (struct deflate_state *)v; + + state->seqno = 0; + state->uncomp_rec = 0; + inflateReset(&state->cx); + log_Printf(LogCCP, "Deflate: Input channel reset\n"); +} + +static struct mbuf * +DeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi) +{ + struct deflate_state *state = (struct deflate_state *)v; + struct mbuf *mo, *mo_head, *mi_head; + u_char *wp; + int ilen, olen; + int seq, flush, res, first; + u_char hdr[2]; + + log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi); + mi_head = mi = mbuf_Read(mi, hdr, 2); + ilen = 2; + + /* Check the sequence number. */ + seq = (hdr[0] << 8) + hdr[1]; + log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq); + if (seq != state->seqno) { + if (seq <= state->uncomp_rec) + /* + * So the peer's started at zero again - fine ! If we're wrong, + * inflate() will fail. This is better than getting into a loop + * trying to get a ResetReq to a busy sender. + */ + state->seqno = seq; + else { + log_Printf(LogWARN, "DeflateInput: Seq error: Got %d, expected %d\n", + seq, state->seqno); + mbuf_Free(mi_head); + ccp_SendResetReq(&ccp->fsm); + return NULL; + } + } + state->seqno++; + state->uncomp_rec = 0; + + /* Allocate an output mbuf */ + mo_head = mo = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); + + /* Our proto starts with 0 if it's compressed */ + wp = MBUF_CTOP(mo); + wp[0] = '\0'; + + /* + * We set avail_out to 1 initially so we can look at the first + * byte of the output and decide whether we have a compressed + * proto field. + */ + state->cx.next_in = MBUF_CTOP(mi); + state->cx.avail_in = mi->cnt; + state->cx.next_out = wp + 1; + state->cx.avail_out = 1; + ilen += mi->cnt; + + flush = mi->next ? Z_NO_FLUSH : Z_SYNC_FLUSH; + first = 1; + olen = 0; + + while (1) { + if ((res = inflate(&state->cx, flush)) != Z_OK) { + if (res == Z_STREAM_END) + break; /* Done */ + log_Printf(LogWARN, "DeflateInput: inflate returned %d (%s)\n", + res, state->cx.msg ? state->cx.msg : ""); + mbuf_Free(mo_head); + mbuf_Free(mi); + ccp_SendResetReq(&ccp->fsm); + return NULL; + } + + if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) + break; + + if (state->cx.avail_in == 0 && mi && (mi = mbuf_FreeSeg(mi)) != NULL) { + /* underflow */ + state->cx.next_in = MBUF_CTOP(mi); + ilen += (state->cx.avail_in = mi->cnt); + if (mi->next == NULL) + flush = Z_SYNC_FLUSH; + } + + if (state->cx.avail_out == 0) { + /* overflow */ + if (first) { + if (!(wp[1] & 1)) { + /* 2 byte proto, shuffle it back in output */ + wp[0] = wp[1]; + state->cx.next_out--; + state->cx.avail_out = DEFLATE_CHUNK_LEN-1; + } else + state->cx.avail_out = DEFLATE_CHUNK_LEN-2; + first = 0; + } else { + olen += (mo->cnt = DEFLATE_CHUNK_LEN); + mo->next = mbuf_Alloc(DEFLATE_CHUNK_LEN, MB_IPIN); + mo = mo->next; + state->cx.next_out = MBUF_CTOP(mo); + state->cx.avail_out = DEFLATE_CHUNK_LEN; + } + } + } + + if (mi != NULL) + mbuf_Free(mi); + + if (first) { + log_Printf(LogWARN, "DeflateInput: Length error\n"); + mbuf_Free(mo_head); + ccp_SendResetReq(&ccp->fsm); + return NULL; + } + + olen += (mo->cnt = DEFLATE_CHUNK_LEN - state->cx.avail_out); + + *proto = ((u_short)wp[0] << 8) | wp[1]; + mo_head->offset += 2; + mo_head->cnt -= 2; + olen -= 2; + + ccp->compin += ilen; + ccp->uncompin += olen; + + log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n", + ilen, olen, *proto); + + /* + * Simulate an EMPTY_BLOCK so that our dictionary stays in sync. + * The peer will have silently removed this! + */ + state->cx.next_out = garbage; + state->cx.avail_out = sizeof garbage; + state->cx.next_in = EMPTY_BLOCK; + state->cx.avail_in = sizeof EMPTY_BLOCK; + inflate(&state->cx, Z_SYNC_FLUSH); + + return mo_head; +} + +static void +DeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi) +{ + struct deflate_state *state = (struct deflate_state *)v; + int res, flush, expect_error; + u_char *rp; + struct mbuf *mi_head; + short len; + + log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno); + + /* + * Stuff an ``uncompressed data'' block header followed by the + * protocol in front of the input + */ + mi_head = mbuf_Alloc(7, MB_HDLCOUT); + mi_head->next = mi; + len = mbuf_Length(mi); + mi = mi_head; + rp = MBUF_CTOP(mi); + if (proto < 0x100) { /* Compress the protocol */ + rp[5] = proto & 0377; + mi->cnt = 6; + len++; + } else { /* Don't compress the protocol */ + rp[5] = proto >> 8; + rp[6] = proto & 0377; + mi->cnt = 7; + len += 2; + } + rp[0] = 0x80; /* BITS: 100xxxxx */ + rp[1] = len & 0377; /* The length */ + rp[2] = len >> 8; + rp[3] = (~len) & 0377; /* One's compliment of the length */ + rp[4] = (~len) >> 8; + + state->cx.next_in = rp; + state->cx.avail_in = mi->cnt; + state->cx.next_out = garbage; + state->cx.avail_out = sizeof garbage; + flush = Z_NO_FLUSH; + expect_error = 0; + + while (1) { + if ((res = inflate(&state->cx, flush)) != Z_OK) { + if (res == Z_STREAM_END) + break; /* Done */ + if (expect_error && res == Z_BUF_ERROR) + break; + log_Printf(LogERROR, "DeflateDictSetup: inflate returned %d (%s)\n", + res, state->cx.msg ? state->cx.msg : ""); + log_Printf(LogERROR, "DeflateDictSetup: avail_in %d, avail_out %d\n", + state->cx.avail_in, state->cx.avail_out); + ccp_SendResetReq(&ccp->fsm); + mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ + return; + } + + if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0) + break; + + if (state->cx.avail_in == 0 && mi && (mi = mi->next) != NULL) { + /* underflow */ + state->cx.next_in = MBUF_CTOP(mi); + state->cx.avail_in = mi->cnt; + if (mi->next == NULL) + flush = Z_SYNC_FLUSH; + } + + if (state->cx.avail_out == 0) { + if (state->cx.avail_in == 0) + /* + * This seems to be a bug in libz ! If inflate() finished + * with 0 avail_in and 0 avail_out *and* this is the end of + * our input *and* inflate() *has* actually written all the + * output it's going to, it *doesn't* return Z_STREAM_END ! + * When we subsequently call it with no more input, it gives + * us Z_BUF_ERROR :-( It seems pretty safe to ignore this + * error (the dictionary seems to stay in sync). In the worst + * case, we'll drop the next compressed packet and do a + * CcpReset() then. + */ + expect_error = 1; + /* overflow */ + state->cx.next_out = garbage; + state->cx.avail_out = sizeof garbage; + } + } + + ccp->compin += len; + ccp->uncompin += len; + + state->seqno++; + state->uncomp_rec++; + mbuf_FreeSeg(mi_head); /* lose our allocated ``head'' buf */ +} + +static const char * +DeflateDispOpts(struct lcp_opt *o) +{ + static char disp[7]; /* Must be used immediately */ + + sprintf(disp, "win %d", (o->data[0]>>4) + 8); + return disp; +} + +static void +DeflateInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) +{ + o->len = 4; + o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8; + o->data[1] = '\0'; +} + +static int +DeflateSetOptsOutput(struct lcp_opt *o) +{ + if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') + return MODE_REJ; + + if ((o->data[0] >> 4) + 8 > 15) { + o->data[0] = ((15 - 8) << 4) + 8; + return MODE_NAK; + } + + return MODE_ACK; +} + +static int +DeflateSetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) +{ + int want; + + if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0') + return MODE_REJ; + + want = (o->data[0] >> 4) + 8; + if (cfg->deflate.in.winsize == 0) { + if (want < 8 || want > 15) { + o->data[0] = ((15 - 8) << 4) + 8; + } + } else if (want != cfg->deflate.in.winsize) { + o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8; + return MODE_NAK; + } + + return MODE_ACK; +} + +static void * +DeflateInitInput(struct lcp_opt *o) +{ + struct deflate_state *state; + + state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); + if (state != NULL) { + state->winsize = (o->data[0] >> 4) + 8; + state->cx.zalloc = NULL; + state->cx.opaque = NULL; + state->cx.zfree = NULL; + state->cx.next_out = NULL; + if (inflateInit2(&state->cx, -state->winsize) == Z_OK) + DeflateResetInput(state); + else { + free(state); + state = NULL; + } + } + + return state; +} + +static void * +DeflateInitOutput(struct lcp_opt *o) +{ + struct deflate_state *state; + + state = (struct deflate_state *)malloc(sizeof(struct deflate_state)); + if (state != NULL) { + state->winsize = (o->data[0] >> 4) + 8; + state->cx.zalloc = NULL; + state->cx.opaque = NULL; + state->cx.zfree = NULL; + state->cx.next_in = NULL; + if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8, + -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK) + DeflateResetOutput(state); + else { + free(state); + state = NULL; + } + } + + return state; +} + +static void +DeflateTermInput(void *v) +{ + struct deflate_state *state = (struct deflate_state *)v; + + inflateEnd(&state->cx); + free(state); +} + +static void +DeflateTermOutput(void *v) +{ + struct deflate_state *state = (struct deflate_state *)v; + + deflateEnd(&state->cx); + free(state); +} + +const struct ccp_algorithm PppdDeflateAlgorithm = { + TY_PPPD_DEFLATE, /* pppd (wrongly) expects this ``type'' field */ + CCP_NEG_DEFLATE24, + DeflateDispOpts, + { + DeflateSetOptsInput, + DeflateInitInput, + DeflateTermInput, + DeflateResetInput, + DeflateInput, + DeflateDictSetup + }, + { + DeflateInitOptsOutput, + DeflateSetOptsOutput, + DeflateInitOutput, + DeflateTermOutput, + DeflateResetOutput, + DeflateOutput + }, +}; + +const struct ccp_algorithm DeflateAlgorithm = { + TY_DEFLATE, /* rfc 1979 */ + CCP_NEG_DEFLATE, + DeflateDispOpts, + { + DeflateSetOptsInput, + DeflateInitInput, + DeflateTermInput, + DeflateResetInput, + DeflateInput, + DeflateDictSetup + }, + { + DeflateInitOptsOutput, + DeflateSetOptsOutput, + DeflateInitOutput, + DeflateTermOutput, + DeflateResetOutput, + DeflateOutput + }, +}; diff --git a/usr.sbin/ppp/deflate.h b/usr.sbin/ppp/ppp/deflate.h index 8eac964776f..c29ad82ef4e 100644 --- a/usr.sbin/ppp/deflate.h +++ b/usr.sbin/ppp/ppp/deflate.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: deflate.h,v 1.2 1997/12/21 14:27:02 brian Exp $ + * $Id: deflate.h,v 1.1 1998/08/31 00:22:19 brian Exp $ */ extern const struct ccp_algorithm PppdDeflateAlgorithm; diff --git a/usr.sbin/ppp/defs.c b/usr.sbin/ppp/ppp/defs.c index 2215cdebaaf..1d04277d871 100644 --- a/usr.sbin/ppp/defs.c +++ b/usr.sbin/ppp/ppp/defs.c @@ -23,95 +23,94 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: defs.c,v 1.8 1998/03/13 03:15:32 brian Exp $ + * $Id: defs.c,v 1.1 1998/08/31 00:22:19 brian Exp $ */ -#include <sys/param.h> -#include <netinet/in.h> -#include <errno.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/errno.h> +#if !defined(__FreeBSD__) || __FreeBSD__ < 3 #include <time.h> +#endif #include <unistd.h> #include "defs.h" -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "loadalias.h" -#include "vars.h" - -int mode = MODE_INTER; -int BGFiledes[2] = { -1, -1 }; -int modem = -1; -int tun_in = -1; -int tun_out = -1; -int netfd = -1; - -static char dstsystem[50]; - -void -SetLabel(const char *label) -{ - if (label) - strncpy(dstsystem, label, sizeof dstsystem - 1); - else - *dstsystem = '\0'; -} - -const char * -GetLabel() -{ - return *dstsystem ? dstsystem : NULL; -} void randinit() { #if __FreeBSD__ >= 3 - static int initdone; + static int initdone; /* srandomdev() call is only required once */ if (!initdone) { initdone = 1; srandomdev(); } #else - srandom(time(NULL)^getpid()); + srandom((time(NULL)^getpid())+random()); #endif } - -int -GetShortHost() +ssize_t +fullread(int fd, void *v, size_t n) { - char *p; + size_t got, total; + + for (total = 0; total < n; total += got) + switch ((got = read(fd, (char *)v + total, n - total))) { + case 0: + return total; + case -1: + if (errno == EINTR) + got = 0; + else + return -1; + } + return total; +} - if (gethostname(VarShortHost, sizeof VarShortHost)) { - LogPrintf(LogERROR, "GetShortHost: gethostname: %s\n", strerror(errno)); - return 0; - } +static struct { + int mode; + const char *name; +} modes[] = { + { PHYS_INTERACTIVE, "interactive" }, + { PHYS_AUTO, "auto" }, + { PHYS_DIRECT, "direct" }, + { PHYS_DEDICATED, "dedicated" }, + { PHYS_DDIAL, "ddial" }, + { PHYS_BACKGROUND, "background" }, + { PHYS_ALL, "*" }, + { 0, 0 } +}; - if ((p = strchr(VarShortHost, '.'))) - *p = '\0'; +const char * +mode2Nam(int mode) +{ + int m; - return 1; + for (m = 0; modes[m].mode; m++) + if (modes[m].mode == mode) + return modes[m].name; + + return "unknown"; } -void -DropClient(int verbose) +int +Nam2mode(const char *name) { - FILE *oVarTerm; - - if (VarTerm && !(mode & MODE_INTER)) { - oVarTerm = VarTerm; - VarTerm = 0; - if (oVarTerm) - fclose(oVarTerm); - close(netfd); - netfd = -1; - if (verbose) - LogPrintf(LogPHASE, "Client connection dropped.\n"); - } + int m, got, len; + + len = strlen(name); + got = -1; + for (m = 0; modes[m].mode; m++) + if (!strncasecmp(name, modes[m].name, len)) { + if (modes[m].name[len] == '\0') + return modes[m].mode; + if (got != -1) + return 0; + got = m; + } + + return got == -1 ? 0 : modes[got].mode; } diff --git a/usr.sbin/ppp/defs.h b/usr.sbin/ppp/ppp/defs.h index afeeeb95130..3bc6c9ba795 100644 --- a/usr.sbin/ppp/defs.h +++ b/usr.sbin/ppp/ppp/defs.h @@ -15,57 +15,51 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: defs.h,v 1.2 1997/12/27 13:45:19 brian Exp $ + * $Id: defs.h,v 1.1 1998/08/31 00:22:19 brian Exp $ * * TODO: */ -/* - * Check following definitions for your machine environment - */ +/* Check the following definitions for your machine environment */ #ifdef __FreeBSD__ -# define MODEM_DEV "/dev/cuaa1" /* name of tty device */ -# define BASE_MODEM_DEV "cuaa1" /* name of base tty device */ +# define MODEM_LIST "/dev/cuaa1, /dev/cuaa0" /* name of tty device */ #else # ifdef __OpenBSD__ -# define MODEM_DEV "/dev/cua01" /* name of tty device */ -# define BASE_MODEM_DEV "cua01" /* name of base tty device */ +# define MODEM_LIST "/dev/cua01, /dev/cua00" /* name of tty device */ # else -# define MODEM_DEV "/dev/tty01" /* name of tty device */ -# define BASE_MODEM_DEV "tty01" /* name of base tty device */ +# define MODEM_LIST "/dev/tty01, /dev/tty00" /* name of tty device */ # endif #endif +#define _PATH_PPP "/etc/ppp" + +#define TUN_NAME "tun" +#define TUN_PREFIX (_PATH_DEV TUN_NAME) /* /dev/tun */ + #define MODEM_SPEED B38400 /* tty speed */ #define SERVER_PORT 3000 /* Base server port no. */ #define MODEM_CTSRTS 1 /* Default (true): use CTS/RTS signals */ -#define RECONNECT_TIMER 3 /* Default timer for carrier loss */ -#define RECONNECT_TRIES 0 /* Default retries on carrier loss */ -#define REDIAL_PERIOD 30 /* Default Hold time to redial */ -#define NEXT_REDIAL_PERIOD 3 /* Default Hold time to next number redial */ +#define RECONNECT_TIMEOUT 3 /* Default timer for carrier loss */ +#define DIAL_TIMEOUT 30 /* Default and Max random time to redial */ +#define DIAL_NEXT_TIMEOUT 3 /* Default Hold time to next number redial */ #define SCRIPT_LEN 512 /* Size of login scripts */ #define LINE_LEN SCRIPT_LEN /* Size of login scripts */ #define MAXARGS 40 /* How many args per config line */ +#define NCP_IDLE_TIMEOUT 180 /* Drop all links */ +#define CHOKED_TIMEOUT 120 /* Delete queued packets w/ blocked tun */ + +#define LINK_MINWEIGHT 20 +#define MIN_LQRPERIOD 2 /* Minimum LQR frequency */ +#define DEF_LQRPERIOD 30 /* Default LQR frequency */ +#define MIN_FSMRETRY 3 /* Minimum FSM retry frequency */ +#define DEF_FSMRETRY 3 /* FSM retry frequency */ +#define DEF_REQs 5 /* This number of REQs in IRC */ #define CONFFILE "ppp.conf" #define LINKUPFILE "ppp.linkup" #define LINKDOWNFILE "ppp.linkdown" #define SECRETFILE "ppp.secret" -/* - * Definition of working mode - */ -#define MODE_INTER 1 /* Interactive mode */ -#define MODE_AUTO 2 /* Auto calling mode */ -#define MODE_DIRECT 4 /* Direct connection mode */ -#define MODE_DEDICATED 8 /* Dedicated line mode */ -#define MODE_DDIAL 16 /* Dedicated dialing line mode */ -#define MODE_ALIAS 32 /* Packet aliasing (masquerading) */ -#define MODE_BACKGROUND 64 /* Background mode. */ - -#define MODE_DAEMON (2|4|8|16|64) -#define MODE_OUTGOING_DAEMON (2|8|16|64) - #define EX_SIG -1 #define EX_NORMAL 0 #define EX_START 1 @@ -81,15 +75,17 @@ #define EX_NODIAL 12 #define EX_NOLOGIN 13 -extern int mode; -extern int BGFiledes[2]; -extern int modem; -extern int tun_in; -extern int tun_out; -extern int netfd; +/* physical::type values (OR'd in bundle::phys_type) */ +#define PHYS_NONE 0 +#define PHYS_INTERACTIVE 1 /* Manual link */ +#define PHYS_AUTO 2 /* Dial-on-demand link */ +#define PHYS_DIRECT 4 /* Incoming link, deleted when closed */ +#define PHYS_DEDICATED 8 /* Dedicated link */ +#define PHYS_DDIAL 16 /* Dial immediately, stay connected */ +#define PHYS_BACKGROUND 32 /* Dial immediately, deleted when closed */ +#define PHYS_ALL 63 -extern void SetLabel(const char *); -extern const char *GetLabel(void); extern void randinit(void); -extern int GetShortHost(void); -extern void DropClient(int); +extern ssize_t fullread(int, void *, size_t); +extern const char *mode2Nam(int); +extern int Nam2mode(const char *); diff --git a/usr.sbin/ppp/loadalias.h b/usr.sbin/ppp/ppp/descriptor.h index 8927be6e263..be0cd5a0c89 100644 --- a/usr.sbin/ppp/loadalias.h +++ b/usr.sbin/ppp/ppp/descriptor.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,23 +23,29 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: loadalias.h,v 1.2 1997/12/21 14:27:08 brian Exp $ + * $Id: descriptor.h,v 1.1 1998/08/31 00:22:20 brian Exp $ */ -struct aliasHandlers { - char *(*PacketAliasGetFragment)(char *); - void (*PacketAliasInit)(void); - int (*PacketAliasIn)(char *, int); - int (*PacketAliasOut)(char *, int); - struct alias_link *(*PacketAliasRedirectAddr)(struct in_addr, struct in_addr); - struct alias_link *(*PacketAliasRedirectPort) - (struct in_addr, u_short, struct in_addr, u_short, - struct in_addr, u_short, u_char); - int (*PacketAliasSaveFragment)(char *); - void (*PacketAliasSetAddress)(struct in_addr); - unsigned (*PacketAliasSetMode)(unsigned, unsigned); - void (*PacketAliasFragmentIn)(char *, char *); +#define PHYSICAL_DESCRIPTOR (1) +#define SERVER_DESCRIPTOR (2) +#define PROMPT_DESCRIPTOR (3) +#define CHAT_DESCRIPTOR (4) +#define DATALINK_DESCRIPTOR (5) +#define BUNDLE_DESCRIPTOR (6) +#define MPSERVER_DESCRIPTOR (7) + +struct bundle; + +struct descriptor { + int type; + + int (*UpdateSet)(struct descriptor *, fd_set *, fd_set *, fd_set *, int *); + int (*IsSet)(struct descriptor *, const fd_set *); + void (*Read)(struct descriptor *, struct bundle *, const fd_set *); + int (*Write)(struct descriptor *, struct bundle *, const fd_set *); }; -extern int loadAliasHandlers(struct aliasHandlers *); -extern void unloadAliasHandlers(void); +#define descriptor_UpdateSet(d, r, w, e, n) ((*(d)->UpdateSet)(d, r, w, e, n)) +#define descriptor_IsSet(d, s) ((*(d)->IsSet)(d, s)) +#define descriptor_Read(d, b, f) ((*(d)->Read)(d, b, f)) +#define descriptor_Write(d, b, f) ((*(d)->Write)(d, b, f)) diff --git a/usr.sbin/ppp/ppp/filter.c b/usr.sbin/ppp/ppp/filter.c new file mode 100644 index 00000000000..29591fac11d --- /dev/null +++ b/usr.sbin/ppp/ppp/filter.c @@ -0,0 +1,533 @@ +/* + * PPP Filter command Interface + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: filter.c,v 1.1 1998/08/31 00:22:20 brian Exp $ + * + * TODO: Shoud send ICMP error message when we discard packets. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "iplist.h" +#include "timer.h" +#include "throughput.h" +#include "lqr.h" +#include "hdlc.h" +#include "fsm.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "prompt.h" +#include "mp.h" +#include "bundle.h" + +static int filter_Nam2Proto(int, char const *const *); +static int filter_Nam2Op(const char *); + +static const u_int32_t netmasks[33] = { + 0x00000000, + 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, + 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, + 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, + 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, + 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, + 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, + 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, + 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, +}; + +int +ParseAddr(struct ipcp *ipcp, int argc, char const *const *argv, + struct in_addr *paddr, struct in_addr *pmask, int *pwidth) +{ + int bits, len; + char *wp; + const char *cp; + + if (argc < 1) { + log_Printf(LogWARN, "ParseAddr: address/mask is expected.\n"); + return (0); + } + + if (pmask) + pmask->s_addr = INADDR_BROADCAST; /* Assume 255.255.255.255 as default */ + + cp = pmask || pwidth ? strchr(*argv, '/') : NULL; + len = cp ? cp - *argv : strlen(*argv); + + if (strncasecmp(*argv, "HISADDR", len) == 0) + *paddr = ipcp->peer_ip; + else if (strncasecmp(*argv, "MYADDR", len) == 0) + *paddr = ipcp->my_ip; + else if (len > 15) + log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", *argv); + else { + char s[16]; + strncpy(s, *argv, len); + s[len] = '\0'; + if (inet_aton(s, paddr) == 0) { + log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s); + return (0); + } + } + if (cp && *++cp) { + bits = strtol(cp, &wp, 0); + if (cp == wp || bits < 0 || bits > 32) { + log_Printf(LogWARN, "ParseAddr: bad mask width.\n"); + return (0); + } + } else if (paddr->s_addr == INADDR_ANY) + /* An IP of 0.0.0.0 without a width is anything */ + bits = 0; + else + /* If a valid IP is given without a width, assume 32 bits */ + bits = 32; + + if (pwidth) + *pwidth = bits; + + if (pmask) + pmask->s_addr = htonl(netmasks[bits]); + + return (1); +} + +static int +ParsePort(const char *service, int proto) +{ + const char *protocol_name; + char *cp; + struct servent *servent; + int port; + + switch (proto) { + case P_UDP: + protocol_name = "udp"; + break; + case P_TCP: + protocol_name = "tcp"; + break; + default: + protocol_name = 0; + } + + servent = getservbyname(service, protocol_name); + if (servent != 0) + return (ntohs(servent->s_port)); + + port = strtol(service, &cp, 0); + if (cp == service) { + log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", + service); + return (0); + } + return (port); +} + +/* + * ICMP Syntax: src eq icmp_message_type + */ +static int +ParseIcmp(int argc, char const *const *argv, struct filterent *tgt) +{ + int type; + char *cp; + + switch (argc) { + case 0: + /* permit/deny all ICMP types */ + tgt->opt.srcop = OP_NONE; + break; + + case 3: + if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { + type = strtol(argv[2], &cp, 0); + if (cp == argv[2]) { + log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); + return (0); + } + tgt->opt.srcop = OP_EQ; + tgt->opt.srcport = type; + } + break; + + default: + log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); + return (0); + } + return (1); +} + +/* + * UDP Syntax: [src op port] [dst op port] + */ +static int +ParseUdpOrTcp(int argc, char const *const *argv, int proto, + struct filterent *tgt) +{ + tgt->opt.srcop = tgt->opt.dstop = OP_NONE; + tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0; + + if (argc >= 3 && !strcmp(*argv, "src")) { + tgt->opt.srcop = filter_Nam2Op(argv[1]); + if (tgt->opt.srcop == OP_NONE) { + log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); + return (0); + } + tgt->opt.srcport = ParsePort(argv[2], proto); + if (tgt->opt.srcport == 0) + return (0); + argc -= 3; + argv += 3; + } + + if (argc >= 3 && !strcmp(argv[0], "dst")) { + tgt->opt.dstop = filter_Nam2Op(argv[1]); + if (tgt->opt.dstop == OP_NONE) { + log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); + return (0); + } + tgt->opt.dstport = ParsePort(argv[2], proto); + if (tgt->opt.dstport == 0) + return (0); + argc -= 3; + argv += 3; + } + + if (proto == P_TCP) { + for (; argc > 0; argc--, argv++) + if (!strcmp(*argv, "estab")) + tgt->opt.estab = 1; + else if (!strcmp(*argv, "syn")) + tgt->opt.syn = 1; + else if (!strcmp(*argv, "finrst")) + tgt->opt.finrst = 1; + else + break; + } + + if (argc > 0) { + log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); + return 0; + } + + return 1; +} + +static int +Parse(struct ipcp *ipcp, int argc, char const *const *argv, + struct filterent *ofp) +{ + int action, proto; + int val; + char *wp; + struct filterent filterdata; + + val = strtol(*argv, &wp, 0); + if (*argv == wp || val > MAXFILTERS) { + log_Printf(LogWARN, "Parse: invalid filter number.\n"); + return (0); + } + if (val < 0) { + for (val = 0; val < MAXFILTERS; val++) { + ofp->action = A_NONE; + ofp++; + } + log_Printf(LogWARN, "Parse: filter cleared.\n"); + return (1); + } + ofp += val; + + if (--argc == 0) { + log_Printf(LogWARN, "Parse: missing action.\n"); + return (0); + } + argv++; + + proto = P_NONE; + memset(&filterdata, '\0', sizeof filterdata); + + if (!strcmp(*argv, "permit")) { + action = A_PERMIT; + } else if (!strcmp(*argv, "deny")) { + action = A_DENY; + } else if (!strcmp(*argv, "clear")) { + ofp->action = A_NONE; + return (1); + } else { + log_Printf(LogWARN, "Parse: bad action: %s\n", *argv); + return (0); + } + filterdata.action = action; + + argc--; + argv++; + + if (filterdata.action == A_DENY) { + if (!strcmp(*argv, "host")) { + filterdata.action |= A_UHOST; + argc--; + argv++; + } else if (!strcmp(*argv, "port")) { + filterdata.action |= A_UPORT; + argc--; + argv++; + } + } + proto = filter_Nam2Proto(argc, argv); + if (proto == P_NONE) { + if (ParseAddr(ipcp, argc, argv, &filterdata.saddr, &filterdata.smask, + &filterdata.swidth)) { + argc--; + argv++; + proto = filter_Nam2Proto(argc, argv); + if (proto == P_NONE) { + if (ParseAddr(ipcp, argc, argv, &filterdata.daddr, &filterdata.dmask, + &filterdata.dwidth)) { + argc--; + argv++; + } + proto = filter_Nam2Proto(argc, argv); + if (proto != P_NONE) { + argc--; + argv++; + } + } else { + argc--; + argv++; + } + } else { + log_Printf(LogWARN, "Parse: Address/protocol expected.\n"); + return (0); + } + } else { + argc--; + argv++; + } + + val = 1; + filterdata.proto = proto; + + switch (proto) { + case P_TCP: + val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata); + break; + case P_UDP: + val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata); + break; + case P_ICMP: + val = ParseIcmp(argc, argv, &filterdata); + break; + } + + log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.saddr)); + log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.smask)); + log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.daddr)); + log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dmask)); + log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto); + + log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", + filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport); + log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", + filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport); + log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab); + log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn); + log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst); + + if (val) + *ofp = filterdata; + return (val); +} + +int +filter_Set(struct cmdargs const *arg) +{ + struct filter *filter; + + if (arg->argc < arg->argn+2) + return -1; + + if (!strcmp(arg->argv[arg->argn], "in")) + filter = &arg->bundle->filter.in; + else if (!strcmp(arg->argv[arg->argn], "out")) + filter = &arg->bundle->filter.out; + else if (!strcmp(arg->argv[arg->argn], "dial")) + filter = &arg->bundle->filter.dial; + else if (!strcmp(arg->argv[arg->argn], "alive")) + filter = &arg->bundle->filter.alive; + else { + log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", + arg->argv[arg->argn]); + return -1; + } + + Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1, + arg->argv + arg->argn + 1, filter->rule); + return 0; +} + +const char * +filter_Action2Nam(int act) +{ + static const char *actname[] = { "none ", "permit ", "deny " }; + return actname[act & (A_PERMIT|A_DENY)]; +} + +static void +doShowFilter(struct filterent *fp, struct prompt *prompt) +{ + int n; + + for (n = 0; n < MAXFILTERS; n++, fp++) { + if (fp->action != A_NONE) { + prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->action)); + if (fp->action & A_UHOST) + prompt_Printf(prompt, "host "); + else if (fp->action & A_UPORT) + prompt_Printf(prompt, "port "); + else + prompt_Printf(prompt, " "); + prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth); + prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); + if (fp->proto) { + prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto)); + + if (fp->opt.srcop) + prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop), + fp->opt.srcport); + if (fp->opt.dstop) + prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop), + fp->opt.dstport); + if (fp->opt.estab) + prompt_Printf(prompt, " estab"); + if (fp->opt.syn) + prompt_Printf(prompt, " syn"); + if (fp->opt.finrst) + prompt_Printf(prompt, " finrst"); + } + prompt_Printf(prompt, "\n"); + } + } +} + +int +filter_Show(struct cmdargs const *arg) +{ + if (arg->argc > arg->argn+1) + return -1; + + if (arg->argc == arg->argn+1) { + struct filter *filter; + + if (!strcmp(arg->argv[arg->argn], "in")) + filter = &arg->bundle->filter.in; + else if (!strcmp(arg->argv[arg->argn], "out")) + filter = &arg->bundle->filter.out; + else if (!strcmp(arg->argv[arg->argn], "dial")) + filter = &arg->bundle->filter.dial; + else if (!strcmp(arg->argv[arg->argn], "alive")) + filter = &arg->bundle->filter.alive; + else + return -1; + doShowFilter(filter->rule, arg->prompt); + } else { + struct filter *filter[4]; + int f; + + filter[0] = &arg->bundle->filter.in; + filter[1] = &arg->bundle->filter.out; + filter[2] = &arg->bundle->filter.dial; + filter[3] = &arg->bundle->filter.alive; + for (f = 0; f < 4; f++) { + if (f) + prompt_Printf(arg->prompt, "\n"); + prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); + doShowFilter(filter[f]->rule, arg->prompt); + } + } + + return 0; +} + +static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; + +const char * +filter_Proto2Nam(int proto) +{ + if (proto >= sizeof protoname / sizeof protoname[0]) + return "unknown"; + return protoname[proto]; +} + +static int +filter_Nam2Proto(int argc, char const *const *argv) +{ + int proto; + + if (argc == 0) + proto = 0; + else + for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--) + if (!strcasecmp(*argv, protoname[proto])) + break; + + return proto; +} + +static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"}; + +const char * +filter_Op2Nam(int op) +{ + if (op >= sizeof opname / sizeof opname[0]) + return "unknown"; + return opname[op]; + +} + +static int +filter_Nam2Op(const char *cp) +{ + int op; + + for (op = sizeof opname / sizeof opname[0] - 1; op; op--) + if (!strcasecmp(cp, opname[op])) + break; + + return op; +} diff --git a/usr.sbin/ppp/filter.h b/usr.sbin/ppp/ppp/filter.h index 6235b9f6c84..5b1325c4c06 100644 --- a/usr.sbin/ppp/filter.h +++ b/usr.sbin/ppp/ppp/filter.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: filter.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * $Id: filter.h,v 1.1 1998/08/31 00:22:20 brian Exp $ * * TODO: */ @@ -60,28 +60,33 @@ struct filterent { u_short srcport; short dstop; u_short dstport; - int estab; + unsigned estab : 1; + unsigned syn : 1; + unsigned finrst : 1; } opt; }; -#define MAXFILTERS 20 +#define MAXFILTERS 20 /* in each filter set */ + +struct filter { + struct filterent rule[MAXFILTERS]; /* incoming packet filter */ + const char *name; + unsigned fragok : 1; + unsigned logok : 1; +}; #define FL_IN 0 #define FL_OUT 1 #define FL_DIAL 2 #define FL_KEEP 3 -extern struct filterent ifilters[MAXFILTERS]; /* incoming packet filter */ -extern struct filterent ofilters[MAXFILTERS]; /* outgoing packet filter */ -extern struct filterent dfilters[MAXFILTERS]; /* dial-out packet filter */ -extern struct filterent afilters[MAXFILTERS]; /* keep-alive packet filter */ +struct ipcp; +struct cmdargs; -extern int ParseAddr(int, char const *const *, struct in_addr *, struct in_addr *, int *); -extern int ShowIfilter(struct cmdargs const *); -extern int ShowOfilter(struct cmdargs const *); -extern int ShowDfilter(struct cmdargs const *); -extern int ShowAfilter(struct cmdargs const *); -extern int SetIfilter(struct cmdargs const *); -extern int SetOfilter(struct cmdargs const *); -extern int SetDfilter(struct cmdargs const *); -extern int SetAfilter(struct cmdargs const *); +extern int ParseAddr(struct ipcp *, int, char const *const *, struct in_addr *, + struct in_addr *, int *); +extern int filter_Show(struct cmdargs const *); +extern int filter_Set(struct cmdargs const *); +extern const char * filter_Action2Nam(int); +extern const char *filter_Proto2Nam(int); +extern const char *filter_Op2Nam(int); diff --git a/usr.sbin/ppp/ppp/fsm.c b/usr.sbin/ppp/ppp/fsm.c new file mode 100644 index 00000000000..3f576adc368 --- /dev/null +++ b/usr.sbin/ppp/ppp/fsm.c @@ -0,0 +1,1014 @@ +/* + * PPP Finite State Machine for LCP/IPCP + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: fsm.c,v 1.1 1998/08/31 00:22:20 brian Exp $ + * + * TODO: + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <string.h> +#include <termios.h> + +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "lqr.h" +#include "hdlc.h" +#include "throughput.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" +#include "async.h" +#include "physical.h" +#include "lcpproto.h" + +static void FsmSendConfigReq(struct fsm *); +static void FsmSendTerminateReq(struct fsm *); +static void FsmInitRestartCounter(struct fsm *); + +typedef void (recvfn)(struct fsm *, struct fsmheader *, struct mbuf *); +static recvfn FsmRecvConfigReq, FsmRecvConfigAck, FsmRecvConfigNak, + FsmRecvConfigRej, FsmRecvTermReq, FsmRecvTermAck, + FsmRecvCodeRej, FsmRecvProtoRej, FsmRecvEchoReq, + FsmRecvEchoRep, FsmRecvDiscReq, FsmRecvIdent, + FsmRecvTimeRemain, FsmRecvResetReq, FsmRecvResetAck; + +static const struct fsmcodedesc { + recvfn *recv; + unsigned check_reqid : 1; + unsigned inc_reqid : 1; + const char *name; +} FsmCodes[] = { + { FsmRecvConfigReq, 0, 0, "ConfigReq" }, + { FsmRecvConfigAck, 1, 1, "ConfigAck" }, + { FsmRecvConfigNak, 1, 1, "ConfigNak" }, + { FsmRecvConfigRej, 1, 1, "ConfigRej" }, + { FsmRecvTermReq, 0, 0, "TerminateReq" }, + { FsmRecvTermAck, 1, 1, "TerminateAck" }, + { FsmRecvCodeRej, 0, 0, "CodeRej" }, + { FsmRecvProtoRej, 0, 0, "ProtocolRej" }, + { FsmRecvEchoReq, 0, 0, "EchoRequest" }, + { FsmRecvEchoRep, 0, 0, "EchoReply" }, + { FsmRecvDiscReq, 0, 0, "DiscardReq" }, + { FsmRecvIdent, 0, 0, "Ident" }, + { FsmRecvTimeRemain,0, 0, "TimeRemain" }, + { FsmRecvResetReq, 0, 0, "ResetReqt" }, + { FsmRecvResetAck, 0, 1, "ResetAck" } +}; + +static const char * +Code2Nam(u_int code) +{ + if (code == 0 || code > sizeof FsmCodes / sizeof FsmCodes[0]) + return "Unknown"; + return FsmCodes[code-1].name; +} + +const char * +State2Nam(u_int state) +{ + static const char *StateNames[] = { + "Initial", "Starting", "Closed", "Stopped", "Closing", "Stopping", + "Req-Sent", "Ack-Rcvd", "Ack-Sent", "Opened", + }; + + if (state >= sizeof StateNames / sizeof StateNames[0]) + return "unknown"; + return StateNames[state]; +} + +static void +StoppedTimeout(void *v) +{ + struct fsm *fp = (struct fsm *)v; + + log_Printf(fp->LogLevel, "%s: Stopped timer expired\n", fp->link->name); + if (fp->OpenTimer.state == TIMER_RUNNING) { + log_Printf(LogWARN, "%s: %s: aborting open delay due to stopped timer\n", + fp->link->name, fp->name); + timer_Stop(&fp->OpenTimer); + } + if (fp->state == ST_STOPPED) + fsm2initial(fp); +} + +void +fsm_Init(struct fsm *fp, const char *name, u_short proto, int mincode, + int maxcode, int maxcfg, int LogLevel, struct bundle *bundle, + struct link *l, const struct fsm_parent *parent, + struct fsm_callbacks *fn, const char *timer_names[3]) +{ + fp->name = name; + fp->proto = proto; + fp->min_code = mincode; + fp->max_code = maxcode; + fp->state = fp->min_code > CODE_TERMACK ? ST_OPENED : ST_INITIAL; + fp->reqid = 1; + fp->restart = 1; + fp->maxconfig = maxcfg; + memset(&fp->FsmTimer, '\0', sizeof fp->FsmTimer); + memset(&fp->OpenTimer, '\0', sizeof fp->OpenTimer); + memset(&fp->StoppedTimer, '\0', sizeof fp->StoppedTimer); + fp->LogLevel = LogLevel; + fp->link = l; + fp->bundle = bundle; + fp->parent = parent; + fp->fn = fn; + fp->FsmTimer.name = timer_names[0]; + fp->OpenTimer.name = timer_names[1]; + fp->StoppedTimer.name = timer_names[2]; +} + +static void +NewState(struct fsm * fp, int new) +{ + log_Printf(fp->LogLevel, "%s: State change %s --> %s\n", + fp->link->name, State2Nam(fp->state), State2Nam(new)); + if (fp->state == ST_STOPPED && fp->StoppedTimer.state == TIMER_RUNNING) + timer_Stop(&fp->StoppedTimer); + fp->state = new; + if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED)) { + timer_Stop(&fp->FsmTimer); + if (new == ST_STOPPED && fp->StoppedTimer.load) { + timer_Stop(&fp->StoppedTimer); + fp->StoppedTimer.func = StoppedTimeout; + fp->StoppedTimer.arg = (void *) fp; + timer_Start(&fp->StoppedTimer); + } + } +} + +void +fsm_Output(struct fsm *fp, u_int code, u_int id, u_char *ptr, int count) +{ + int plen; + struct fsmheader lh; + struct mbuf *bp; + + if (log_IsKept(fp->LogLevel)) { + log_Printf(fp->LogLevel, "%s: Send%s(%d) state = %s\n", + fp->link->name, Code2Nam(code), id, State2Nam(fp->state)); + switch (code) { + case CODE_CONFIGREQ: + case CODE_CONFIGACK: + case CODE_CONFIGREJ: + case CODE_CONFIGNAK: + (*fp->fn->DecodeConfig)(fp, ptr, count, MODE_NOP, NULL); + if (count < sizeof(struct fsmconfig)) + log_Printf(fp->LogLevel, " [EMPTY]\n"); + break; + } + } + + plen = sizeof(struct fsmheader) + count; + lh.code = code; + lh.id = id; + lh.length = htons(plen); + bp = mbuf_Alloc(plen, MB_FSM); + memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); + if (count) + memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); + log_DumpBp(LogDEBUG, "fsm_Output", bp); + hdlc_Output(fp->link, PRI_LINK, fp->proto, bp); +} + +static void +FsmOpenNow(void *v) +{ + struct fsm *fp = (struct fsm *)v; + + timer_Stop(&fp->OpenTimer); + if (fp->state <= ST_STOPPED) { + if (fp->state != ST_STARTING) { + /* + * In practice, we're only here in ST_STOPPED (when delaying the + * first config request) or ST_CLOSED (when openmode == 0). + * + * The ST_STOPPED bit is breaking the RFC already :-( + * + * According to the RFC (1661) state transition table, a TLS isn't + * required for an Open event when state == Closed, but the RFC + * must be wrong as TLS hasn't yet been called (since the last TLF) + * ie, Initial gets an `Up' event, Closing gets a RTA etc. + */ + (*fp->fn->LayerStart)(fp); + (*fp->parent->LayerStart)(fp->parent->object, fp); + } + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + } +} + +void +fsm_Open(struct fsm * fp) +{ + switch (fp->state) { + case ST_INITIAL: + NewState(fp, ST_STARTING); + (*fp->fn->LayerStart)(fp); + (*fp->parent->LayerStart)(fp->parent->object, fp); + break; + case ST_CLOSED: + if (fp->open_mode == OPEN_PASSIVE) { + NewState(fp, ST_STOPPED); /* XXX: This is a hack ! */ + } else if (fp->open_mode > 0) { + if (fp->open_mode > 1) + log_Printf(LogPHASE, "%s: Entering STOPPED state for %d seconds\n", + fp->link->name, fp->open_mode); + NewState(fp, ST_STOPPED); /* XXX: This is a not-so-bad hack ! */ + timer_Stop(&fp->OpenTimer); + fp->OpenTimer.load = fp->open_mode * SECTICKS; + fp->OpenTimer.func = FsmOpenNow; + fp->OpenTimer.arg = (void *)fp; + timer_Start(&fp->OpenTimer); + } else + FsmOpenNow(fp); + break; + case ST_STOPPED: /* XXX: restart option */ + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + case ST_OPENED: /* XXX: restart option */ + break; + case ST_CLOSING: /* XXX: restart option */ + case ST_STOPPING: /* XXX: restart option */ + NewState(fp, ST_STOPPING); + break; + } +} + +void +fsm_Up(struct fsm * fp) +{ + switch (fp->state) { + case ST_INITIAL: + log_Printf(fp->LogLevel, "FSM: Using \"%s\" as a transport\n", + fp->link->name); + NewState(fp, ST_CLOSED); + break; + case ST_STARTING: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + default: + log_Printf(fp->LogLevel, "%s: Oops, Up at %s\n", + fp->link->name, State2Nam(fp->state)); + break; + } +} + +void +fsm_Down(struct fsm *fp) +{ + switch (fp->state) { + case ST_CLOSED: + NewState(fp, ST_INITIAL); + break; + case ST_CLOSING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_INITIAL); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_STOPPED: + NewState(fp, ST_STARTING); + (*fp->fn->LayerStart)(fp); + (*fp->parent->LayerStart)(fp->parent->object, fp); + break; + case ST_STOPPING: + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + NewState(fp, ST_STARTING); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + NewState(fp, ST_STARTING); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + } +} + +void +fsm_Close(struct fsm *fp) +{ + switch (fp->state) { + case ST_STARTING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_INITIAL); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_STOPPED: + NewState(fp, ST_CLOSED); + break; + case ST_STOPPING: + NewState(fp, ST_CLOSING); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + FsmInitRestartCounter(fp); + FsmSendTerminateReq(fp); + NewState(fp, ST_CLOSING); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + case ST_REQSENT: + case ST_ACKRCVD: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendTerminateReq(fp); + NewState(fp, ST_CLOSING); + break; + } +} + +/* + * Send functions + */ +static void +FsmSendConfigReq(struct fsm * fp) +{ + if (--fp->maxconfig > 0) { + (*fp->fn->SendConfigReq)(fp); + timer_Start(&fp->FsmTimer); /* Start restart timer */ + fp->restart--; /* Decrement restart counter */ + } else { + fsm_Close(fp); + } +} + +static void +FsmSendTerminateReq(struct fsm *fp) +{ + fsm_Output(fp, CODE_TERMREQ, fp->reqid, NULL, 0); + (*fp->fn->SentTerminateReq)(fp); + timer_Start(&fp->FsmTimer); /* Start restart timer */ + fp->restart--; /* Decrement restart counter */ +} + +/* + * Timeout actions + */ +static void +FsmTimeout(void *v) +{ + struct fsm *fp = (struct fsm *)v; + + if (fp->restart) { + switch (fp->state) { + case ST_CLOSING: + case ST_STOPPING: + FsmSendTerminateReq(fp); + break; + case ST_REQSENT: + case ST_ACKSENT: + FsmSendConfigReq(fp); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + timer_Start(&fp->FsmTimer); + } else { + switch (fp->state) { + case ST_CLOSING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_CLOSED); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_STOPPING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_STOPPED); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_REQSENT: /* XXX: 3p */ + case ST_ACKSENT: + case ST_ACKRCVD: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_STOPPED); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + } + } +} + +static void +FsmInitRestartCounter(struct fsm * fp) +{ + timer_Stop(&fp->FsmTimer); + fp->FsmTimer.func = FsmTimeout; + fp->FsmTimer.arg = (void *) fp; + (*fp->fn->InitRestartCounter)(fp); +} + +/* + * Actions when receive packets + */ +static void +FsmRecvConfigReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +/* RCR */ +{ + struct fsm_decode dec; + int plen, flen; + int ackaction = 0; + + plen = mbuf_Length(bp); + flen = ntohs(lhp->length) - sizeof *lhp; + if (plen < flen) { + log_Printf(LogWARN, "%s: FsmRecvConfigReq: plen (%d) < flen (%d)\n", + fp->link->name, plen, flen); + mbuf_Free(bp); + return; + } + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + if (fp->proto == PROTO_CCP && fp->link->lcp.fsm.state == ST_OPENED) { + /* + * ccp_SetOpenMode() leaves us in initial if we're disabling + * & denying everything. This is a bit smelly, we know that + * ``bp'' really has ``fsmheader'' in front of it, and CCP_PROTO + * in front of that. CCP_PROTO isn't compressed either 'cos it + * doesn't begin with 0x00.... + */ + bp->offset -= sizeof(struct fsmheader) + 2; + bp->cnt += sizeof(struct fsmheader) + 2; + lcp_SendProtoRej(&fp->link->lcp, MBUF_CTOP(bp), bp->cnt); + mbuf_Free(bp); + return; + } + /* Drop through */ + case ST_STARTING: + log_Printf(fp->LogLevel, "%s: Oops, RCR in %s.\n", + fp->link->name, State2Nam(fp->state)); + mbuf_Free(bp); + return; + case ST_CLOSED: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + mbuf_Free(bp); + return; + case ST_CLOSING: + log_Printf(fp->LogLevel, "%s: Error: Got ConfigReq while state = %s\n", + fp->link->name, State2Nam(fp->state)); + case ST_STOPPING: + mbuf_Free(bp); + return; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + } + + dec.ackend = dec.ack; + dec.nakend = dec.nak; + dec.rejend = dec.rej; + (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REQ, &dec); + if (flen < sizeof(struct fsmconfig)) + log_Printf(fp->LogLevel, " [EMPTY]\n"); + + if (dec.nakend == dec.nak && dec.rejend == dec.rej) + ackaction = 1; + + switch (fp->state) { + case ST_STOPPED: + FsmInitRestartCounter(fp); + /* Fall through */ + + case ST_OPENED: + FsmSendConfigReq(fp); + break; + } + + if (dec.rejend != dec.rej) + fsm_Output(fp, CODE_CONFIGREJ, lhp->id, dec.rej, dec.rejend - dec.rej); + if (dec.nakend != dec.nak) + fsm_Output(fp, CODE_CONFIGNAK, lhp->id, dec.nak, dec.nakend - dec.nak); + if (ackaction) + fsm_Output(fp, CODE_CONFIGACK, lhp->id, dec.ack, dec.ackend - dec.ack); + + switch (fp->state) { + case ST_OPENED: + case ST_STOPPED: + if (ackaction) + NewState(fp, ST_ACKSENT); + else + NewState(fp, ST_REQSENT); + break; + case ST_REQSENT: + if (ackaction) + NewState(fp, ST_ACKSENT); + break; + case ST_ACKRCVD: + if (ackaction) { + NewState(fp, ST_OPENED); + if ((*fp->fn->LayerUp)(fp)) + (*fp->parent->LayerUp)(fp->parent->object, fp); + else { + (*fp->fn->LayerDown)(fp); + FsmInitRestartCounter(fp); + FsmSendTerminateReq(fp); + NewState(fp, ST_CLOSING); + } + } + break; + case ST_ACKSENT: + if (!ackaction) + NewState(fp, ST_REQSENT); + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvConfigAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +/* RCA */ +{ + switch (fp->state) { + case ST_CLOSED: + case ST_STOPPED: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + break; + case ST_CLOSING: + case ST_STOPPING: + break; + case ST_REQSENT: + FsmInitRestartCounter(fp); + NewState(fp, ST_ACKRCVD); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + case ST_ACKSENT: + FsmInitRestartCounter(fp); + NewState(fp, ST_OPENED); + if ((*fp->fn->LayerUp)(fp)) + (*fp->parent->LayerUp)(fp->parent->object, fp); + else { + (*fp->fn->LayerDown)(fp); + FsmInitRestartCounter(fp); + FsmSendTerminateReq(fp); + NewState(fp, ST_CLOSING); + } + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvConfigNak(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +/* RCN */ +{ + struct fsm_decode dec; + int plen, flen; + + plen = mbuf_Length(bp); + flen = ntohs(lhp->length) - sizeof *lhp; + if (plen < flen) { + mbuf_Free(bp); + return; + } + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + log_Printf(fp->LogLevel, "%s: Oops, RCN in %s.\n", + fp->link->name, State2Nam(fp->state)); + mbuf_Free(bp); + return; + case ST_CLOSED: + case ST_STOPPED: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + mbuf_Free(bp); + return; + case ST_CLOSING: + case ST_STOPPING: + mbuf_Free(bp); + return; + } + + dec.ackend = dec.ack; + dec.nakend = dec.nak; + dec.rejend = dec.rej; + (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_NAK, &dec); + if (flen < sizeof(struct fsmconfig)) + log_Printf(fp->LogLevel, " [EMPTY]\n"); + + switch (fp->state) { + case ST_REQSENT: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + + mbuf_Free(bp); +} + +static void +FsmRecvTermReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +/* RTR */ +{ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + log_Printf(fp->LogLevel, "%s: Oops, RTR in %s\n", + fp->link->name, State2Nam(fp->state)); + break; + case ST_CLOSED: + case ST_STOPPED: + case ST_CLOSING: + case ST_STOPPING: + case ST_REQSENT: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + break; + case ST_ACKRCVD: + case ST_ACKSENT: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + NewState(fp, ST_REQSENT); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + (*fp->fn->SendTerminateAck)(fp, lhp->id); + FsmInitRestartCounter(fp); + timer_Start(&fp->FsmTimer); /* Start restart timer */ + fp->restart = 0; + NewState(fp, ST_STOPPING); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvTermAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) +/* RTA */ +{ + switch (fp->state) { + case ST_CLOSING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_CLOSED); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_STOPPING: + (*fp->fn->LayerFinish)(fp); + NewState(fp, ST_STOPPED); + (*fp->parent->LayerFinish)(fp->parent->object, fp); + break; + case ST_ACKRCVD: + NewState(fp, ST_REQSENT); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvConfigRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +/* RCJ */ +{ + struct fsm_decode dec; + int plen, flen; + + plen = mbuf_Length(bp); + flen = ntohs(lhp->length) - sizeof *lhp; + if (plen < flen) { + mbuf_Free(bp); + return; + } + + /* + * Check and process easy case + */ + switch (fp->state) { + case ST_INITIAL: + case ST_STARTING: + log_Printf(fp->LogLevel, "%s: Oops, RCJ in %s.\n", + fp->link->name, State2Nam(fp->state)); + mbuf_Free(bp); + return; + case ST_CLOSED: + case ST_STOPPED: + (*fp->fn->SendTerminateAck)(fp, lhp->id); + mbuf_Free(bp); + return; + case ST_CLOSING: + case ST_STOPPING: + mbuf_Free(bp); + return; + } + + dec.ackend = dec.ack; + dec.nakend = dec.nak; + dec.rejend = dec.rej; + (*fp->fn->DecodeConfig)(fp, MBUF_CTOP(bp), flen, MODE_REJ, &dec); + if (flen < sizeof(struct fsmconfig)) + log_Printf(fp->LogLevel, " [EMPTY]\n"); + + switch (fp->state) { + case ST_REQSENT: + case ST_ACKSENT: + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + break; + case ST_OPENED: + (*fp->fn->LayerDown)(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + (*fp->parent->LayerDown)(fp->parent->object, fp); + break; + case ST_ACKRCVD: + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvCodeRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + mbuf_Free(bp); +} + +static void +FsmRecvProtoRej(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + struct physical *p = link2physical(fp->link); + u_short *sp, proto; + + sp = (u_short *)MBUF_CTOP(bp); + proto = ntohs(*sp); + log_Printf(fp->LogLevel, "%s: -- Protocol 0x%04x (%s) was rejected!\n", + fp->link->name, proto, hdlc_Protocol2Nam(proto)); + + switch (proto) { + case PROTO_LQR: + if (p) + lqr_Stop(p, LQM_LQR); + else + log_Printf(LogERROR, "%s: FsmRecvProtoRej: Not a physical link !\n", + fp->link->name); + break; + case PROTO_CCP: + if (fp->proto == PROTO_LCP) { + fp = &fp->link->ccp.fsm; + (*fp->fn->LayerFinish)(fp); + switch (fp->state) { + case ST_CLOSED: + case ST_CLOSING: + NewState(fp, ST_CLOSED); + default: + NewState(fp, ST_STOPPED); + break; + } + (*fp->parent->LayerFinish)(fp->parent->object, fp); + } + break; + case PROTO_MP: + if (fp->proto == PROTO_LCP) { + struct lcp *lcp = fsm2lcp(fp); + + if (lcp->want_mrru && lcp->his_mrru) { + log_Printf(LogPHASE, "%s: MP protocol reject is fatal !\n", + fp->link->name); + fsm_Close(fp); + } + } + break; + } + mbuf_Free(bp); +} + +static void +FsmRecvEchoReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + struct lcp *lcp = fsm2lcp(fp); + u_char *cp; + u_int32_t magic; + + if (lcp) { + cp = MBUF_CTOP(bp); + magic = ntohl(*(u_int32_t *)cp); + if (magic != lcp->his_magic) { + log_Printf(fp->LogLevel, "%s: RecvEchoReq: Error: His magic is bad!!\n", + fp->link->name); + /* XXX: We should send terminate request */ + } + if (fp->state == ST_OPENED) { + *(u_int32_t *)cp = htonl(lcp->want_magic); /* local magic */ + fsm_Output(fp, CODE_ECHOREP, lhp->id, cp, mbuf_Length(bp)); + } + } + mbuf_Free(bp); +} + +static void +FsmRecvEchoRep(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + struct lcp *lcp = fsm2lcp(fp); + u_int32_t magic; + + if (lcp) { + magic = ntohl(*(u_int32_t *)MBUF_CTOP(bp)); + /* Tolerate echo replies with either magic number */ + if (magic != 0 && magic != lcp->his_magic && magic != lcp->want_magic) { + log_Printf(LogWARN, + "%s: RecvEchoRep: Bad magic: expected 0x%08x, got: 0x%08x\n", + fp->link->name, lcp->his_magic, magic); + /* + * XXX: We should send terminate request. But poor implementations may + * die as a result. + */ + } + lqr_RecvEcho(fp, bp); + } + mbuf_Free(bp); +} + +static void +FsmRecvDiscReq(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) +{ + mbuf_Free(bp); +} + +static void +FsmRecvIdent(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) +{ + mbuf_Free(bp); +} + +static void +FsmRecvTimeRemain(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) +{ + mbuf_Free(bp); +} + +static void +FsmRecvResetReq(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + (*fp->fn->RecvResetReq)(fp); + /* + * All sendable compressed packets are queued in the PRI_NORMAL modem + * output queue.... dump 'em to the priority queue so that they arrive + * at the peer before our ResetAck. + */ + link_SequenceQueue(fp->link); + fsm_Output(fp, CODE_RESETACK, lhp->id, NULL, 0); + mbuf_Free(bp); +} + +static void +FsmRecvResetAck(struct fsm *fp, struct fsmheader *lhp, struct mbuf *bp) +{ + (*fp->fn->RecvResetAck)(fp, lhp->id); + mbuf_Free(bp); +} + +void +fsm_Input(struct fsm *fp, struct mbuf *bp) +{ + int len; + struct fsmheader *lhp; + const struct fsmcodedesc *codep; + + len = mbuf_Length(bp); + if (len < sizeof(struct fsmheader)) { + mbuf_Free(bp); + return; + } + lhp = (struct fsmheader *) MBUF_CTOP(bp); + if (lhp->code < fp->min_code || lhp->code > fp->max_code || + lhp->code > sizeof FsmCodes / sizeof *FsmCodes) { + /* + * Use a private id. This is really a response-type packet, but we + * MUST send a unique id for each REQ.... + */ + static u_char id; + + fsm_Output(fp, CODE_CODEREJ, id++, MBUF_CTOP(bp), bp->cnt); + mbuf_Free(bp); + return; + } + bp->offset += sizeof(struct fsmheader); + bp->cnt -= sizeof(struct fsmheader); + + codep = FsmCodes + lhp->code - 1; + if (lhp->id != fp->reqid && codep->check_reqid && + Enabled(fp->bundle, OPT_IDCHECK)) { + log_Printf(fp->LogLevel, "%s: Recv%s(%d), dropped (expected %d)\n", + fp->link->name, codep->name, lhp->id, fp->reqid); + return; + } + + log_Printf(fp->LogLevel, "%s: Recv%s(%d) state = %s\n", + fp->link->name, codep->name, lhp->id, State2Nam(fp->state)); + + if (log_IsKept(LogDEBUG)) + mbuf_Log(); + + if (codep->inc_reqid && (lhp->id == fp->reqid || + (!Enabled(fp->bundle, OPT_IDCHECK) && codep->check_reqid))) + fp->reqid++; /* That's the end of that ``exchange''.... */ + + (*codep->recv)(fp, lhp, bp); + + if (log_IsKept(LogDEBUG)) + mbuf_Log(); +} + +void +fsm_NullRecvResetReq(struct fsm *fp) +{ + log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset req\n", + fp->link->name); +} + +void +fsm_NullRecvResetAck(struct fsm *fp, u_char id) +{ + log_Printf(fp->LogLevel, "%s: Oops - received unexpected reset ack\n", + fp->link->name); +} + +void +fsm_Reopen(struct fsm *fp) +{ + if (fp->state == ST_OPENED) { + (*fp->fn->LayerDown)(fp); + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + (*fp->parent->LayerDown)(fp->parent->object, fp); + } +} + +void +fsm2initial(struct fsm *fp) +{ + if (fp->state == ST_STOPPED) + fsm_Close(fp); + if (fp->state > ST_INITIAL) + fsm_Down(fp); + if (fp->state > ST_INITIAL) + fsm_Close(fp); +} diff --git a/usr.sbin/ppp/fsm.h b/usr.sbin/ppp/ppp/fsm.h index 09355d18d6e..b2fc4dd9707 100644 --- a/usr.sbin/ppp/fsm.h +++ b/usr.sbin/ppp/ppp/fsm.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: fsm.h,v 1.5 1998/01/21 02:13:31 brian Exp $ + * $Id: fsm.h,v 1.1 1998/08/31 00:22:20 brian Exp $ * * TODO: */ @@ -45,15 +45,50 @@ #define OPEN_PASSIVE -1 +struct fsm; + +struct fsm_decode { + u_char ack[100], *ackend; + u_char nak[100], *nakend; + u_char rej[100], *rejend; +}; + +struct fsm_callbacks { + int (*LayerUp) (struct fsm *); /* Layer is now up (tlu) */ + void (*LayerDown) (struct fsm *); /* About to come down (tld) */ + void (*LayerStart) (struct fsm *); /* Layer about to start up (tls) */ + void (*LayerFinish) (struct fsm *); /* Layer now down (tlf) */ + void (*InitRestartCounter) (struct fsm *); /* Set fsm timer load */ + void (*SendConfigReq) (struct fsm *); /* Send REQ please */ + void (*SentTerminateReq) (struct fsm *); /* Term REQ just sent */ + void (*SendTerminateAck) (struct fsm *, u_char); /* Send Term ACK please */ + void (*DecodeConfig) (struct fsm *, u_char *, int, int, struct fsm_decode *); + /* Deal with incoming data */ + void (*RecvResetReq) (struct fsm *fp); /* Reset output */ + void (*RecvResetAck) (struct fsm *fp, u_char); /* Reset input */ +}; + +struct fsm_parent { + void (*LayerStart) (void *, struct fsm *); /* tls */ + void (*LayerUp) (void *, struct fsm *); /* tlu */ + void (*LayerDown) (void *, struct fsm *); /* tld */ + void (*LayerFinish) (void *, struct fsm *); /* tlf */ + void *object; +}; + +struct link; +struct bundle; + struct fsm { const char *name; /* Name of protocol */ u_short proto; /* Protocol number */ + u_short min_code; u_short max_code; - int open_mode; + int open_mode; /* Delay before config REQ (-1 forever) */ int state; /* State of the machine */ u_char reqid; /* Next request id */ int restart; /* Restart counter value */ - int maxconfig; + int maxconfig; /* Max config REQ before a close() */ struct pppTimer FsmTimer; /* Restart Timer */ struct pppTimer OpenTimer; /* Delay before opening */ @@ -70,15 +105,14 @@ struct fsm { struct pppTimer StoppedTimer; int LogLevel; - void (*LayerUp) (struct fsm *); - void (*LayerDown) (struct fsm *); - void (*LayerStart) (struct fsm *); - void (*LayerFinish) (struct fsm *); - void (*InitRestartCounter) (struct fsm *); - void (*SendConfigReq) (struct fsm *); - void (*SendTerminateReq) (struct fsm *); - void (*SendTerminateAck) (struct fsm *); - void (*DecodeConfig) (u_char *, int, int); + /* The link layer active with this FSM (may be our bundle below) */ + struct link *link; + + /* Our high-level link */ + struct bundle *bundle; + + const struct fsm_parent *parent; + const struct fsm_callbacks *fn; }; struct fsmheader { @@ -103,30 +137,23 @@ struct fsmheader { #define CODE_RESETREQ 14 /* Used in CCP */ #define CODE_RESETACK 15 /* Used in CCP */ -struct fsmcodedesc { - void (*action) (struct fsm *, struct fsmheader *, struct mbuf *); - const char *name; -}; - +/* Minimum config req size. This struct is *only* used for it's size */ struct fsmconfig { u_char type; u_char length; }; -extern u_char AckBuff[200]; -extern u_char NakBuff[200]; -extern u_char RejBuff[100]; -extern u_char ReqBuff[200]; -extern u_char *ackp; -extern u_char *nakp; -extern u_char *rejp; - -extern char const *StateNames[]; - -extern void FsmInit(struct fsm *); -extern void FsmOutput(struct fsm *, u_int, u_int, u_char *, int); -extern void FsmOpen(struct fsm *); -extern void FsmUp(struct fsm *); -extern void FsmDown(struct fsm *); -extern void FsmInput(struct fsm *, struct mbuf *); -extern void FsmClose(struct fsm *); +extern void fsm_Init(struct fsm *, const char *, u_short, int, int, int, int, + struct bundle *, struct link *, const struct fsm_parent *, + struct fsm_callbacks *, const char *[3]); +extern void fsm_Output(struct fsm *, u_int, u_int, u_char *, int); +extern void fsm_Open(struct fsm *); +extern void fsm_Up(struct fsm *); +extern void fsm_Down(struct fsm *); +extern void fsm_Input(struct fsm *, struct mbuf *); +extern void fsm_Close(struct fsm *); +extern void fsm_NullRecvResetReq(struct fsm *); +extern void fsm_NullRecvResetAck(struct fsm *, u_char); +extern void fsm_Reopen(struct fsm *); +extern void fsm2initial(struct fsm *); +extern const char *State2Nam(u_int); diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/ppp/hdlc.c index df8d4e1debd..ae28e2259fb 100644 --- a/usr.sbin/ppp/hdlc.c +++ b/usr.sbin/ppp/ppp/hdlc.c @@ -17,69 +17,53 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: hdlc.c,v 1.9 1998/03/13 01:25:57 brian Exp $ + * $Id: hdlc.c,v 1.1 1998/08/31 00:22:20 brian Exp $ * * TODO: */ -#include <sys/param.h> +#include <sys/types.h> #include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> #include <stdio.h> #include <string.h> #include <termios.h> +#include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" -#include "defs.h" #include "timer.h" #include "fsm.h" +#include "lqr.h" #include "hdlc.h" #include "lcpproto.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" #include "ipcp.h" #include "ip.h" #include "vjcomp.h" +#include "auth.h" #include "pap.h" #include "chap.h" #include "lcp.h" #include "async.h" -#include "lqr.h" -#include "loadalias.h" -#include "vars.h" -#include "modem.h" #include "ccp.h" - -static struct hdlcstat { - int badfcs; - int badaddr; - int badcommand; - int unknownproto; -} HdlcStat; - -static u_int32_t ifOutPackets; -static u_int32_t ifOutOctets; -static u_int32_t ifOutLQRs; - -static struct protostat { - u_short number; - const char *name; - u_long in_count; - u_long out_count; -} ProtocolStat[] = { - { PROTO_IP, "IP" }, - { PROTO_VJUNCOMP, "VJ_UNCOMP" }, - { PROTO_VJCOMP, "VJ_COMP" }, - { PROTO_COMPD, "COMPD" }, - { PROTO_LCP, "LCP" }, - { PROTO_IPCP, "IPCP" }, - { PROTO_CCP, "CCP" }, - { PROTO_PAP, "PAP" }, - { PROTO_LQR, "LQR" }, - { PROTO_CHAP, "CHAP" }, - { 0, "Others" } -}; - -static u_short const fcstab[256] = { +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "prompt.h" +#include "chat.h" +#include "mp.h" +#include "cbcp.h" +#include "datalink.h" +#include "filter.h" +#include "bundle.h" + +static u_int16_t const fcstab[256] = { /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, @@ -114,14 +98,11 @@ static u_short const fcstab[256] = { /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -u_char EscMap[33]; - void -HdlcInit() +hdlc_Init(struct hdlc *hdlc, struct lcp *lcp) { - ifOutOctets = 0; - ifOutPackets = 0; - ifOutLQRs = 0; + memset(hdlc, '\0', sizeof(struct hdlc)); + hdlc->lqm.owner = lcp; } /* @@ -129,7 +110,7 @@ HdlcInit() * 2.27 for further details. */ inline u_short -HdlcFcs(u_short fcs, u_char * cp, int len) +hdlc_Fcs(u_short fcs, u_char * cp, int len) { while (len--) fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; @@ -142,7 +123,7 @@ HdlcFcsBuf(u_short fcs, struct mbuf *m) int len; u_char *pos, *end; - len = plength(m); + len = mbuf_Length(m); pos = MBUF_CTOP(m); end = pos + m->cnt; while (len--) { @@ -157,28 +138,22 @@ HdlcFcsBuf(u_short fcs, struct mbuf *m) } void -HdlcOutput(int pri, u_short proto, struct mbuf * bp) +hdlc_Output(struct link *l, int pri, u_short proto, struct mbuf *bp) { + struct physical *p = link2physical(l); struct mbuf *mhp, *mfcs; - struct protostat *statp; - struct lqrdata *lqr; u_char *cp; u_short fcs; - if ((proto & 0xfff1) == 0x21) /* Network Layer protocol */ - if (CcpFsm.state == ST_OPENED) - if (CcpOutput(pri, proto, bp)) - return; - - if (DEV_IS_SYNC) + if (!p || physical_IsSync(p)) mfcs = NULL; else - mfcs = mballoc(2, MB_HDLCOUT); + mfcs = mbuf_Alloc(2, MB_HDLCOUT); - mhp = mballoc(4, MB_HDLCOUT); + mhp = mbuf_Alloc(4, MB_HDLCOUT); mhp->cnt = 0; cp = MBUF_CTOP(mhp); - if (proto == PROTO_LCP || LcpInfo.his_acfcomp == 0) { + if (p && (proto == PROTO_LCP || l->lcp.his_acfcomp == 0)) { *cp++ = HDLC_ADDR; *cp++ = HDLC_UI; mhp->cnt += 2; @@ -187,7 +162,7 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) /* * If possible, compress protocol field. */ - if (LcpInfo.his_protocomp && (proto & 0xff00) == 0) { + if (l->lcp.his_protocomp && (proto & 0xff00) == 0) { *cp++ = proto; mhp->cnt++; } else { @@ -195,41 +170,60 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) *cp = proto & 0377; mhp->cnt += 2; } + mhp->next = bp; + + if (!p) { + /* + * This is where we multiplex the data over our available physical + * links. We don't frame our logical link data. Instead we wait + * for the logical link implementation to chop our data up and pile + * it into the physical links by re-calling this function with the + * encapsulated fragments. + */ + link_Output(l, pri, mhp); + return; + } + + /* Tack mfcs onto the end, then set bp back to the start of the data */ while (bp->next != NULL) bp = bp->next; bp->next = mfcs; bp = mhp->next; - lqr = &MyLqrData; - lqr->PeerOutPackets = ifOutPackets++; - ifOutOctets += plength(mhp) + 1; - lqr->PeerOutOctets = ifOutOctets; + p->hdlc.lqm.OutOctets += mbuf_Length(mhp) + 1; + p->hdlc.lqm.OutPackets++; if (proto == PROTO_LQR) { - lqr->MagicNumber = LcpInfo.want_magic; - lqr->LastOutLQRs = HisLqrData.PeerOutLQRs; - lqr->LastOutPackets = HisLqrData.PeerOutPackets; - lqr->LastOutOctets = HisLqrData.PeerOutOctets; - lqr->PeerInLQRs = HisLqrSave.SaveInLQRs; - lqr->PeerInPackets = HisLqrSave.SaveInPackets; - lqr->PeerInDiscards = HisLqrSave.SaveInDiscards; - lqr->PeerInErrors = HisLqrSave.SaveInErrors; - lqr->PeerInOctets = HisLqrSave.SaveInOctets; - if (HisLqrData.LastOutLQRs == ifOutLQRs) { + /* Overwrite the entire packet */ + struct lqrdata lqr; + + lqr.MagicNumber = p->link.lcp.want_magic; + lqr.LastOutLQRs = p->hdlc.lqm.lqr.peer.PeerOutLQRs; + lqr.LastOutPackets = p->hdlc.lqm.lqr.peer.PeerOutPackets; + lqr.LastOutOctets = p->hdlc.lqm.lqr.peer.PeerOutOctets; + lqr.PeerInLQRs = p->hdlc.lqm.lqr.SaveInLQRs; + lqr.PeerInPackets = p->hdlc.lqm.SaveInPackets; + lqr.PeerInDiscards = p->hdlc.lqm.SaveInDiscards; + lqr.PeerInErrors = p->hdlc.lqm.SaveInErrors; + lqr.PeerInOctets = p->hdlc.lqm.SaveInOctets; + lqr.PeerOutPackets = p->hdlc.lqm.OutPackets; + lqr.PeerOutOctets = p->hdlc.lqm.OutOctets; + if (p->hdlc.lqm.lqr.peer.LastOutLQRs == p->hdlc.lqm.lqr.OutLQRs) { /* * only increment if it's the first time or we've got a reply * from the last one */ - lqr->PeerOutLQRs = ++ifOutLQRs; - LqrDump("LqrOutput", lqr); + lqr.PeerOutLQRs = ++p->hdlc.lqm.lqr.OutLQRs; + lqr_Dump(l->name, "Output", &lqr); } else { - lqr->PeerOutLQRs = ifOutLQRs; - LqrDump("LqrOutput (again)", lqr); + lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs; + lqr_Dump(l->name, "Output (again)", &lqr); } - LqrChangeOrder(lqr, (struct lqrdata *) (MBUF_CTOP(bp))); + lqr_ChangeOrder(&lqr, (struct lqrdata *)MBUF_CTOP(bp)); } - if (!DEV_IS_SYNC) { + + if (mfcs) { mfcs->cnt = 0; fcs = HdlcFcsBuf(INITFCS, mhp); fcs = ~fcs; @@ -238,18 +232,16 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) *cp++ = fcs >> 8; mfcs->cnt = 2; } - LogDumpBp(LogHDLC, "HdlcOutput", mhp); - for (statp = ProtocolStat; statp->number; statp++) - if (statp->number == proto) - break; - statp->out_count++; - LogPrintf(LogDEBUG, "HdlcOutput: proto = 0x%04x\n", proto); + log_DumpBp(LogHDLC, "hdlc_Output", mhp); - if (DEV_IS_SYNC) - ModemOutput(pri, mhp); + link_ProtocolRecord(l, proto, PROTO_OUT); + log_Printf(LogDEBUG, "hdlc_Output: proto = 0x%04x\n", proto); + + if (physical_IsSync(p)) + link_Output(l, pri, mhp); /* Send it raw */ else - AsyncOutput(pri, mhp, proto); + async_Output(pri, mhp, proto, p); } /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ @@ -365,8 +357,8 @@ static struct { #define NPROTOCOLS (sizeof protocols/sizeof protocols[0]) -static const char * -Protocol2Nam(u_short proto) +const char * +hdlc_Protocol2Nam(u_short proto) { int f; @@ -378,209 +370,278 @@ Protocol2Nam(u_short proto) return "unrecognised protocol"; } -static void -DecodePacket(u_short proto, struct mbuf * bp) +void +hdlc_DecodePacket(struct bundle *bundle, u_short proto, struct mbuf * bp, + struct link *l) { + struct physical *p = link2physical(l); u_char *cp; + const char *type; - LogPrintf(LogDEBUG, "DecodePacket: proto = 0x%04x\n", proto); + log_Printf(LogDEBUG, "DecodePacket: proto = 0x%04x\n", proto); - /* - * If proto isn't PROTO_COMPD, we still want to pass it to the - * decompression routines so that the dictionary's updated - */ - if (CcpFsm.state == ST_OPENED) { - if (proto == PROTO_COMPD) { - if ((bp = CompdInput(&proto, bp)) == NULL) - return; - } else if ((proto & 0xfff1) == 0x21) /* Network Layer protocol */ - CcpDictSetup(proto, bp); - } + /* decompress everything. CCP needs uncompressed data too */ + if ((bp = ccp_Decompress(&l->ccp, &proto, bp)) == NULL) + return; switch (proto) { case PROTO_LCP: - LcpInput(bp); + lcp_Input(&l->lcp, bp); break; case PROTO_PAP: - PapInput(bp); + if (p) + pap_Input(bundle, bp, p); + else { + log_Printf(LogERROR, "DecodePacket: PAP: Not a physical link !\n"); + mbuf_Free(bp); + } + break; + case PROTO_CBCP: + if (p) + cbcp_Input(p, bp); + else { + log_Printf(LogERROR, "DecodePacket: CBCP: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_LQR: - HisLqrSave.SaveInLQRs++; - LqrInput(bp); + if (p) { + p->hdlc.lqm.lqr.SaveInLQRs++; + lqr_Input(p, bp); + } else { + log_Printf(LogERROR, "DecodePacket: LQR: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_CHAP: - ChapInput(bp); + if (p) + chap_Input(bundle, bp, p); + else { + log_Printf(LogERROR, "DecodePacket: CHAP: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_VJUNCOMP: case PROTO_VJCOMP: - bp = VjCompInput(bp, proto); - if (bp == NULL) { + bp = vj_Input(&bundle->ncp.ipcp, bp, proto); + if (bp == NULL) break; - } /* fall down */ case PROTO_IP: - IpInput(bp); + ip_Input(bundle, bp); break; case PROTO_IPCP: - IpcpInput(bp); + ipcp_Input(&bundle->ncp.ipcp, bundle, bp); break; case PROTO_CCP: - CcpInput(bp); + ccp_Input(&l->ccp, bundle, bp); break; + case PROTO_MP: + if (bundle->ncp.mp.active) { + if (p) + mp_Input(&bundle->ncp.mp, bp, p); + else { + log_Printf(LogWARN, "DecodePacket: Can't do MP inside MP !\n"); + mbuf_Free(bp); + } + break; + } + /* Fall through */ default: - LogPrintf(LogPHASE, "Unknown protocol 0x%04x (%s)\n", - proto, Protocol2Nam(proto)); + switch (proto) { + case PROTO_MP: + case PROTO_COMPD: + case PROTO_ICOMPD: + type = "Unexpected"; + break; + default: + type = "Unknown"; + break; + } + log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", type, proto, + hdlc_Protocol2Nam(proto)); bp->offset -= 2; bp->cnt += 2; cp = MBUF_CTOP(bp); - LcpSendProtoRej(cp, bp->cnt); - HisLqrSave.SaveInDiscards++; - HdlcStat.unknownproto++; - pfree(bp); - break; - } -} - -int -ReportProtStatus(struct cmdargs const *arg) -{ - struct protostat *statp; - int cnt; - - statp = ProtocolStat; - statp--; - cnt = 0; - fprintf(VarTerm, " Protocol in out Protocol in out\n"); - do { - statp++; - fprintf(VarTerm, " %-9s: %8lu, %8lu", - statp->name, statp->in_count, statp->out_count); - if (++cnt == 2) { - fprintf(VarTerm, "\n"); - cnt = 0; + lcp_SendProtoRej(&l->lcp, cp, bp->cnt); + if (p) { + p->hdlc.lqm.SaveInDiscards++; + p->hdlc.stats.unknownproto++; } - } while (statp->number); - if (cnt) - fprintf(VarTerm, "\n"); - return (0); -} - -int -ReportHdlcStatus(struct cmdargs const *arg) -{ - struct hdlcstat *hp = &HdlcStat; - - if (VarTerm) { - fprintf(VarTerm, "HDLC level errors\n\n"); - fprintf(VarTerm, "FCS: %u ADDR: %u COMMAND: %u PROTO: %u\n", - hp->badfcs, hp->badaddr, hp->badcommand, hp->unknownproto); + mbuf_Free(bp); + break; } - return 0; } -static struct hdlcstat laststat; - -void -HdlcErrorCheck() +static int +hdlc_GetProto(const u_char *cp, u_short *proto) { - struct hdlcstat *hp = &HdlcStat; - struct hdlcstat *op = &laststat; - - if (memcmp(hp, op, sizeof laststat)) { - LogPrintf(LogPHASE, "HDLC errors -> FCS: %u ADDR: %u COMD: %u PROTO: %u\n", - hp->badfcs - op->badfcs, hp->badaddr - op->badaddr, - hp->badcommand - op->badcommand, hp->unknownproto - op->unknownproto); + *proto = *cp; + if (!(*proto & 1)) { + *proto = (*proto << 8) | cp[1]; + return 2; } - laststat = HdlcStat; + return 1; } void -HdlcInput(struct mbuf * bp) +hdlc_Input(struct bundle *bundle, struct mbuf * bp, struct physical *physical) { u_short fcs, proto; u_char *cp, addr, ctrl; - struct protostat *statp; + int n; - LogDumpBp(LogHDLC, "HdlcInput:", bp); - if (DEV_IS_SYNC) + log_DumpBp(LogHDLC, "hdlc_Input:", bp); + if (physical_IsSync(physical)) fcs = GOODFCS; else - fcs = HdlcFcs(INITFCS, MBUF_CTOP(bp), bp->cnt); - HisLqrSave.SaveInOctets += bp->cnt + 1; + fcs = hdlc_Fcs(INITFCS, MBUF_CTOP(bp), bp->cnt); + physical->hdlc.lqm.SaveInOctets += bp->cnt + 1; - LogPrintf(LogDEBUG, "HdlcInput: fcs = %04x (%s)\n", - fcs, (fcs == GOODFCS) ? "good" : "bad"); + log_Printf(LogDEBUG, "%s: hdlc_Input: fcs = %04x (%s)\n", + physical->link.name, fcs, (fcs == GOODFCS) ? "good" : "BAD!"); if (fcs != GOODFCS) { - HisLqrSave.SaveInErrors++; - LogPrintf(LogDEBUG, "HdlcInput: Bad FCS\n"); - HdlcStat.badfcs++; - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badfcs++; + mbuf_Free(bp); return; } - if (!DEV_IS_SYNC) + if (!physical_IsSync(physical)) bp->cnt -= 2; /* discard FCS part */ if (bp->cnt < 2) { /* XXX: raise this bar ? */ - pfree(bp); + mbuf_Free(bp); return; } cp = MBUF_CTOP(bp); - if (!LcpInfo.want_acfcomp) { - - /* - * We expect that packet is not compressed. - */ + if (!physical->link.lcp.want_acfcomp) { + /* We expect the packet not to be compressed */ addr = *cp++; if (addr != HDLC_ADDR) { - HisLqrSave.SaveInErrors++; - HdlcStat.badaddr++; - LogPrintf(LogDEBUG, "HdlcInput: addr %02x\n", *cp); - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badaddr++; + log_Printf(LogDEBUG, "hdlc_Input: addr %02x\n", *cp); + mbuf_Free(bp); return; } ctrl = *cp++; if (ctrl != HDLC_UI) { - HisLqrSave.SaveInErrors++; - HdlcStat.badcommand++; - LogPrintf(LogDEBUG, "HdlcInput: %02x\n", *cp); - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badcommand++; + log_Printf(LogDEBUG, "hdlc_Input: %02x\n", *cp); + mbuf_Free(bp); return; } bp->offset += 2; bp->cnt -= 2; } else if (cp[0] == HDLC_ADDR && cp[1] == HDLC_UI) { - /* - * We can receive compressed packet, but peer still send uncompressed - * packet to me. + * We can receive compressed packets, but the peer still sends + * uncompressed packets ! */ cp += 2; bp->offset += 2; bp->cnt -= 2; } - if (LcpInfo.want_protocomp) { - proto = 0; - cp--; - do { - cp++; - bp->offset++; - bp->cnt--; - proto = proto << 8; - proto += *cp; - } while (!(proto & 1)); - } else { - proto = *cp++ << 8; - proto |= *cp++; - bp->offset += 2; - bp->cnt -= 2; - } - for (statp = ProtocolStat; statp->number; statp++) - if (statp->number == proto) + n = hdlc_GetProto(cp, &proto); + bp->offset += n; + bp->cnt -= n; + if (!physical->link.lcp.want_protocomp && n == 1) + log_Printf(LogHDLC, "%s: Warning: received a proto-compressed packet !\n", + physical->link.name); + + link_ProtocolRecord(&physical->link, proto, PROTO_IN); + physical->hdlc.lqm.SaveInPackets++; + + hdlc_DecodePacket(bundle, proto, bp, &physical->link); +} + +/* + * Detect a HDLC frame + */ + +static const char *FrameHeaders[] = { + "\176\377\003\300\041", + "\176\377\175\043\300\041", + "\176\177\175\043\100\041", + "\176\175\337\175\043\300\041", + "\176\175\137\175\043\100\041", + NULL, +}; + +u_char * +hdlc_Detect(struct physical *physical, u_char *cp, int n) +{ + const char *fp, **hp; + char *ptr; + + cp[n] = '\0'; /* be sure to null terminate */ + ptr = NULL; + for (hp = FrameHeaders; *hp; hp++) { + fp = *hp; + if (physical_IsSync(physical)) + fp++; + ptr = strstr((char *)cp, fp); /* XXX: cp may have embedded NULs */ + if (ptr) break; - statp->in_count++; - HisLqrSave.SaveInPackets++; + } + return (u_char *)ptr; +} + +int +hdlc_ReportStatus(struct cmdargs const *arg) +{ + struct hdlc *hdlc = &arg->cx->physical->hdlc; + + prompt_Printf(arg->prompt, "%s HDLC level errors:\n", arg->cx->name); + prompt_Printf(arg->prompt, " Bad Frame Check Sequence fields: %u\n", + hdlc->stats.badfcs); + prompt_Printf(arg->prompt, " Bad address (!= 0x%02x) fields: %u\n", + HDLC_ADDR, hdlc->stats.badaddr); + prompt_Printf(arg->prompt, " Bad command (!= 0x%02x) fields: %u\n", + HDLC_UI, hdlc->stats.badcommand); + prompt_Printf(arg->prompt, " Unrecognised protocol fields: %u\n", + hdlc->stats.unknownproto); + return 0; +} + +static void +hdlc_ReportTime(void *v) +{ + /* Moan about HDLC errors */ + struct hdlc *hdlc = (struct hdlc *)v; + + timer_Stop(&hdlc->ReportTimer); + + if (memcmp(&hdlc->laststats, &hdlc->stats, sizeof hdlc->stats)) { + log_Printf(LogPHASE, + "%s: HDLC errors -> FCS: %u, ADDR: %u, COMD: %u, PROTO: %u\n", + hdlc->lqm.owner->fsm.link->name, + hdlc->stats.badfcs - hdlc->laststats.badfcs, + hdlc->stats.badaddr - hdlc->laststats.badaddr, + hdlc->stats.badcommand - hdlc->laststats.badcommand, + hdlc->stats.unknownproto - hdlc->laststats.unknownproto); + hdlc->laststats = hdlc->stats; + } - DecodePacket(proto, bp); + timer_Start(&hdlc->ReportTimer); +} + +void +hdlc_StartTimer(struct hdlc *hdlc) +{ + timer_Stop(&hdlc->ReportTimer); + hdlc->ReportTimer.load = 60 * SECTICKS; + hdlc->ReportTimer.arg = hdlc; + hdlc->ReportTimer.func = hdlc_ReportTime; + hdlc->ReportTimer.name = "hdlc"; + timer_Start(&hdlc->ReportTimer); +} + +void +hdlc_StopTimer(struct hdlc *hdlc) +{ + timer_Stop(&hdlc->ReportTimer); } diff --git a/usr.sbin/ppp/ppp/hdlc.h b/usr.sbin/ppp/ppp/hdlc.h new file mode 100644 index 00000000000..c6c5c02b324 --- /dev/null +++ b/usr.sbin/ppp/ppp/hdlc.h @@ -0,0 +1,115 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: hdlc.h,v 1.1 1998/08/31 00:22:21 brian Exp $ + * + * TODO: + */ + +/* + * Definition for Async HDLC + */ +#define HDLC_SYN 0x7e /* SYNC character */ +#define HDLC_ESC 0x7d /* Escape character */ +#define HDLC_XOR 0x20 /* Modifier value */ + +#define HDLC_ADDR 0xff +#define HDLC_UI 0x03 +/* + * Definition for HDLC Frame Check Sequence + */ +#define INITFCS 0xffff /* Initial value for FCS computation */ +#define GOODFCS 0xf0b8 /* Good FCS value */ + +#define DEF_MRU 1500 +#define MAX_MRU 2048 +#define MIN_MRU 296 + +#define DEF_MTU 0 /* whatever peer says */ +#define MAX_MTU 2048 +#define MIN_MTU 296 + +/* + * Output priority + */ +/* PRI_NORMAL and PRI_FAST have meaning only on the IP queue. + * All IP frames have the same priority once they are compressed. + * IP frames stay on the IP queue till they can be sent on the + * link. They are compressed at that time. +*/ +#define PRI_NORMAL 0 /* Normal priority */ +#define PRI_FAST 1 /* Fast (interractive) */ +#define PRI_LINK 1 /* Urgent (LQR packets) */ +#define PRI_MAX 1 + +struct physical; +struct link; +struct lcp; +struct bundle; +struct mbuf; +struct cmdargs; + +struct hdlc { + struct pppTimer ReportTimer; + + struct { + int badfcs; + int badaddr; + int badcommand; + int unknownproto; + } laststats, stats; + + struct { + struct lcp *owner; /* parent LCP */ + struct pppTimer timer; /* When to send */ + int method; /* bit-mask for LQM_* from lqr.h */ + + u_int32_t OutPackets; /* Packets sent by me */ + u_int32_t OutOctets; /* Octets sent by me */ + u_int32_t SaveInPackets; /* Packets received from peer */ + u_int32_t SaveInDiscards; /* Discards */ + u_int32_t SaveInErrors; /* Errors */ + u_int32_t SaveInOctets; /* Octets received from peer */ + + struct { + u_int32_t OutLQRs; /* LQRs sent by me */ + u_int32_t SaveInLQRs; /* LQRs received from peer */ + struct lqrdata peer; /* Last LQR from peer */ + int peer_timeout; /* peers max lqr timeout */ + int resent; /* Resent last packet `resent' times */ + } lqr; + + struct { + u_int32_t seq_sent; /* last echo sent */ + u_int32_t seq_recv; /* last echo received */ + } echo; + } lqm; +}; + + +extern void hdlc_Init(struct hdlc *, struct lcp *); +extern void hdlc_StartTimer(struct hdlc *); +extern void hdlc_StopTimer(struct hdlc *); +extern int hdlc_ReportStatus(struct cmdargs const *); +extern const char *hdlc_Protocol2Nam(u_short); +extern void hdlc_DecodePacket(struct bundle *, u_short, struct mbuf *, + struct link *); + +extern void hdlc_Input(struct bundle *, struct mbuf *, struct physical *); +extern void hdlc_Output(struct link *, int, u_short, struct mbuf *bp); +extern u_short hdlc_Fcs(u_short, u_char *, int); +extern u_char *hdlc_Detect(struct physical *, u_char *, int); diff --git a/usr.sbin/ppp/id.c b/usr.sbin/ppp/ppp/id.c index d455ea966f5..070bb8466f1 100644 --- a/usr.sbin/ppp/id.c +++ b/usr.sbin/ppp/ppp/id.c @@ -23,14 +23,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: id.c,v 1.5 1998/02/19 02:02:46 brian Exp $ + * $Id: id.c,v 1.1 1998/08/31 00:22:21 brian Exp $ */ #include <sys/types.h> #include <sys/socket.h> +#include <sys/un.h> #include <sys/ioctl.h> #include <fcntl.h> +#include <signal.h> +#include <stdarg.h> #include <stdio.h> #include <string.h> #include <sysexits.h> @@ -42,8 +45,6 @@ #endif #include <utmp.h> -#include "command.h" -#include "mbuf.h" #include "log.h" #include "main.h" #include "id.h" @@ -62,8 +63,8 @@ static void ID0setuser(void) { if (seteuid(uid) == -1) { - LogPrintf(LogERROR, "ID0setuser: Unable to seteuid!\n"); - Cleanup(EX_NOPERM); + log_Printf(LogERROR, "ID0setuser: Unable to seteuid!\n"); + AbortProgram(EX_NOPERM); } } @@ -77,8 +78,8 @@ static void ID0set0(void) { if (seteuid(euid) == -1) { - LogPrintf(LogERROR, "ID0set0: Unable to seteuid!\n"); - Cleanup(EX_NOPERM); + log_Printf(LogERROR, "ID0set0: Unable to seteuid!\n"); + AbortProgram(EX_NOPERM); } } @@ -89,7 +90,7 @@ ID0ioctl(int fd, unsigned long req, void *arg) ID0set0(); ret = ioctl(fd, req, arg); - LogPrintf(LogID0, "%d = ioctl(%d, %d, %p)\n", ret, fd, req, arg); + log_Printf(LogID0, "%d = ioctl(%d, %lu, %p)\n", ret, fd, req, arg); ID0setuser(); return ret; } @@ -101,7 +102,7 @@ ID0unlink(const char *name) ID0set0(); ret = unlink(name); - LogPrintf(LogID0, "%d = unlink(\"%s\")\n", ret, name); + log_Printf(LogID0, "%d = unlink(\"%s\")\n", ret, name); ID0setuser(); return ret; } @@ -113,7 +114,7 @@ ID0socket(int domain, int type, int protocol) ID0set0(); ret = socket(domain, type, protocol); - LogPrintf(LogID0, "%d = socket(%d, %d, %d)\n", ret, domain, type, protocol); + log_Printf(LogID0, "%d = socket(%d, %d, %d)\n", ret, domain, type, protocol); ID0setuser(); return ret; } @@ -125,20 +126,23 @@ ID0fopen(const char *path, const char *mode) ID0set0(); ret = fopen(path, mode); - LogPrintf(LogID0, "%p = fopen(\"%s\", \"%s\")\n", ret, path, mode); + log_Printf(LogID0, "%p = fopen(\"%s\", \"%s\")\n", ret, path, mode); ID0setuser(); return ret; } int -ID0open(const char *path, int flags) +ID0open(const char *path, int flags, ...) { int ret; + va_list ap; + va_start(ap, flags); ID0set0(); - ret = open(path, flags); - LogPrintf(LogID0, "%d = open(\"%s\", %d)\n", ret, path, flags); + ret = open(path, flags, va_arg(ap, int)); + log_Printf(LogID0, "%d = open(\"%s\", %d)\n", ret, path, flags); ID0setuser(); + va_end(ap); return ret; } @@ -149,7 +153,7 @@ ID0write(int fd, const void *data, size_t len) ID0set0(); ret = write(fd, data, len); - LogPrintf(LogID0, "%d = write(%d, data, %d)\n", ret, fd, len); + log_Printf(LogID0, "%d = write(%d, data, %ld)\n", ret, fd, (long)len); ID0setuser(); return ret; } @@ -161,7 +165,20 @@ ID0uu_lock(const char *basettyname) ID0set0(); ret = uu_lock(basettyname); - LogPrintf(LogID0, "%d = uu_lock(\"%s\")\n", ret, basettyname); + log_Printf(LogID0, "%d = uu_lock(\"%s\")\n", ret, basettyname); + ID0setuser(); + return ret; +} + +int +ID0uu_lock_txfr(const char *basettyname, pid_t newpid) +{ + int ret; + + ID0set0(); + ret = uu_lock_txfr(basettyname, newpid); + log_Printf(LogID0, "%d = uu_lock_txfr(\"%s\", %d)\n", ret, basettyname, + (int)newpid); ID0setuser(); return ret; } @@ -173,7 +190,7 @@ ID0uu_unlock(const char *basettyname) ID0set0(); ret = uu_unlock(basettyname); - LogPrintf(LogID0, "%d = uu_unlock(\"%s\")\n", ret, basettyname); + log_Printf(LogID0, "%d = uu_unlock(\"%s\")\n", ret, basettyname); ID0setuser(); return ret; } @@ -183,13 +200,13 @@ ID0login(struct utmp *ut) { ID0set0(); if (logout(ut->ut_line)) { - LogPrintf(LogID0, "logout(\"%s\")\n", ut->ut_line); + log_Printf(LogID0, "logout(\"%s\")\n", ut->ut_line); logwtmp(ut->ut_line, "", ""); - LogPrintf(LogID0, "logwtmp(\"%s\", \"\", \"\")\n", ut->ut_line); + log_Printf(LogID0, "logwtmp(\"%s\", \"\", \"\")\n", ut->ut_line); } login(ut); - LogPrintf(LogID0, "login(\"%s\", \"%.*s\")\n", - ut->ut_line, sizeof ut->ut_name, ut->ut_name); + log_Printf(LogID0, "login(\"%s\", \"%.*s\")\n", + ut->ut_line, (int)(sizeof ut->ut_name), ut->ut_name); ID0setuser(); } @@ -203,10 +220,48 @@ ID0logout(const char *device) ID0set0(); if (logout(ut.ut_line)) { - LogPrintf(LogID0, "logout(\"%s\")\n", ut.ut_line); + log_Printf(LogID0, "logout(\"%s\")\n", ut.ut_line); logwtmp(ut.ut_line, "", ""); - LogPrintf(LogID0, "logwtmp(\"%s\", \"\", \"\")\n", ut.ut_line); + log_Printf(LogID0, "logwtmp(\"%s\", \"\", \"\")\n", ut.ut_line); } else - LogPrintf(LogERROR, "ID0logout: No longer logged in on %s\n", ut.ut_line); + log_Printf(LogERROR, "ID0logout: No longer logged in on %s\n", ut.ut_line); + ID0setuser(); +} + +int +ID0bind_un(int s, const struct sockaddr_un *name) +{ + int result; + + ID0set0(); + result = bind(s, (const struct sockaddr *)name, sizeof *name); + log_Printf(LogID0, "%d = bind(%d, \"%s\", %d)\n", + result, s, name->sun_path, (int)sizeof(*name)); + ID0setuser(); + return result; +} + +int +ID0connect_un(int s, const struct sockaddr_un *name) +{ + int result; + + ID0set0(); + result = connect(s, (const struct sockaddr *)name, sizeof *name); + log_Printf(LogID0, "%d = connect(%d, \"%s\", %d)\n", + result, s, name->sun_path, (int)sizeof(*name)); + ID0setuser(); + return result; +} + +int +ID0kill(pid_t pid, int sig) +{ + int result; + + ID0set0(); + result = kill(pid, sig); + log_Printf(LogID0, "%d = kill(%d, %d)\n", result, (int)pid, sig); ID0setuser(); + return result; } diff --git a/usr.sbin/ppp/id.h b/usr.sbin/ppp/ppp/id.h index f51893e1b5e..0c213ec391a 100644 --- a/usr.sbin/ppp/id.h +++ b/usr.sbin/ppp/ppp/id.h @@ -23,10 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: id.h,v 1.4 1998/02/19 02:02:47 brian Exp $ + * $Id: id.h,v 1.1 1998/08/31 00:22:21 brian Exp $ */ struct utmp; +struct sockaddr_un; extern void ID0init(void); extern uid_t ID0realuid(void); @@ -34,9 +35,13 @@ extern int ID0ioctl(int, unsigned long, void *); extern int ID0unlink(const char *); extern int ID0socket(int, int, int); extern FILE *ID0fopen(const char *, const char *); -extern int ID0open(const char *, int); +extern int ID0open(const char *, int, ...); extern int ID0write(int, const void *, size_t); extern int ID0uu_lock(const char *); +extern int ID0uu_lock_txfr(const char *, pid_t); extern int ID0uu_unlock(const char *); extern void ID0login(struct utmp *); extern void ID0logout(const char *); +extern int ID0bind_un(int, const struct sockaddr_un *); +extern int ID0connect_un(int, const struct sockaddr_un *); +extern int ID0kill(pid_t, int); diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ppp/ip.c index 4540d713914..3ad9ffa35b3 100644 --- a/usr.sbin/ppp/ip.c +++ b/usr.sbin/ppp/ppp/ip.c @@ -17,16 +17,16 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ip.c,v 1.10 1998/06/27 12:06:42 brian Exp $ + * $Id: ip.c,v 1.1 1998/08/31 00:22:21 brian Exp $ * * TODO: * o Return ICMP message for filterd packet * and optionaly record it into log. */ -#include <sys/param.h> -#include <sys/time.h> +#include <sys/types.h> +#ifdef __OpenBSD__ #include <sys/socket.h> -#include <net/if.h> +#endif #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> @@ -34,6 +34,7 @@ #include <netinet/udp.h> #include <netinet/tcp.h> #include <arpa/inet.h> +#include <sys/un.h> #ifndef NOALIAS #include <alias.h> @@ -42,91 +43,30 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <termios.h> #include <unistd.h> -#include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" +#include "lqr.h" #include "hdlc.h" -#include "loadalias.h" -#include "vars.h" -#include "filter.h" -#include "os.h" +#include "throughput.h" +#include "iplist.h" +#include "slcompress.h" #include "ipcp.h" -#include "vjcomp.h" +#include "filter.h" +#include "descriptor.h" #include "lcp.h" -#include "modem.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" +#include "vjcomp.h" #include "tun.h" #include "ip.h" -static struct pppTimer IdleTimer; - -static void -IdleTimeout(void *v) -{ - LogPrintf(LogPHASE, "Idle timer expired.\n"); - reconnect(RECON_FALSE); - LcpClose(); -} - -/* - * Start Idle timer. If timeout is reached, we call LcpClose() to - * close LCP and link. - */ -void -StartIdleTimer() -{ - static time_t IdleStarted; - - if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { - StopTimer(&IdleTimer); - IdleTimer.func = IdleTimeout; - IdleTimer.load = VarIdleTimeout * SECTICKS; - IdleTimer.state = TIMER_STOPPED; - time(&IdleStarted); - IdleTimer.arg = (void *)&IdleStarted; - StartTimer(&IdleTimer); - } -} - -void -UpdateIdleTimer() -{ - if (OsLinkIsUp()) - StartIdleTimer(); -} - -void -StopIdleTimer() -{ - StopTimer(&IdleTimer); -} - -int -RemainingIdleTime() -{ - if (VarIdleTimeout == 0 || IdleTimer.state != TIMER_RUNNING || - IdleTimer.arg == NULL) - return -1; - return VarIdleTimeout - (time(NULL) - *(time_t *)IdleTimer.arg); -} - -/* - * If any IP layer traffic is detected, refresh IdleTimer. - */ -static void -RestartIdleTimer(void) -{ - if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { - time((time_t *)IdleTimer.arg); - StartTimer(&IdleTimer); - } -} - static const u_short interactive_ports[32] = { 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, @@ -136,9 +76,6 @@ static const u_short interactive_ports[32] = { static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; -static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; -static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; - static int PortMatch(int op, u_short pport, u_short rport) { @@ -158,27 +95,30 @@ PortMatch(int op, u_short pport, u_short rport) * Check a packet against with defined filters */ static int -FilterCheck(struct ip * pip, int direction) +FilterCheck(struct ip *pip, struct filter *filter) { - struct filterent *fp = Filters[direction]; - int gotinfo, cproto, estab, n; + int gotinfo, cproto, estab, syn, finrst, n, len, didname; struct tcphdr *th; struct udphdr *uh; struct icmp *ih; char *ptop; u_short sport, dport; + struct filterent *fp = filter->rule; + char dbuff[100]; if (fp->action) { - cproto = gotinfo = estab = 0; + cproto = gotinfo = estab = syn = finrst = didname = 0; sport = dport = 0; for (n = 0; n < MAXFILTERS; n++) { if (fp->action) { /* permit fragments on in and out filter */ - if ((direction == FL_IN || direction == FL_OUT) && - (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { + if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0) return (A_PERMIT); - } - LogPrintf(LogDEBUG, "rule = %d\n", n); + + if (!didname) + log_Printf(LogDEBUG, "%s filter:\n", filter->name); + didname = 1; + if ((pip->ip_src.s_addr & fp->smask.s_addr) == (fp->saddr.s_addr & fp->smask.s_addr) && (pip->ip_dst.s_addr & fp->dmask.s_addr) == @@ -192,14 +132,21 @@ FilterCheck(struct ip * pip, int direction) cproto = P_ICMP; ih = (struct icmp *) ptop; sport = ih->icmp_type; - estab = 1; + estab = syn = finrst = -1; + if (log_IsKept(LogDEBUG)) + snprintf(dbuff, sizeof dbuff, "sport = %d", sport); break; case IPPROTO_UDP: + case IPPROTO_IGMP: + case IPPROTO_IPIP: cproto = P_UDP; uh = (struct udphdr *) ptop; sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport); - estab = 1; + estab = syn = finrst = -1; + if (log_IsKept(LogDEBUG)) + snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", + sport, dport); break; case IPPROTO_TCP: cproto = P_TCP; @@ -207,39 +154,67 @@ FilterCheck(struct ip * pip, int direction) sport = ntohs(th->th_sport); dport = ntohs(th->th_dport); estab = (th->th_flags & TH_ACK); - if (estab == 0) - LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", - th->th_flags, sport, dport); + syn = (th->th_flags & TH_SYN); + finrst = (th->th_flags & (TH_FIN|TH_RST)); + if (log_IsKept(LogDEBUG) && !estab) + snprintf(dbuff, sizeof dbuff, + "flags = %02x, sport = %d, dport = %d", + th->th_flags, sport, dport); break; default: - return (A_DENY);/* We'll block unknown type of packet */ + return (A_DENY); /* We'll block unknown type of packet */ } + if (log_IsKept(LogDEBUG)) { + if (estab != -1) { + len = strlen(dbuff); + snprintf(dbuff + len, sizeof dbuff - len, + ", estab = %d, syn = %d, finrst = %d", + estab, syn, finrst); + } + log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", + filter_Proto2Nam(cproto), dbuff); + } gotinfo = 1; - LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," - " dstop = %d, estab = %d\n", direction, cproto, - fp->opt.srcop, fp->opt.dstop, estab); } - LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," - " dport = %d\n", n, cproto, sport, dport); - LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); + if (log_IsKept(LogDEBUG)) { + if (fp->opt.srcop != OP_NONE) { + snprintf(dbuff, sizeof dbuff, ", src %s %d", + filter_Op2Nam(fp->opt.srcop), fp->opt.srcport); + len = strlen(dbuff); + } else + len = 0; + if (fp->opt.dstop != OP_NONE) { + snprintf(dbuff + len, sizeof dbuff - len, + ", dst %s %d", filter_Op2Nam(fp->opt.dstop), + fp->opt.dstport); + } else if (!len) + *dbuff = '\0'; + + log_Printf(LogDEBUG, " rule = %d: Address match, " + "check against proto %s%s, action = %s\n", + n, filter_Proto2Nam(fp->proto), + dbuff, filter_Action2Nam(fp->action)); + } if (cproto == fp->proto) { if ((fp->opt.srcop == OP_NONE || - PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) - && + PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) && (fp->opt.dstop == OP_NONE || - PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) - && - (fp->opt.estab == 0 || estab)) { + PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) && + (fp->opt.estab == 0 || estab) && + (fp->opt.syn == 0 || syn) && + (fp->opt.finrst == 0 || finrst)) { return (fp->action); } } } else { /* Address is mached. Make a decision. */ - LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); + log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, + filter_Action2Nam(fp->action)); return (fp->action); } - } + } else + log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); } fp++; } @@ -248,27 +223,26 @@ FilterCheck(struct ip * pip, int direction) return (A_PERMIT); /* No rule is given. Permit this packet */ } +#ifdef notdef static void IcmpError(struct ip * pip, int code) { -#ifdef notdef struct mbuf *bp; if (pip->ip_p != IPPROTO_ICMP) { - bp = mballoc(cnt, MB_IPIN); + bp = mbuf_Alloc(cnt, MB_IPIN); memcpy(MBUF_CTOP(bp), ptr, cnt); - SendPppFrame(bp); - RestartIdleTimer(); - IpcpAddOutOctets(cnt); + vj_SendFrame(bp); + ipcp_AddOutOctets(cnt); } -#endif } +#endif /* * For debugging aid. */ int -PacketCheck(char *cp, int nb, int direction) +PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) { struct ip *pip; struct tcphdr *th; @@ -278,16 +252,15 @@ PacketCheck(char *cp, int nb, int direction) int mask, len, n; int pri = PRI_NORMAL; int logit, loglen; - static char logbuf[200]; + char logbuf[200]; - logit = LogIsKept(LogTCPIP) && direction != FL_DIAL; + logit = log_IsKept(LogTCPIP) && filter->logok; loglen = 0; pip = (struct ip *) cp; if (logit && loglen < sizeof logbuf) { - snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", - Direction[direction]); + snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); loglen += strlen(logbuf + loglen); } ptop = (cp + (pip->ip_hl << 2)); @@ -315,6 +288,28 @@ PacketCheck(char *cp, int nb, int direction) loglen += strlen(logbuf + loglen); } break; + case IPPROTO_IPIP: + if (logit && loglen < sizeof logbuf) { + uh = (struct udphdr *) ptop; + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); + loglen += strlen(logbuf + loglen); + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); + loglen += strlen(logbuf + loglen); + } + break; + case IPPROTO_IGMP: + if (logit && loglen < sizeof logbuf) { + uh = (struct udphdr *) ptop; + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); + loglen += strlen(logbuf + loglen); + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); + loglen += strlen(logbuf + loglen); + } + break; case IPPROTO_TCP: th = (struct tcphdr *) ptop; if (pip->ip_tos == IPTOS_LOWDELAY) @@ -340,8 +335,8 @@ PacketCheck(char *cp, int nb, int direction) n++; } snprintf(logbuf + loglen, sizeof logbuf - loglen, - " seq:%x ack:%x (%d/%d)", - ntohl(th->th_seq), ntohl(th->th_ack), len, nb); + " seq:%lx ack:%lx (%d/%d)", + (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); loglen += strlen(logbuf + loglen); if ((th->th_flags & TH_SYN) && nb > 40) { u_short *sp; @@ -358,42 +353,46 @@ PacketCheck(char *cp, int nb, int direction) break; } - if ((FilterCheck(pip, direction) & A_DENY)) { + if ((FilterCheck(pip, filter) & A_DENY)) { if (logit) - LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); + log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); +#ifdef notdef if (direction == 0) IcmpError(pip, pri); +#endif return (-1); } else { - if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ - if (logit) - LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); - ipKeepAlive = 0; - } else { - if (logit) - LogPrintf(LogTCPIP, "%s\n", logbuf); - ipKeepAlive = 1; + /* Check Keep Alive filter */ + if (logit) { + if (FilterCheck(pip, &bundle->filter.alive) & A_DENY) + log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); + else + log_Printf(LogTCPIP, "%s\n", logbuf); } return (pri); } } void -IpInput(struct mbuf * bp) -{ /* IN: Pointer to IP pakcet */ +ip_Input(struct bundle *bundle, struct mbuf * bp) +{ u_char *cp; struct mbuf *wp; int nb, nw; struct tun_data tun; + struct ip *pip = (struct ip *)tun.data; +#ifndef NOALIAS + struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); +#endif tun_fill_header(tun, AF_INET); cp = tun.data; nb = 0; for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ if (sizeof tun.data - (cp - tun.data) < wp->cnt) { - LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n", - plength(bp)); - pfree(bp); + log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n", + mbuf_Length(bp)); + mbuf_Free(bp); return; } memcpy(cp, MBUF_CTOP(wp), wp->cnt); @@ -402,52 +401,57 @@ IpInput(struct mbuf * bp) } #ifndef NOALIAS - if (mode & MODE_ALIAS) { + if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP && + (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) { struct tun_data *frag; int iresult; char *fptr; - iresult = VarPacketAliasIn(tun.data, sizeof tun.data); + iresult = PacketAliasIn(tun.data, sizeof tun.data); nb = ntohs(((struct ip *) tun.data)->ip_len); if (nb > MAX_MRU) { - LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); - pfree(bp); + log_Printf(LogWARN, "ip_Input: Problem with IP header length\n"); + mbuf_Free(bp); return; } if (iresult == PKT_ALIAS_OK || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { - if (PacketCheck(tun.data, nb, FL_IN) < 0) { - pfree(bp); + if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { + mbuf_Free(bp); return; } - IpcpAddInOctets(nb); + + if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) + bundle_StartIdleTimer(bundle); + + ipcp_AddInOctets(&bundle->ncp.ipcp, nb); nb = ntohs(((struct ip *) tun.data)->ip_len); nb += sizeof tun - sizeof tun.data; - nw = write(tun_out, &tun, nb); + nw = write(bundle->dev.fd, &tun, nb); if (nw != nb) { if (nw == -1) - LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, + log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); else - LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); } if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { - while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { - VarPacketAliasFragmentIn(tun.data, fptr); + while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) { + PacketAliasFragmentIn(tun.data, fptr); nb = ntohs(((struct ip *) fptr)->ip_len); frag = (struct tun_data *) ((char *)fptr - sizeof tun + sizeof tun.data); nb += sizeof tun - sizeof tun.data; - nw = write(tun_out, frag, nb); + nw = write(bundle->dev.fd, frag, nb); if (nw != nb) { if (nw == -1) - LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, + log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); else - LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); } free(frag); } @@ -457,83 +461,99 @@ IpInput(struct mbuf * bp) nb += sizeof tun - sizeof tun.data; frag = (struct tun_data *)malloc(nb); if (frag == NULL) - LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); + log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n"); else { tun_fill_header(*frag, AF_INET); memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); - VarPacketAliasSaveFragment(frag->data); + PacketAliasSaveFragment(frag->data); } } } else #endif /* #ifndef NOALIAS */ { /* no aliasing */ - if (PacketCheck(tun.data, nb, FL_IN) < 0) { - pfree(bp); + if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { + mbuf_Free(bp); return; } - IpcpAddInOctets(nb); + + if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) + bundle_StartIdleTimer(bundle); + + ipcp_AddInOctets(&bundle->ncp.ipcp, nb); + nb += sizeof tun - sizeof tun.data; - nw = write(tun_out, &tun, nb); + nw = write(bundle->dev.fd, &tun, nb); if (nw != nb) { if (nw == -1) - LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); + log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); else - LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); } } - pfree(bp); - - RestartIdleTimer(); + mbuf_Free(bp); } -static struct mqueue IpOutputQueues[PRI_FAST + 1]; - void -IpEnqueue(int pri, char *ptr, int count) +ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) { struct mbuf *bp; - bp = mballoc(count, MB_IPQ); - memcpy(MBUF_CTOP(bp), ptr, count); - Enqueue(&IpOutputQueues[pri], bp); + if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0]) + log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); + else { + bp = mbuf_Alloc(count, MB_IPQ); + memcpy(MBUF_CTOP(bp), ptr, count); + mbuf_Enqueue(&ipcp->Queue[pri], bp); + } +} + +void +ip_DeleteQueue(struct ipcp *ipcp) +{ + struct mqueue *queue; + + for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) + while (queue->top) + mbuf_Free(mbuf_Dequeue(queue)); } -#if 0 int -IsIpEnqueued() +ip_QueueLen(struct ipcp *ipcp) { struct mqueue *queue; - int exist = 0; + int result = 0; - for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { - if (queue->qlen > 0) { - exist = 1; - break; - } - } - return (exist); + for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) + result += queue->qlen; + + return result; } -#endif -void -IpStartOutput() +int +ip_FlushPacket(struct link *l, struct bundle *bundle) { + struct ipcp *ipcp = &bundle->ncp.ipcp; struct mqueue *queue; struct mbuf *bp; int cnt; - if (IpcpFsm.state != ST_OPENED) - return; - for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { + if (ipcp->fsm.state != ST_OPENED) + return 0; + + for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--) if (queue->top) { - bp = Dequeue(queue); + bp = mbuf_Dequeue(queue); if (bp) { - cnt = plength(bp); - SendPppFrame(bp); - RestartIdleTimer(); - IpcpAddOutOctets(cnt); - break; + struct ip *pip = (struct ip *)MBUF_CTOP(bp); + + cnt = mbuf_Length(bp); + if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) + bundle_StartIdleTimer(bundle); + vj_SendFrame(l, bp, bundle); + ipcp_AddOutOctets(ipcp, cnt); + return 1; } } - } + + return 0; } diff --git a/usr.sbin/ppp/ip.h b/usr.sbin/ppp/ppp/ip.h index 04d92663136..b8598aa5370 100644 --- a/usr.sbin/ppp/ip.h +++ b/usr.sbin/ppp/ppp/ip.h @@ -17,15 +17,18 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ip.h,v 1.2 1997/12/29 22:23:08 brian Exp $ + * $Id: ip.h,v 1.1 1998/08/31 00:22:21 brian Exp $ * */ -extern void IpStartOutput(void); -extern int PacketCheck(char *, int, int); -extern void IpEnqueue(int, char *, int); -extern void IpInput(struct mbuf *); -extern void StartIdleTimer(void); -extern void StopIdleTimer(void); -extern void UpdateIdleTimer(void); -extern int RemainingIdleTime(void); +struct mbuf; +struct filter; +struct link; +struct bundle; + +extern int ip_FlushPacket(struct link *, struct bundle *); +extern int PacketCheck(struct bundle *, char *, int, struct filter *); +extern void ip_Enqueue(struct ipcp *, int, char *, int); +extern void ip_Input(struct bundle *, struct mbuf *); +extern void ip_DeleteQueue(struct ipcp *); +extern int ip_QueueLen(struct ipcp *); diff --git a/usr.sbin/ppp/ppp/ipcp.c b/usr.sbin/ppp/ppp/ipcp.c new file mode 100644 index 00000000000..eb62aaeea1a --- /dev/null +++ b/usr.sbin/ppp/ppp/ipcp.c @@ -0,0 +1,1122 @@ +/* + * PPP IP Control Protocol (IPCP) Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipcp.c,v 1.1 1998/08/31 00:22:21 brian Exp $ + * + * TODO: + * o More RFC1772 backward compatibility + */ +#include <sys/param.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netdb.h> +#include <net/if.h> +#include <sys/sockio.h> +#include <sys/un.h> + +#ifndef NOALIAS +#include <alias.h> +#endif +#include <fcntl.h> +#include <resolv.h> +#include <stdlib.h> +#include <string.h> +#include <sys/errno.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "lcpproto.h" +#include "lcp.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "vjcomp.h" +#include "async.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "id.h" +#include "arp.h" +#include "systems.h" +#include "prompt.h" +#include "route.h" + +#undef REJECTED +#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) +#define issep(ch) ((ch) == ' ' || (ch) == '\t') +#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') + +struct compreq { + u_short proto; + u_char slots; + u_char compcid; +}; + +static int IpcpLayerUp(struct fsm *); +static void IpcpLayerDown(struct fsm *); +static void IpcpLayerStart(struct fsm *); +static void IpcpLayerFinish(struct fsm *); +static void IpcpInitRestartCounter(struct fsm *); +static void IpcpSendConfigReq(struct fsm *); +static void IpcpSentTerminateReq(struct fsm *); +static void IpcpSendTerminateAck(struct fsm *, u_char); +static void IpcpDecodeConfig(struct fsm *, u_char *, int, int, + struct fsm_decode *); + +static struct fsm_callbacks ipcp_Callbacks = { + IpcpLayerUp, + IpcpLayerDown, + IpcpLayerStart, + IpcpLayerFinish, + IpcpInitRestartCounter, + IpcpSendConfigReq, + IpcpSentTerminateReq, + IpcpSendTerminateAck, + IpcpDecodeConfig, + fsm_NullRecvResetReq, + fsm_NullRecvResetAck +}; + +static const char *cftypes[] = { + /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ + "???", + "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ + "COMPPROTO", /* 2: IP-Compression-Protocol */ + "IPADDR", /* 3: IP-Address */ +}; + +#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) + +static const char *cftypes128[] = { + /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ + "???", + "PRIDNS", /* 129: Primary DNS Server Address */ + "PRINBNS", /* 130: Primary NBNS Server Address */ + "SECDNS", /* 131: Secondary DNS Server Address */ + "SECNBNS", /* 132: Secondary NBNS Server Address */ +}; + +#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) + +void +ipcp_AddInOctets(struct ipcp *ipcp, int n) +{ + throughput_addin(&ipcp->throughput, n); +} + +void +ipcp_AddOutOctets(struct ipcp *ipcp, int n) +{ + throughput_addout(&ipcp->throughput, n); +} + +static void +getdns(struct ipcp *ipcp, struct in_addr addr[2]) +{ + FILE *fp; + + addr[0].s_addr = addr[1].s_addr = INADDR_ANY; + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + char buf[LINE_LEN], *cp, *end; + int n; + + n = 0; + buf[sizeof buf - 1] = '\0'; + while (fgets(buf, sizeof buf - 1, fp)) { + if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { + for (cp = buf + 11; issep(*cp); cp++) + ; + for (end = cp; isip(*end); end++) + ; + *end = '\0'; + if (inet_aton(cp, addr+n) && ++n == 2) + break; + } + } + if (n == 1) + addr[1] = addr[0]; + fclose(fp); + } +} + +static int +setdns(struct ipcp *ipcp, struct in_addr addr[2]) +{ + FILE *fp; + char wbuf[LINE_LEN + 54]; + int wlen; + + if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { + struct in_addr old[2]; + + getdns(ipcp, old); + if (addr[0].s_addr == INADDR_ANY) + addr[0] = old[0]; + if (addr[1].s_addr == INADDR_ANY) + addr[1] = old[1]; + } + + if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { + log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", + _PATH_RESCONF); + return 0; + } + + wlen = 0; + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + char buf[LINE_LEN]; + int len; + + buf[sizeof buf - 1] = '\0'; + while (fgets(buf, sizeof buf - 1, fp)) { + if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { + len = strlen(buf); + if (len > sizeof wbuf - wlen) { + log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", + _PATH_RESCONF, LINE_LEN); + fclose(fp); + return 0; + } + memcpy(wbuf + wlen, buf, len); + wlen += len; + } + } + fclose(fp); + } + + if (addr[0].s_addr != INADDR_ANY) { + snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", + inet_ntoa(addr[0])); + log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); + wlen += strlen(wbuf + wlen); + } + + if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { + snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", + inet_ntoa(addr[1])); + log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); + wlen += strlen(wbuf + wlen); + } + + if (wlen) { + int fd; + + if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { + if (write(fd, wbuf, wlen) != wlen) { + log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); + close(fd); + return 0; + } + if (ftruncate(fd, wlen) == -1) { + log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); + close(fd); + return 0; + } + close(fd); + } else { + log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); + return 0; + } + } + + return 1; +} + +int +ipcp_Show(struct cmdargs const *arg) +{ + struct ipcp *ipcp = &arg->bundle->ncp.ipcp; + + prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, + State2Nam(ipcp->fsm.state)); + if (ipcp->fsm.state == ST_OPENED) { + prompt_Printf(arg->prompt, " His side: %s, %s\n", + inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); + prompt_Printf(arg->prompt, " My side: %s, %s\n", + inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); + } + + if (ipcp->route) { + prompt_Printf(arg->prompt, "\n"); + route_ShowSticky(arg->prompt, ipcp->route); + } + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + prompt_Printf(arg->prompt, " My Address: %s/%d", + inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); + + if (ipcp->cfg.HaveTriggerAddress) + prompt_Printf(arg->prompt, " (trigger with %s)", + inet_ntoa(ipcp->cfg.TriggerAddress)); + prompt_Printf(arg->prompt, "\n VJ compression: %s (%d slots %s slot " + "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), + ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); + + if (iplist_isvalid(&ipcp->cfg.peer_list)) + prompt_Printf(arg->prompt, " His Address: %s\n", + ipcp->cfg.peer_list.src); + else + prompt_Printf(arg->prompt, " His Address: %s/%d\n", + inet_ntoa(ipcp->cfg.peer_range.ipaddr), + ipcp->cfg.peer_range.width); + + prompt_Printf(arg->prompt, " DNS: %s, ", + inet_ntoa(ipcp->cfg.ns.dns[0])); + prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), + command_ShowNegval(ipcp->cfg.ns.dns_neg)); + prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", + inet_ntoa(ipcp->cfg.ns.nbns[0])); + prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); + + prompt_Printf(arg->prompt, "\n"); + throughput_disp(&ipcp->throughput, arg->prompt); + + return 0; +} + +int +ipcp_vjset(struct cmdargs const *arg) +{ + if (arg->argc != arg->argn+2) + return -1; + if (!strcasecmp(arg->argv[arg->argn], "slots")) { + int slots; + + slots = atoi(arg->argv[arg->argn+1]); + if (slots < 4 || slots > 16) + return 1; + arg->bundle->ncp.ipcp.cfg.vj.slots = slots; + return 0; + } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { + if (!strcasecmp(arg->argv[arg->argn+1], "on")) + arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; + else if (!strcasecmp(arg->argv[arg->argn+1], "off")) + arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; + else + return 2; + return 0; + } + return -1; +} + +void +ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, + const struct fsm_parent *parent) +{ + struct hostent *hp; + char name[MAXHOSTNAMELEN]; + static const char *timer_names[] = + {"IPCP restart", "IPCP openmode", "IPCP stopped"}; + + fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP, + bundle, l, parent, &ipcp_Callbacks, timer_names); + + ipcp->route = NULL; + ipcp->cfg.vj.slots = DEF_VJ_STATES; + ipcp->cfg.vj.slotcomp = 1; + memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); + if (gethostname(name, sizeof name) == 0) { + hp = gethostbyname(name); + if (hp && hp->h_addrtype == AF_INET) { + memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; + } + } + ipcp->cfg.netmask.s_addr = INADDR_ANY; + memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); + iplist_setsrc(&ipcp->cfg.peer_list, ""); + ipcp->cfg.HaveTriggerAddress = 0; + + ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; + ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; + ipcp->cfg.ns.dns_neg = 0; + ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; + ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; + + ipcp->cfg.fsmretry = DEF_FSMRETRY; + ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; + + memset(&ipcp->vj, '\0', sizeof ipcp->vj); + + ipcp->my_ifip.s_addr = INADDR_ANY; + ipcp->peer_ifip.s_addr = INADDR_ANY; + + throughput_init(&ipcp->throughput); + memset(ipcp->Queue, '\0', sizeof ipcp->Queue); + ipcp_Setup(ipcp); +} + +void +ipcp_SetLink(struct ipcp *ipcp, struct link *l) +{ + ipcp->fsm.link = l; +} + +void +ipcp_Setup(struct ipcp *ipcp) +{ + int pos; + + ipcp->fsm.open_mode = 0; + ipcp->fsm.maxconfig = 10; + + if (iplist_isvalid(&ipcp->cfg.peer_list)) { + if (ipcp->my_ifip.s_addr != INADDR_ANY && + (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) + ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); + else + ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; + } + + ipcp->heis1172 = 0; + + ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; + ipcp->peer_compproto = 0; + + if (ipcp->cfg.HaveTriggerAddress) { + /* + * Some implementations of PPP require that we send a + * *special* value as our address, even though the rfc specifies + * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). + */ + ipcp->my_ip = ipcp->cfg.TriggerAddress; + log_Printf(LogIPCP, "Using trigger address %s\n", + inet_ntoa(ipcp->cfg.TriggerAddress)); + } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) == + (ipcp->cfg.my_range.ipaddr.s_addr & + ipcp->cfg.my_range.mask.s_addr)) + /* + * Otherwise, if we've been assigned an IP number before, we really + * want to keep the same IP number so that we can keep any existing + * connections that are bound to that IP. + */ + ipcp->my_ip = ipcp->my_ifip; + else + ipcp->my_ip = ipcp->cfg.my_range.ipaddr; + + if (IsEnabled(ipcp->cfg.vj.neg)) + ipcp->my_compproto = (PROTO_VJCOMP << 16) + + ((ipcp->cfg.vj.slots - 1) << 8) + + ipcp->cfg.vj.slotcomp; + else + ipcp->my_compproto = 0; + sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); + + ipcp->peer_reject = 0; + ipcp->my_reject = 0; +} + +static int +ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, + struct in_addr hisaddr, int silent) +{ + struct sockaddr_in *sock_in; + int s; + u_int32_t mask, addr; + struct ifaliasreq ifra; + + /* If given addresses are alreay set, then ignore this request */ + if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && + bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) + return 0; + + ipcp_CleanInterface(&bundle->ncp.ipcp); + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno)); + return (-1); + } + + memset(&ifra, '\0', sizeof ifra); + strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); + ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; + + /* Set interface address */ + sock_in = (struct sockaddr_in *)&ifra.ifra_addr; + sock_in->sin_family = AF_INET; + sock_in->sin_addr = myaddr; + sock_in->sin_len = sizeof *sock_in; + + /* Set destination address */ + sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; + sock_in->sin_family = AF_INET; + sock_in->sin_addr = hisaddr; + sock_in->sin_len = sizeof *sock_in; + + addr = ntohl(myaddr.s_addr); + if (IN_CLASSA(addr)) + mask = IN_CLASSA_NET; + else if (IN_CLASSB(addr)) + mask = IN_CLASSB_NET; + else + mask = IN_CLASSC_NET; + + /* if subnet mask is given, use it instead of class mask */ + if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && + (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) + mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); + + sock_in = (struct sockaddr_in *)&ifra.ifra_mask; + sock_in->sin_family = AF_INET; + sock_in->sin_addr.s_addr = htonl(mask); + sock_in->sin_len = sizeof *sock_in; + + if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { + if (!silent) + log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n", + strerror(errno)); + close(s); + return (-1); + } + + if (Enabled(bundle, OPT_SROUTES)) + route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); + + bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; + bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; + + if (Enabled(bundle, OPT_PROXY)) + arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); + + close(s); + return (0); +} + +static struct in_addr +ChooseHisAddr(struct bundle *bundle, const struct in_addr gw) +{ + struct in_addr try; + u_long f; + + for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { + try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); + log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", + f, inet_ntoa(try)); + if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { + log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); + break; + } + } + + if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { + log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); + try.s_addr = INADDR_ANY; + } + + return try; +} + +static void +IpcpInitRestartCounter(struct fsm * fp) +{ + /* Set fsm timer load */ + struct ipcp *ipcp = fsm2ipcp(fp); + + fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; + fp->restart = DEF_REQs; +} + +static void +IpcpSendConfigReq(struct fsm *fp) +{ + /* Send config REQ please */ + struct physical *p = link2physical(fp->link); + struct ipcp *ipcp = fsm2ipcp(fp); + u_char buff[24]; + struct lcp_opt *o; + + o = (struct lcp_opt *)buff; + + if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { + *(u_int32_t *)o->data = ipcp->my_ip.s_addr; + INC_LCP_OPT(TY_IPADDR, 6, o); + } + + if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { + if (ipcp->heis1172) { + *(u_int32_t *)o->data = htons(PROTO_VJCOMP); + INC_LCP_OPT(TY_COMPPROTO, 4, o); + } else { + *(u_int32_t *)o->data = htonl(ipcp->my_compproto); + INC_LCP_OPT(TY_COMPPROTO, 6, o); + } + } + + if (IsEnabled(ipcp->cfg.ns.dns_neg) && + !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && + !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { + struct in_addr dns[2]; + getdns(ipcp, dns); + *(u_int32_t *)o->data = dns[0].s_addr; + INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); + *(u_int32_t *)o->data = dns[1].s_addr; + INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); + } + + fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); +} + +static void +IpcpSentTerminateReq(struct fsm * fp) +{ + /* Term REQ just sent by FSM */ +} + +static void +IpcpSendTerminateAck(struct fsm *fp, u_char id) +{ + /* Send Term ACK please */ + fsm_Output(fp, CODE_TERMACK, id, NULL, 0); +} + +static void +IpcpLayerStart(struct fsm *fp) +{ + /* We're about to start up ! */ + struct ipcp *ipcp = fsm2ipcp(fp); + + log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); + throughput_start(&ipcp->throughput, "IPCP throughput", + Enabled(fp->bundle, OPT_THROUGHPUT)); + + /* This is where we should be setting up the interface in AUTO mode */ +} + +static void +IpcpLayerFinish(struct fsm *fp) +{ + /* We're now down */ + struct ipcp *ipcp = fsm2ipcp(fp); + + log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); + throughput_stop(&ipcp->throughput); + throughput_log(&ipcp->throughput, LogIPCP, NULL); +} + +void +ipcp_CleanInterface(struct ipcp *ipcp) +{ + struct ifaliasreq ifra; + struct sockaddr_in *me, *peer; + int s; + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); + return; + } + + route_Clean(ipcp->fsm.bundle, ipcp->route); + + if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) + arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); + + if (ipcp->my_ifip.s_addr != INADDR_ANY || + ipcp->peer_ifip.s_addr != INADDR_ANY) { + memset(&ifra, '\0', sizeof ifra); + strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, + sizeof ifra.ifra_name - 1); + ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; + me = (struct sockaddr_in *)&ifra.ifra_addr; + peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; + me->sin_family = peer->sin_family = AF_INET; + me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); + me->sin_addr = ipcp->my_ifip; + peer->sin_addr = ipcp->peer_ifip; + if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) + log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", + strerror(errno)); + ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; + } + + close(s); +} + +static void +IpcpLayerDown(struct fsm *fp) +{ + /* About to come down */ + struct ipcp *ipcp = fsm2ipcp(fp); + const char *s; + + s = inet_ntoa(ipcp->peer_ifip); + log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); + + /* + * XXX this stuff should really live in the FSM. Our config should + * associate executable sections in files with events. + */ + if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { + if (bundle_GetLabel(fp->bundle)) { + if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), + LINKDOWNFILE, NULL, NULL) < 0) + system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); + } else + system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); + } + + if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO)) + ipcp_CleanInterface(ipcp); + + ipcp_Setup(ipcp); +} + +int +ipcp_InterfaceUp(struct ipcp *ipcp) +{ + if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { + log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); + return 0; + } + +#ifndef NOALIAS + if (ipcp->fsm.bundle->AliasEnabled) + PacketAliasSetAddress(ipcp->my_ip); +#endif + + return 1; +} + +static int +IpcpLayerUp(struct fsm *fp) +{ + /* We're now up */ + struct ipcp *ipcp = fsm2ipcp(fp); + char tbuff[100]; + + log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); + snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); + + if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) + sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); + + if (!ipcp_InterfaceUp(ipcp)) + return 0; + + /* + * XXX this stuff should really live in the FSM. Our config should + * associate executable sections in files with events. + */ + if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, + NULL, NULL) < 0) { + if (bundle_GetLabel(fp->bundle)) { + if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), + LINKUPFILE, NULL, NULL) < 0) + system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); + } else + system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); + } + + log_DisplayPrompts(); + return 1; +} + +static int +AcceptableAddr(struct in_range *prange, struct in_addr ipaddr) +{ + /* Is the given IP in the given range ? */ + return (prange->ipaddr.s_addr & prange->mask.s_addr) == + (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; +} + +static void +IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, + struct fsm_decode *dec) +{ + /* Deal with incoming PROTO_IPCP */ + struct ipcp *ipcp = fsm2ipcp(fp); + int type, length; + u_int32_t compproto; + struct compreq *pcomp; + struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; + char tbuff[100], tbuff2[100]; + int gotdns, gotdnsnak; + + gotdns = 0; + gotdnsnak = 0; + dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; + + while (plen >= sizeof(struct fsmconfig)) { + type = *cp; + length = cp[1]; + + if (length == 0) { + log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); + break; + } + + if (type < NCFTYPES) + snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); + else if (type > 128 && type < 128 + NCFTYPES128) + snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); + else + snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); + + switch (type) { + case TY_IPADDR: /* RFC1332 */ + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + + switch (mode_type) { + case MODE_REQ: + if (iplist_isvalid(&ipcp->cfg.peer_list)) { + if (ipaddr.s_addr == INADDR_ANY || + iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || + ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, + ipaddr, 1)) { + log_Printf(LogIPCP, "%s: Address invalid or already in use\n", + inet_ntoa(ipaddr)); + if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) + /* + * If we've already got a valid address configured for the peer + * (in AUTO mode), try NAKing with that so that we don't + * have to upset things too much. + */ + ipcp->peer_ip = ipcp->peer_ifip; + else + /* Just pick an IP number from our list */ + ipcp->peer_ip = ChooseHisAddr + (fp->bundle, ipcp->cfg.my_range.ipaddr); + + if (ipcp->peer_ip.s_addr == INADDR_ANY) { + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } else { + memcpy(dec->nakend, cp, 2); + memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); + dec->nakend += length; + } + break; + } + } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { + /* + * If destination address is not acceptable, NAK with what we + * want to use. + */ + memcpy(dec->nakend, cp, 2); + if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == + (ipcp->cfg.peer_range.ipaddr.s_addr & + ipcp->cfg.peer_range.mask.s_addr)) + /* We prefer the already-configured address */ + memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); + else + memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); + dec->nakend += length; + break; + } + ipcp->peer_ip = ipaddr; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + break; + case MODE_NAK: + if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { + /* Use address suggested by peer */ + snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, + inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); + ipcp->my_ip = ipaddr; + } else { + log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, + "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); + fsm_Close(&ipcp->fsm); + } + break; + case MODE_REJ: + ipcp->peer_reject |= (1 << type); + break; + } + break; + case TY_COMPPROTO: + compproto = htonl(*(u_int32_t *)(cp + 2)); + log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); + + switch (mode_type) { + case MODE_REQ: + if (!IsAccepted(ipcp->cfg.vj.neg)) { + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } else { + pcomp = (struct compreq *) (cp + 2); + switch (length) { + case 4: /* RFC1172 */ + if (ntohs(pcomp->proto) == PROTO_VJCOMP) { + log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); + ipcp->heis1172 = 1; + ipcp->peer_compproto = compproto; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } else { + memcpy(dec->nakend, cp, 2); + pcomp->proto = htons(PROTO_VJCOMP); + memcpy(dec->nakend+2, &pcomp, 2); + dec->nakend += length; + } + break; + case 6: /* RFC1332 */ + if (ntohs(pcomp->proto) == PROTO_VJCOMP + && pcomp->slots <= MAX_VJ_STATES + && pcomp->slots >= MIN_VJ_STATES) { + ipcp->peer_compproto = compproto; + ipcp->heis1172 = 0; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } else { + memcpy(dec->nakend, cp, 2); + pcomp->proto = htons(PROTO_VJCOMP); + pcomp->slots = DEF_VJ_STATES; + pcomp->compcid = 0; + memcpy(dec->nakend+2, &pcomp, sizeof pcomp); + dec->nakend += length; + } + break; + default: + memcpy(dec->rejend, cp, length); + dec->rejend += length; + break; + } + } + break; + case MODE_NAK: + log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", + tbuff, ipcp->my_compproto, compproto); + ipcp->my_compproto = compproto; + break; + case MODE_REJ: + ipcp->peer_reject |= (1 << type); + break; + } + break; + case TY_IPADDRS: /* RFC1172 */ + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + dstipaddr.s_addr = *(u_int32_t *)(cp + 6); + snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); + log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); + + switch (mode_type) { + case MODE_REQ: + ipcp->peer_ip = ipaddr; + ipcp->my_ip = dstipaddr; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + break; + case MODE_NAK: + snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, + inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); + ipcp->my_ip = ipaddr; + ipcp->peer_ip = dstipaddr; + break; + case MODE_REJ: + ipcp->peer_reject |= (1 << type); + break; + } + break; + + case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ + case TY_SECONDARY_DNS: + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + + switch (mode_type) { + case MODE_REQ: + if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { + ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + break; + } + if (!gotdns) { + dns[0] = ipcp->cfg.ns.dns[0]; + dns[1] = ipcp->cfg.ns.dns[1]; + if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) + getdns(ipcp, dns); + gotdns = 1; + } + have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; + + if (ipaddr.s_addr != have_ip.s_addr) { + /* + * The client has got the DNS stuff wrong (first request) so + * we'll tell 'em how it is + */ + memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ + memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); + dec->nakend += length; + } else { + /* + * Otherwise they have it right (this time) so we send a ack packet + * back confirming it... end of story + */ + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } + break; + case MODE_NAK: /* what does this mean?? */ + if (IsEnabled(ipcp->cfg.ns.dns_neg)) { + gotdnsnak = 1; + dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr = + *(u_int32_t *)(cp + 2); + } + break; + case MODE_REJ: /* Can't do much, stop asking */ + ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); + break; + } + break; + + case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ + case TY_SECONDARY_NBNS: + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + + switch (mode_type) { + case MODE_REQ: + have_ip.s_addr = + ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; + + if (have_ip.s_addr == INADDR_ANY) { + log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); + ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + break; + } + + if (ipaddr.s_addr != have_ip.s_addr) { + memcpy(dec->nakend, cp, 2); + memcpy(dec->nakend+2, &have_ip.s_addr, length); + dec->nakend += length; + } else { + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } + break; + case MODE_NAK: + log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); + break; + case MODE_REJ: + log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); + break; + } + break; + + default: + if (mode_type != MODE_NOP) { + ipcp->my_reject |= (1 << type); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } + break; + } + plen -= length; + cp += length; + } + + if (gotdnsnak) + if (!setdns(ipcp, dnsnak)) { + ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); + ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); + } + + if (mode_type != MODE_NOP) { + if (dec->rejend != dec->rej) { + /* rejects are preferred */ + dec->ackend = dec->ack; + dec->nakend = dec->nak; + } else if (dec->nakend != dec->nak) + /* then NAKs */ + dec->ackend = dec->ack; + } +} + +void +ipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) +{ + /* Got PROTO_IPCP from link */ + if (bundle_Phase(bundle) == PHASE_NETWORK) + fsm_Input(&ipcp->fsm, bp); + else { + if (bundle_Phase(bundle) < PHASE_NETWORK) + log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", + ipcp->fsm.link->name, bundle_PhaseName(bundle)); + mbuf_Free(bp); + } +} + +int +ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) +{ + struct ipcp *ipcp = &bundle->ncp.ipcp; + + /* Use `hisaddr' for the peers address (set iface if `setaddr') */ + memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); + iplist_reset(&ipcp->cfg.peer_list); + if (strpbrk(hisaddr, ",-")) { + iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); + if (iplist_isvalid(&ipcp->cfg.peer_list)) { + iplist_setrandpos(&ipcp->cfg.peer_list); + ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); + if (ipcp->peer_ip.s_addr == INADDR_ANY) { + log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); + return(0); + } + ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; + } else { + log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); + return 0; + } + } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, + &ipcp->cfg.peer_range.mask, + &ipcp->cfg.peer_range.width) != 0) { + ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; + + if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, + ipcp->cfg.peer_range.ipaddr, 0) < 0) { + ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; + ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; + return 0; + } + } else + return 0; + + return 1; +} diff --git a/usr.sbin/ppp/ppp/ipcp.h b/usr.sbin/ppp/ppp/ipcp.h new file mode 100644 index 00000000000..0f293080468 --- /dev/null +++ b/usr.sbin/ppp/ppp/ipcp.h @@ -0,0 +1,115 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipcp.h,v 1.1 1998/08/31 00:22:22 brian Exp $ + * + * TODO: + */ + +#define IPCP_MAXCODE CODE_CODEREJ + +#define TY_IPADDRS 1 +#define TY_COMPPROTO 2 +#define TY_IPADDR 3 + +/* Domain NameServer and NetBIOS NameServer options */ + +#define TY_PRIMARY_DNS 129 +#define TY_PRIMARY_NBNS 130 +#define TY_SECONDARY_DNS 131 +#define TY_SECONDARY_NBNS 132 +#define TY_ADJUST_NS 119 /* subtract from NS val for REJECT bit */ + +struct sticky_route; + +struct in_range { + struct in_addr ipaddr; + struct in_addr mask; + int width; +}; + +struct ipcp { + struct fsm fsm; /* The finite state machine */ + + struct { + struct { + int slots; /* Maximum VJ slots */ + unsigned slotcomp : 1; /* Slot compression */ + unsigned neg : 2; /* VJ negotiation */ + } vj; + + struct in_range my_range; /* MYADDR spec */ + struct in_addr netmask; /* netmask (unused by most OSs) */ + struct in_range peer_range; /* HISADDR spec */ + struct iplist peer_list; /* Ranges of HISADDR values */ + + struct in_addr TriggerAddress; /* Address to suggest in REQ */ + unsigned HaveTriggerAddress : 1; /* Trigger address specified */ + + struct { + struct in_addr dns[2]; /* DNS addresses offered */ + unsigned dns_neg : 2; /* dns negotiation */ + struct in_addr nbns[2]; /* NetBIOS NS addresses offered */ + } ns; + + u_int fsmretry; /* FSM retry frequency */ + } cfg; + + struct { + struct slcompress cslc; /* VJ state */ + struct slstat slstat; /* VJ statistics */ + } vj; + + struct sticky_route *route; /* List of dynamic routes */ + + unsigned heis1172 : 1; /* True if he is speaking rfc1172 */ + + struct in_addr peer_ip; /* IP address he's willing to use */ + u_int32_t peer_compproto; /* VJ params he's willing to use */ + + struct in_addr my_ip; /* IP address I'm willing to use */ + u_int32_t my_compproto; /* VJ params I'm willing to use */ + + u_int32_t peer_reject; /* Request codes rejected by peer */ + u_int32_t my_reject; /* Request codes I have rejected */ + + struct in_addr my_ifip; /* My configured interface address */ + struct in_addr peer_ifip; /* My congigured destination address */ + + struct pppThroughput throughput; /* throughput statistics */ + struct mqueue Queue[PRI_FAST + 1]; /* Output packet queues */ +}; + +#define fsm2ipcp(fp) (fp->proto == PROTO_IPCP ? (struct ipcp *)fp : NULL) + +struct bundle; +struct link; +struct cmdargs; + +extern void ipcp_Init(struct ipcp *, struct bundle *, struct link *, + const struct fsm_parent *); +extern void ipcp_Setup(struct ipcp *); +extern void ipcp_SetLink(struct ipcp *, struct link *); + +extern int ipcp_Show(struct cmdargs const *); +extern void ipcp_Input(struct ipcp *, struct bundle *, struct mbuf *); +extern void ipcp_AddInOctets(struct ipcp *, int); +extern void ipcp_AddOutOctets(struct ipcp *, int); +extern int ipcp_UseHisaddr(struct bundle *, const char *, int); +extern int ipcp_vjset(struct cmdargs const *); +extern void ipcp_CleanInterface(struct ipcp *); +extern int ipcp_InterfaceUp(struct ipcp *); diff --git a/usr.sbin/ppp/iplist.c b/usr.sbin/ppp/ppp/iplist.c index 937d74cc185..4acbecc67ce 100644 --- a/usr.sbin/ppp/iplist.c +++ b/usr.sbin/ppp/ppp/iplist.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iplist.c,v 1.4 1997/12/24 09:30:37 brian Exp $ + * $Id: iplist.c,v 1.1 1998/08/31 00:22:22 brian Exp $ */ #include <sys/types.h> @@ -33,8 +33,6 @@ #include <stdlib.h> #include <string.h> -#include "command.h" -#include "mbuf.h" #include "log.h" #include "defs.h" #include "iplist.h" @@ -42,10 +40,10 @@ static int do_inet_aton(const char *start, const char *end, struct in_addr *ip) { - static char ipstr[16]; + char ipstr[16]; if (end - start > 15) { - LogPrintf(LogWARN, "%.*s: Invalid IP address\n", end-start, start); + log_Printf(LogWARN, "%.*s: Invalid IP address\n", (int)(end-start), start); return 0; } strncpy(ipstr, start, end-start); @@ -112,7 +110,8 @@ iplist_nextrange(struct iplist *list) end = ptr + strlen(ptr); if (end == ptr) return 0; - LogPrintf(LogWARN, "%.*s: Invalid IP range (skipping)\n", end - ptr, ptr); + log_Printf(LogWARN, "%.*s: Invalid IP range (skipping)\n", + (int)(end - ptr), ptr); to = ptr; do *to = *end++; @@ -170,7 +169,7 @@ iplist_reset(struct iplist *list) } struct in_addr -iplist_setcurpos(struct iplist *list, int pos) +iplist_setcurpos(struct iplist *list, long pos) { if (pos < 0 || pos >= list->nItems) { list->cur.pos = -1; @@ -208,7 +207,8 @@ int iplist_ip2pos(struct iplist *list, struct in_addr ip) { struct iplist_cur cur; - int f, result; + u_long f; + int result; result = -1; memcpy(&cur, &list->cur, sizeof cur); diff --git a/usr.sbin/ppp/iplist.h b/usr.sbin/ppp/ppp/iplist.h index 6d348034ad6..c9f941973b2 100644 --- a/usr.sbin/ppp/iplist.h +++ b/usr.sbin/ppp/ppp/iplist.h @@ -23,25 +23,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: iplist.h,v 1.3 1998/06/28 09:41:39 brian Exp $ + * $Id: iplist.h,v 1.1 1998/08/31 00:22:22 brian Exp $ */ +struct iplist_cur { + struct in_addr ip; + int pos; + char *srcptr; + u_long srcitem; + u_int32_t lstart; + u_long nItems; +}; + struct iplist { - struct iplist_cur { - struct in_addr ip; - int pos; - char *srcptr; - u_long srcitem; - u_int32_t lstart; - u_long nItems; - } cur; - int nItems; + struct iplist_cur cur; + u_long nItems; char src[LINE_LEN]; }; extern int iplist_setsrc(struct iplist *, const char *); extern void iplist_reset(struct iplist *); -extern struct in_addr iplist_setcurpos(struct iplist *, int); +extern struct in_addr iplist_setcurpos(struct iplist *, long); extern struct in_addr iplist_setrandpos(struct iplist *); extern int iplist_ip2pos(struct iplist *, struct in_addr); extern struct in_addr iplist_next(struct iplist *); diff --git a/usr.sbin/ppp/ppp/lcp.c b/usr.sbin/ppp/ppp/lcp.c new file mode 100644 index 00000000000..b506cefdb18 --- /dev/null +++ b/usr.sbin/ppp/ppp/lcp.c @@ -0,0 +1,1063 @@ +/* + * PPP Link Control Protocol (LCP) Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lcp.c,v 1.1 1998/08/31 00:22:22 brian Exp $ + * + * TODO: + * o Limit data field length by MRU + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "lcp.h" +#include "throughput.h" +#include "lcpproto.h" +#include "descriptor.h" +#include "lqr.h" +#include "hdlc.h" +#include "ccp.h" +#include "async.h" +#include "link.h" +#include "physical.h" +#include "prompt.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "mp.h" +#include "chat.h" +#include "auth.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" +#include "bundle.h" + +/* for received LQRs */ +struct lqrreq { + u_char type; + u_char length; + u_short proto; /* Quality protocol */ + u_int32_t period; /* Reporting interval */ +}; + +static int LcpLayerUp(struct fsm *); +static void LcpLayerDown(struct fsm *); +static void LcpLayerStart(struct fsm *); +static void LcpLayerFinish(struct fsm *); +static void LcpInitRestartCounter(struct fsm *); +static void LcpSendConfigReq(struct fsm *); +static void LcpSentTerminateReq(struct fsm *); +static void LcpSendTerminateAck(struct fsm *, u_char); +static void LcpDecodeConfig(struct fsm *, u_char *, int, int, + struct fsm_decode *); + +static struct fsm_callbacks lcp_Callbacks = { + LcpLayerUp, + LcpLayerDown, + LcpLayerStart, + LcpLayerFinish, + LcpInitRestartCounter, + LcpSendConfigReq, + LcpSentTerminateReq, + LcpSendTerminateAck, + LcpDecodeConfig, + fsm_NullRecvResetReq, + fsm_NullRecvResetAck +}; + +static const char *lcp_TimerNames[] = + {"LCP restart", "LCP openmode", "LCP stopped"}; + +static const char *cftypes[] = { + /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ + "???", + "MRU", /* 1: Maximum-Receive-Unit */ + "ACCMAP", /* 2: Async-Control-Character-Map */ + "AUTHPROTO", /* 3: Authentication-Protocol */ + "QUALPROTO", /* 4: Quality-Protocol */ + "MAGICNUM", /* 5: Magic-Number */ + "RESERVED", /* 6: RESERVED */ + "PROTOCOMP", /* 7: Protocol-Field-Compression */ + "ACFCOMP", /* 8: Address-and-Control-Field-Compression */ + "FCSALT", /* 9: FCS-Alternatives */ + "SDP", /* 10: Self-Describing-Pad */ + "NUMMODE", /* 11: Numbered-Mode */ + "MULTIPROC", /* 12: Multi-Link-Procedure */ + "CALLBACK", /* 13: Callback */ + "CONTIME", /* 14: Connect-Time */ + "COMPFRAME", /* 15: Compound-Frames */ + "NDE", /* 16: Nominal-Data-Encapsulation */ + "MRRU", /* 17: Multilink-MRRU */ + "SHORTSEQ", /* 18: Multilink-Short-Sequence-Number-Header */ + "ENDDISC", /* 19: Multilink-Endpoint-Discriminator */ + "PROPRIETRY", /* 20: Proprietary */ + "DCEID", /* 21: DCE-Identifier */ + "MULTIPP", /* 22: Multi-Link-Plus-Procedure */ + "LDBACP", /* 23: Link Discriminator for BACP */ +}; + +#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) + +int +lcp_ReportStatus(struct cmdargs const *arg) +{ + struct link *l; + struct lcp *lcp; + + l = command_ChooseLink(arg); + lcp = &l->lcp; + + prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name, + State2Nam(lcp->fsm.state)); + prompt_Printf(arg->prompt, + " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" + " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", + lcp->his_mru, (u_long)lcp->his_accmap, + lcp->his_protocomp ? "on" : "off", + lcp->his_acfcomp ? "on" : "off", + (u_long)lcp->his_magic, lcp->his_mrru, + lcp->his_shortseq ? "on" : "off", lcp->his_reject); + prompt_Printf(arg->prompt, + " my side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" + " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", + lcp->want_mru, (u_long)lcp->want_accmap, + lcp->want_protocomp ? "on" : "off", + lcp->want_acfcomp ? "on" : "off", + (u_long)lcp->want_magic, lcp->want_mrru, + lcp->want_shortseq ? "on" : "off", lcp->my_reject); + + prompt_Printf(arg->prompt, "\n Defaults: MRU = %d, ", lcp->cfg.mru); + prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap); + prompt_Printf(arg->prompt, " LQR period = %us, ", + lcp->cfg.lqrperiod); + prompt_Printf(arg->prompt, "Open Mode = %s", + lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active"); + if (lcp->cfg.openmode > 0) + prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode); + prompt_Printf(arg->prompt, "\n FSM retry = %us\n", + lcp->cfg.fsmretry); + prompt_Printf(arg->prompt, "\n Negotiation:\n"); + prompt_Printf(arg->prompt, " ACFCOMP = %s\n", + command_ShowNegval(lcp->cfg.acfcomp)); + prompt_Printf(arg->prompt, " CHAP = %s\n", + command_ShowNegval(lcp->cfg.chap)); + prompt_Printf(arg->prompt, " LQR = %s\n", + command_ShowNegval(lcp->cfg.lqr)); + prompt_Printf(arg->prompt, " PAP = %s\n", + command_ShowNegval(lcp->cfg.pap)); + prompt_Printf(arg->prompt, " PROTOCOMP = %s\n", + command_ShowNegval(lcp->cfg.protocomp)); + + return 0; +} + +static u_int32_t +GenerateMagic(void) +{ + /* Generate random number which will be used as magic number */ + randinit(); + return random(); +} + +void +lcp_SetupCallbacks(struct lcp *lcp) +{ + lcp->fsm.fn = &lcp_Callbacks; + lcp->fsm.FsmTimer.name = lcp_TimerNames[0]; + lcp->fsm.OpenTimer.name = lcp_TimerNames[1]; + lcp->fsm.StoppedTimer.name = lcp_TimerNames[2]; +} + +void +lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l, + const struct fsm_parent *parent) +{ + /* Initialise ourselves */ + int mincode = parent ? 1 : LCP_MINMPCODE; + + fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, 10, LogLCP, + bundle, l, parent, &lcp_Callbacks, lcp_TimerNames); + + lcp->cfg.mru = DEF_MRU; + lcp->cfg.accmap = 0; + lcp->cfg.openmode = 1; + lcp->cfg.lqrperiod = DEF_LQRPERIOD; + lcp->cfg.fsmretry = DEF_FSMRETRY; + + lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED; + lcp->cfg.chap = NEG_ACCEPTED; + lcp->cfg.lqr = NEG_ACCEPTED; + lcp->cfg.pap = NEG_ACCEPTED; + lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED; + + lcp_Setup(lcp, lcp->cfg.openmode); +} + +void +lcp_Setup(struct lcp *lcp, int openmode) +{ + lcp->fsm.open_mode = openmode; + lcp->fsm.maxconfig = 10; + + lcp->his_mru = DEF_MRU; + lcp->his_mrru = 0; + lcp->his_magic = 0; + lcp->his_lqrperiod = 0; + lcp->his_acfcomp = 0; + lcp->his_auth = 0; + lcp->his_callback.opmask = 0; + lcp->his_shortseq = 0; + + lcp->want_mru = lcp->cfg.mru; + lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru; + lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0; + lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0; + + if (lcp->fsm.parent) { + struct physical *p = link2physical(lcp->fsm.link); + + lcp->his_accmap = 0xffffffff; + lcp->want_accmap = lcp->cfg.accmap; + lcp->his_protocomp = 0; + lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0; + lcp->want_magic = GenerateMagic(); + lcp->want_auth = IsEnabled(lcp->cfg.chap) ? PROTO_CHAP : + IsEnabled(lcp->cfg.pap) ? PROTO_PAP : 0; + if (p->type != PHYS_DIRECT) + memcpy(&lcp->want_callback, &p->dl->cfg.callback, sizeof(struct callback)); + else + lcp->want_callback.opmask = 0; + lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ? + lcp->cfg.lqrperiod * 100 : 0; + } else { + lcp->his_accmap = lcp->want_accmap = 0; + lcp->his_protocomp = lcp->want_protocomp = 1; + lcp->want_magic = 0; + lcp->want_auth = 0; + lcp->want_callback.opmask = 0; + lcp->want_lqrperiod = 0; + } + + lcp->his_reject = lcp->my_reject = 0; + lcp->auth_iwait = lcp->auth_ineed = 0; + lcp->LcpFailedMagic = 0; +} + +static void +LcpInitRestartCounter(struct fsm * fp) +{ + /* Set fsm timer load */ + struct lcp *lcp = fsm2lcp(fp); + + fp->FsmTimer.load = lcp->cfg.fsmretry * SECTICKS; + fp->restart = DEF_REQs; +} + +static void +LcpSendConfigReq(struct fsm *fp) +{ + /* Send config REQ please */ + struct physical *p = link2physical(fp->link); + struct lcp *lcp = fsm2lcp(fp); + u_char buff[200]; + struct lcp_opt *o; + struct mp *mp; + + if (!p) { + log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n", + fp->link->name); + return; + } + + o = (struct lcp_opt *)buff; + if (!physical_IsSync(p)) { + if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) + INC_LCP_OPT(TY_ACFCOMP, 2, o); + + if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) + INC_LCP_OPT(TY_PROTOCOMP, 2, o); + + if (!REJECTED(lcp, TY_ACCMAP)) { + *(u_int32_t *)o->data = htonl(lcp->want_accmap); + INC_LCP_OPT(TY_ACCMAP, 6, o); + } + } + + if (!REJECTED(lcp, TY_MRU)) { + *(u_int16_t *)o->data = htons(lcp->want_mru); + INC_LCP_OPT(TY_MRU, 4, o); + } + + if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) { + *(u_int32_t *)o->data = htonl(lcp->want_magic); + INC_LCP_OPT(TY_MAGICNUM, 6, o); + } + + if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { + *(u_int16_t *)o->data = htons(PROTO_LQR); + *(u_int32_t *)(o->data + 2) = htonl(lcp->want_lqrperiod); + INC_LCP_OPT(TY_QUALPROTO, 8, o); + } + + switch (lcp->want_auth) { + case PROTO_PAP: + *(u_int16_t *)o->data = htons(PROTO_PAP); + INC_LCP_OPT(TY_AUTHPROTO, 4, o); + break; + + case PROTO_CHAP: + *(u_int16_t *)o->data = htons(PROTO_CHAP); + o->data[2] = 0x05; + INC_LCP_OPT(TY_AUTHPROTO, 5, o); + break; + } + + if (!REJECTED(lcp, TY_CALLBACK)) { + if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { + *o->data = CALLBACK_AUTH; + INC_LCP_OPT(TY_CALLBACK, 3, o); + } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { + *o->data = CALLBACK_CBCP; + INC_LCP_OPT(TY_CALLBACK, 3, o); + } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { + int sz = strlen(lcp->want_callback.msg); + + if (sz > sizeof o->data - 1) { + sz = sizeof o->data - 1; + log_Printf(LogWARN, "Truncating E164 data to %d octets (oops!)\n", sz); + } + *o->data = CALLBACK_E164; + memcpy(o->data + 1, lcp->want_callback.msg, sz); + INC_LCP_OPT(TY_CALLBACK, sz + 3, o); + } + } + + if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) { + *(u_int16_t *)o->data = htons(lcp->want_mrru); + INC_LCP_OPT(TY_MRRU, 4, o); + + if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ)) + INC_LCP_OPT(TY_SHORTSEQ, 2, o); + } + + mp = &lcp->fsm.bundle->ncp.mp; + if (mp->cfg.enddisc.class != 0 && !REJECTED(lcp, TY_ENDDISC)) { + *o->data = mp->cfg.enddisc.class; + memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len); + INC_LCP_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o); + } + + fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); +} + +void +lcp_SendProtoRej(struct lcp *lcp, u_char *option, int count) +{ + /* Don't understand `option' */ + fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count); +} + +static void +LcpSentTerminateReq(struct fsm * fp) +{ + /* Term REQ just sent by FSM */ +} + +static void +LcpSendTerminateAck(struct fsm *fp, u_char id) +{ + /* Send Term ACK please */ + struct physical *p = link2physical(fp->link); + + if (p && p->dl->state == DATALINK_CBCP) + cbcp_ReceiveTerminateReq(p); + + fsm_Output(fp, CODE_TERMACK, id, NULL, 0); +} + +static void +LcpLayerStart(struct fsm *fp) +{ + /* We're about to start up ! */ + struct lcp *lcp = fsm2lcp(fp); + + log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name); + lcp->LcpFailedMagic = 0; +} + +static void +LcpLayerFinish(struct fsm *fp) +{ + /* We're now down */ + log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name); +} + +static int +LcpLayerUp(struct fsm *fp) +{ + /* We're now up */ + struct physical *p = link2physical(fp->link); + struct lcp *lcp = fsm2lcp(fp); + + log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name); + async_SetLinkParams(&p->async, lcp); + lqr_Start(lcp); + hdlc_StartTimer(&p->hdlc); + return 1; +} + +static void +LcpLayerDown(struct fsm *fp) +{ + /* About to come down */ + struct physical *p = link2physical(fp->link); + + log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name); + hdlc_StopTimer(&p->hdlc); + lqr_StopTimer(p); + lcp_Setup(fsm2lcp(fp), 0); +} + +static int +E164ok(struct callback *cb, char *req, int sz) +{ + char list[sizeof cb->msg], *next; + int len; + + if (!strcmp(cb->msg, "*")) + return 1; + + strncpy(list, cb->msg, sizeof list - 1); + list[sizeof list - 1] = '\0'; + for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { + len = strlen(next); + if (sz == len && !memcmp(list, req, sz)) + return 1; + } + return 0; +} + +static void +LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, + struct fsm_decode *dec) +{ + /* Deal with incoming PROTO_LCP */ + struct lcp *lcp = fsm2lcp(fp); + int type, length, sz, pos, op, callback_req; + u_int32_t magic, accmap; + u_short mtu, mru, proto; + u_int16_t *sp; + struct lqrreq *req; + char request[20], desc[22]; + struct mp *mp; + struct physical *p = link2physical(fp->link); + + callback_req = 0; + + while (plen >= sizeof(struct fsmconfig)) { + type = *cp; + length = cp[1]; + + if (type < 0 || type >= NCFTYPES) + snprintf(request, sizeof request, " <%d>[%d]", type, length); + else + snprintf(request, sizeof request, " %s[%d]", cftypes[type], length); + + if (length < 2) { + log_Printf(LogLCP, "%s:%s: Bad LCP length\n", fp->link->name, request); + break; + } + + switch (type) { + case TY_MRRU: + mp = &lcp->fsm.bundle->ncp.mp; + sp = (u_int16_t *)(cp + 2); + mru = htons(*sp); + log_Printf(LogLCP, "%s %u\n", request, mru); + + switch (mode_type) { + case MODE_REQ: + if (mp->cfg.mrru) { + if (REJECTED(lcp, TY_MRRU)) + /* Ignore his previous reject so that we REQ next time */ + lcp->his_reject &= ~(1 << type); + + mtu = lcp->fsm.bundle->cfg.mtu; + if (mru < MIN_MRU || mru < mtu) { + /* Push him up to MTU or MIN_MRU */ + lcp->his_mrru = mru < mtu ? mtu : MIN_MRU; + *sp = htons((u_int16_t)lcp->his_mrru); + memcpy(dec->nakend, cp, 4); + dec->nakend += 4; + } else { + lcp->his_mrru = mtu ? mtu : mru; + memcpy(dec->ackend, cp, 4); + dec->ackend += 4; + } + break; + } else + goto reqreject; + break; + case MODE_NAK: + if (mp->cfg.mrru) { + if (REJECTED(lcp, TY_MRRU)) + /* Must have changed his mind ! */ + lcp->his_reject &= ~(1 << type); + + if (mru > MAX_MRU) + lcp->want_mrru = MAX_MRU; + else if (mru < MIN_MRU) + lcp->want_mrru = MIN_MRU; + else + lcp->want_mrru = mru; + } + /* else we honour our config and don't send the suggested REQ */ + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + lcp->want_mrru = 0; /* Ah well, no multilink :-( */ + break; + } + break; + + case TY_MRU: + sp = (u_int16_t *) (cp + 2); + mru = htons(*sp); + log_Printf(LogLCP, "%s %d\n", request, mru); + + switch (mode_type) { + case MODE_REQ: + mtu = lcp->fsm.bundle->cfg.mtu; + if (mru < MIN_MRU || (!lcp->want_mrru && mru < mtu)) { + /* Push him up to MTU or MIN_MRU */ + lcp->his_mru = mru < mtu ? mtu : MIN_MRU; + *sp = htons((u_int16_t)lcp->his_mru); + memcpy(dec->nakend, cp, 4); + dec->nakend += 4; + } else { + lcp->his_mru = mtu ? mtu : mru; + memcpy(dec->ackend, cp, 4); + dec->ackend += 4; + } + break; + case MODE_NAK: + if (mru > MAX_MRU) + lcp->want_mru = MAX_MRU; + else if (mru < MIN_MRU) + lcp->want_mru = MIN_MRU; + else + lcp->want_mru = mru; + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_ACCMAP: + accmap = htonl(*(u_int32_t *)(cp + 2)); + log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap); + + switch (mode_type) { + case MODE_REQ: + lcp->his_accmap = accmap; + memcpy(dec->ackend, cp, 6); + dec->ackend += 6; + break; + case MODE_NAK: + lcp->want_accmap = accmap; + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_AUTHPROTO: + sp = (u_int16_t *) (cp + 2); + proto = ntohs(*sp); + switch (proto) { + case PROTO_PAP: + log_Printf(LogLCP, "%s 0x%04x (PAP)\n", request, proto); + break; + case PROTO_CHAP: + log_Printf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]); + break; + default: + log_Printf(LogLCP, "%s 0x%04x\n", request, proto); + break; + } + + switch (mode_type) { + case MODE_REQ: + switch (proto) { + case PROTO_PAP: + if (length != 4) { + log_Printf(LogLCP, " Bad length!\n"); + goto reqreject; + } + if (IsAccepted(lcp->cfg.pap)) { + lcp->his_auth = proto; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } else if (IsAccepted(lcp->cfg.chap)) { + *dec->nakend++ = *cp; + *dec->nakend++ = 5; + *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8); + *dec->nakend++ = (unsigned char) PROTO_CHAP; + *dec->nakend++ = 0x05; + } else + goto reqreject; + break; + + case PROTO_CHAP: + if (length < 5) { + log_Printf(LogLCP, " Bad length!\n"); + goto reqreject; + } +#ifdef HAVE_DES + if (IsAccepted(lcp->cfg.chap) && (cp[4] == 0x05 || cp[4] == 0x80)) +#else + if (IsAccepted(lcp->cfg.chap) && cp[4] == 0x05) +#endif + { + lcp->his_auth = proto; + memcpy(dec->ackend, cp, length); + dec->ackend += length; +#ifdef HAVE_DES + link2physical(fp->link)->dl->chap.using_MSChap = cp[4] == 0x80; +#endif + } else if (IsAccepted(lcp->cfg.pap)) { + *dec->nakend++ = *cp; + *dec->nakend++ = 4; + *dec->nakend++ = (unsigned char) (PROTO_PAP >> 8); + *dec->nakend++ = (unsigned char) PROTO_PAP; + } else + goto reqreject; + break; + + default: + log_Printf(LogLCP, "%s 0x%04x - not recognised, NAK\n", + request, proto); + memcpy(dec->nakend, cp, length); + dec->nakend += length; + break; + } + break; + case MODE_NAK: + switch (proto) { + case PROTO_PAP: + if (IsEnabled(lcp->cfg.pap)) + lcp->want_auth = PROTO_PAP; + else { + log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n"); + lcp->his_reject |= (1 << type); + } + break; + case PROTO_CHAP: + if (IsEnabled(lcp->cfg.chap)) + lcp->want_auth = PROTO_CHAP; + else { + log_Printf(LogLCP, "Peer will only send CHAP (not enabled)\n"); + lcp->his_reject |= (1 << type); + } + break; + default: + /* We've been NAK'd with something we don't understand :-( */ + lcp->his_reject |= (1 << type); + break; + } + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_QUALPROTO: + req = (struct lqrreq *)cp; + log_Printf(LogLCP, "%s proto %x, interval %lums\n", + request, ntohs(req->proto), (u_long)ntohl(req->period) * 10); + switch (mode_type) { + case MODE_REQ: + if (ntohs(req->proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr)) + goto reqreject; + else { + lcp->his_lqrperiod = ntohl(req->period); + if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100) + lcp->his_lqrperiod = MIN_LQRPERIOD * 100; + req->period = htonl(lcp->his_lqrperiod); + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } + break; + case MODE_NAK: + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_MAGICNUM: + magic = ntohl(*(u_int32_t *)(cp + 2)); + log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic); + + switch (mode_type) { + case MODE_REQ: + if (lcp->want_magic) { + /* Validate magic number */ + if (magic == lcp->want_magic) { + log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n", + (u_long)magic, ++lcp->LcpFailedMagic); + lcp->want_magic = GenerateMagic(); + memcpy(dec->nakend, cp, 6); + dec->nakend += 6; + ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0); + sigpause(0); + } else { + lcp->his_magic = magic; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + lcp->LcpFailedMagic = 0; + } + } else { + goto reqreject; + } + break; + case MODE_NAK: + log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic); + lcp->want_magic = GenerateMagic(); + break; + case MODE_REJ: + log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic); + lcp->want_magic = 0; + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_PROTOCOMP: + log_Printf(LogLCP, "%s\n", request); + + switch (mode_type) { + case MODE_REQ: + if (IsAccepted(lcp->cfg.protocomp)) { + lcp->his_protocomp = 1; + memcpy(dec->ackend, cp, 2); + dec->ackend += 2; + } else { +#ifdef OLDMST + /* + * MorningStar before v1.3 needs NAK + */ + memcpy(dec->nakend, cp, 2); + dec->nakend += 2; +#else + goto reqreject; +#endif + } + break; + case MODE_NAK: + case MODE_REJ: + lcp->want_protocomp = 0; + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_ACFCOMP: + log_Printf(LogLCP, "%s\n", request); + switch (mode_type) { + case MODE_REQ: + if (IsAccepted(lcp->cfg.acfcomp)) { + lcp->his_acfcomp = 1; + memcpy(dec->ackend, cp, 2); + dec->ackend += 2; + } else { +#ifdef OLDMST + /* + * MorningStar before v1.3 needs NAK + */ + memcpy(dec->nakend, cp, 2); + dec->nakend += 2; +#else + goto reqreject; +#endif + } + break; + case MODE_NAK: + case MODE_REJ: + lcp->want_acfcomp = 0; + lcp->his_reject |= (1 << type); + break; + } + break; + + case TY_SDP: + log_Printf(LogLCP, "%s\n", request); + switch (mode_type) { + case MODE_REQ: + case MODE_NAK: + case MODE_REJ: + break; + } + break; + + case TY_CALLBACK: + if (length == 2) + op = CALLBACK_NONE; + else + op = (int)cp[2]; + sz = length - 3; + switch (op) { + case CALLBACK_AUTH: + log_Printf(LogLCP, "%s Auth\n", request); + break; + case CALLBACK_DIALSTRING: + log_Printf(LogLCP, "%s Dialstring %.*s\n", request, sz, cp + 3); + break; + case CALLBACK_LOCATION: + log_Printf(LogLCP, "%s Location %.*s\n", request, sz, cp + 3); + break; + case CALLBACK_E164: + log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, sz, cp + 3); + break; + case CALLBACK_NAME: + log_Printf(LogLCP, "%s Name %.*s\n", request, sz, cp + 3); + break; + case CALLBACK_CBCP: + log_Printf(LogLCP, "%s CBCP\n", request); + break; + default: + log_Printf(LogLCP, "%s ???\n", request); + break; + } + + switch (mode_type) { + case MODE_REQ: + callback_req = 1; + if (p->type != PHYS_DIRECT) + goto reqreject; + if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) && + (op != CALLBACK_AUTH || p->link.lcp.auth_ineed) && + (op != CALLBACK_E164 || + E164ok(&p->dl->cfg.callback, cp + 3, sz))) { + lcp->his_callback.opmask = CALLBACK_BIT(op); + if (sz > sizeof lcp->his_callback.msg - 1) { + sz = sizeof lcp->his_callback.msg - 1; + log_Printf(LogWARN, "Truncating option arg to %d octets\n", sz); + } + memcpy(lcp->his_callback.msg, cp + 3, sz); + lcp->his_callback.msg[sz] = '\0'; + memcpy(dec->ackend, cp, sz + 3); + dec->ackend += sz + 3; + } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && + p->link.lcp.auth_ineed) { + *dec->nakend++ = *cp; + *dec->nakend++ = 3; + *dec->nakend++ = CALLBACK_AUTH; + } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { + *dec->nakend++ = *cp; + *dec->nakend++ = 3; + *dec->nakend++ = CALLBACK_CBCP; + } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { + *dec->nakend++ = *cp; + *dec->nakend++ = 3; + *dec->nakend++ = CALLBACK_E164; + } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { + log_Printf(LogWARN, "Cannot insist on auth callback without" + " PAP or CHAP enabled !\n"); + *dec->nakend++ = *cp; + *dec->nakend++ = 2; + } else + goto reqreject; + break; + case MODE_NAK: + /* We don't do what he NAKs want, we do things in our preferred order */ + if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) + lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH); + else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) + lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP); + else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) + lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164); + if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) { + log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n"); + lcp->want_callback.opmask = 0; + } else if (!lcp->want_callback.opmask) { + log_Printf(LogPHASE, "Peer NAKd last configured callback\n"); + fsm_Close(&lcp->fsm); + } + break; + case MODE_REJ: + if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { + lcp->his_reject |= (1 << type); + lcp->want_callback.opmask = 0; + } else { + log_Printf(LogPHASE, "Peer rejected *required* callback\n"); + fsm_Close(&lcp->fsm); + } + break; + } + break; + + case TY_SHORTSEQ: + mp = &lcp->fsm.bundle->ncp.mp; + log_Printf(LogLCP, "%s\n", request); + + switch (mode_type) { + case MODE_REQ: + if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) { + lcp->his_shortseq = 1; + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } else + goto reqreject; + break; + case MODE_NAK: + /* + * He's trying to get us to ask for short sequence numbers. + * We ignore the NAK and honour our configuration file instead. + */ + break; + case MODE_REJ: + lcp->his_reject |= (1 << type); + lcp->want_shortseq = 0; /* For when we hit MP */ + break; + } + break; + + case TY_ENDDISC: + log_Printf(LogLCP, "%s %s\n", request, + mp_Enddisc(cp[2], cp + 3, length - 3)); + switch (mode_type) { + case MODE_REQ: + if (!p) { + log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n"); + goto reqreject; + } else if (length-3 < sizeof p->dl->peer.enddisc.address && + cp[2] <= MAX_ENDDISC_CLASS) { + p->dl->peer.enddisc.class = cp[2]; + p->dl->peer.enddisc.len = length-3; + memcpy(p->dl->peer.enddisc.address, cp + 3, length - 3); + p->dl->peer.enddisc.address[length - 3] = '\0'; + /* XXX: If mp->active, compare and NAK with mp->peer ? */ + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } else { + if (cp[2] > MAX_ENDDISC_CLASS) + log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n", + cp[2]); + else + log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n", + (long)(sizeof p->dl->peer.enddisc.address - 1)); + goto reqreject; + } + break; + + case MODE_NAK: /* Treat this as a REJ, we don't vary or disc */ + case MODE_REJ: + lcp->his_reject |= (1 << type); + break; + } + break; + + default: + sz = (sizeof desc - 2) / 2; + if (sz > length - 2) + sz = length - 2; + pos = 0; + desc[0] = sz ? ' ' : '\0'; + for (pos = 0; sz--; pos++) + sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]); + + log_Printf(LogLCP, "%s%s\n", request, desc); + + if (mode_type == MODE_REQ) { +reqreject: + if (length > sizeof dec->rej - (dec->rejend - dec->rej)) { + length = sizeof dec->rej - (dec->rejend - dec->rej); + log_Printf(LogLCP, "Can't REJ length %d - trunating to %d\n", + cp[1], length); + } + memcpy(dec->rejend, cp, length); + dec->rejend += length; + lcp->my_reject |= (1 << type); + if (length != cp[1]) + length = 0; /* force our way out of the loop */ + } + break; + } + plen -= length; + cp += length; + } + + if (mode_type != MODE_NOP) { + if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT && + p->dl->cfg.callback.opmask && !callback_req && + !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) { + /* We *REQUIRE* that the peer requests callback */ + *dec->nakend++ = TY_CALLBACK; + *dec->nakend++ = 3; + if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && + p->link.lcp.auth_ineed) + *dec->nakend++ = CALLBACK_AUTH; + else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) + *dec->nakend++ = CALLBACK_CBCP; + else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) + *dec->nakend++ = CALLBACK_E164; + else { + log_Printf(LogWARN, "Cannot insist on auth callback without" + " PAP or CHAP enabled !\n"); + dec->nakend[-1] = 2; /* XXX: Silly ! */ + } + } + if (dec->rejend != dec->rej) { + /* rejects are preferred */ + dec->ackend = dec->ack; + dec->nakend = dec->nak; + } else if (dec->nakend != dec->nak) + /* then NAKs */ + dec->ackend = dec->ack; + } +} + +void +lcp_Input(struct lcp *lcp, struct mbuf * bp) +{ + /* Got PROTO_LCP from link */ + fsm_Input(&lcp->fsm, bp); +} diff --git a/usr.sbin/ppp/ppp/lcp.h b/usr.sbin/ppp/ppp/lcp.h new file mode 100644 index 00000000000..75aa506d162 --- /dev/null +++ b/usr.sbin/ppp/ppp/lcp.h @@ -0,0 +1,136 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lcp.h,v 1.1 1998/08/31 00:22:22 brian Exp $ + * + * TODO: + */ + +/* callback::opmask values */ +#define CALLBACK_AUTH (0) +#define CALLBACK_DIALSTRING (1) /* Don't do this */ +#define CALLBACK_LOCATION (2) /* Don't do this */ +#define CALLBACK_E164 (3) +#define CALLBACK_NAME (4) /* Don't do this */ +#define CALLBACK_CBCP (6) +#define CALLBACK_NONE (14) /* No callback is ok */ + +#define CALLBACK_BIT(n) ((n) < 0 ? 0 : 1 << (n)) + +struct callback { + int opmask; /* want these types of callback */ + char msg[SCRIPT_LEN]; /* with this data (E.164) */ +}; + +#define REJECTED(p, x) ((p)->his_reject & (1<<(x))) + +struct lcp { + struct fsm fsm; /* The finite state machine */ + u_int16_t his_mru; /* Peers maximum packet size */ + u_int16_t his_mrru; /* Peers maximum reassembled packet size (MP) */ + u_int32_t his_accmap; /* Peeers async char control map */ + u_int32_t his_magic; /* Peers magic number */ + u_int32_t his_lqrperiod; /* Peers LQR frequency (100ths of seconds) */ + u_short his_auth; /* Peer wants this type of authentication */ + struct callback his_callback; /* Peer wants callback ? */ + unsigned his_shortseq : 1; /* Peer would like only 12bit seqs (MP) */ + unsigned his_protocomp : 1; /* Does peer do Protocol field compression */ + unsigned his_acfcomp : 1; /* Does peer do addr & cntrl fld compression */ + + u_short want_mru; /* Our maximum packet size */ + u_short want_mrru; /* Our maximum reassembled packet size (MP) */ + u_int32_t want_accmap; /* Our async char control map */ + u_int32_t want_magic; /* Our magic number */ + u_int32_t want_lqrperiod; /* Our LQR frequency (100ths of seconds) */ + u_short want_auth; /* We want this type of authentication */ + struct callback want_callback;/* We want callback ? */ + unsigned want_shortseq : 1; /* I'd like only 12bit seqs (MP) */ + unsigned want_protocomp : 1; /* Do we do protocol field compression */ + unsigned want_acfcomp : 1; /* Do we do addr & cntrl fld compression */ + + u_int32_t his_reject; /* Request codes rejected by peer */ + u_int32_t my_reject; /* Request codes I have rejected */ + + u_short auth_iwait; /* I must authenticate to the peer */ + u_short auth_ineed; /* I require that the peer authenticates */ + + int LcpFailedMagic; /* Number of `magic is same' errors */ + + struct { + u_short mru; /* Preferred MRU value */ + u_int32_t accmap; /* Initial ACCMAP value */ + int openmode; /* when to start CFG REQs */ + u_int32_t lqrperiod; /* LQR frequency (seconds) */ + u_int fsmretry; /* FSM retry frequency */ + + unsigned acfcomp : 2; /* Address & Control Field Compression neg */ + unsigned chap : 2; /* Challenge Handshake Authentication proto */ + unsigned lqr : 2; /* Link Quality Report */ + unsigned pap : 2; /* Password Authentication protocol */ + unsigned protocomp : 2; /* Protocol field compression */ + } cfg; +}; + +#define LCP_MAXCODE CODE_DISCREQ +#define LCP_MINMPCODE CODE_CODEREJ + +#define TY_MRU 1 /* Maximum-Receive-Unit */ +#define TY_ACCMAP 2 /* Async-Control-Character-Map */ +#define TY_AUTHPROTO 3 /* Authentication-Protocol */ +#define TY_QUALPROTO 4 /* Quality-Protocol */ +#define TY_MAGICNUM 5 /* Magic-Number */ +#define TY_RESERVED 6 /* RESERVED */ +#define TY_PROTOCOMP 7 /* Protocol-Field-Compression */ +#define TY_ACFCOMP 8 /* Address-and-Control-Field-Compression */ +#define TY_FCSALT 9 /* FCS-Alternatives */ +#define TY_SDP 10 /* Self-Describing-Padding */ +#define TY_CALLBACK 13 /* Callback */ +#define TY_CFRAMES 15 /* Compound-frames */ +#define TY_MRRU 17 /* Max Reconstructed Receive Unit (MP) */ +#define TY_SHORTSEQ 18 /* Want short seqs (12bit) please (see mp.h) */ +#define TY_ENDDISC 19 /* Endpoint discriminator */ + +#define MAX_LCP_OPT_LEN 20 +struct lcp_opt { + u_char id; + u_char len; + u_char data[MAX_LCP_OPT_LEN-2]; +}; + +#define INC_LCP_OPT(ty, length, o) \ + do { \ + (o)->id = (ty); \ + (o)->len = (length); \ + (o) = (struct lcp_opt *)((char *)(o) + (length)); \ + } while (0) + +struct mbuf; +struct link; +struct physical; +struct bundle; +struct cmdargs; + +#define fsm2lcp(fp) (fp->proto == PROTO_LCP ? (struct lcp *)fp : NULL) + +extern void lcp_Init(struct lcp *, struct bundle *, struct link *, + const struct fsm_parent *); +extern void lcp_Setup(struct lcp *, int); + +extern void lcp_SendProtoRej(struct lcp *, u_char *, int); +extern int lcp_ReportStatus(struct cmdargs const *); +extern void lcp_Input(struct lcp *, struct mbuf *); +extern void lcp_SetupCallbacks(struct lcp *); diff --git a/usr.sbin/ppp/lcpproto.h b/usr.sbin/ppp/ppp/lcpproto.h index dadb2311e2b..cc523f6f2a6 100644 --- a/usr.sbin/ppp/lcpproto.h +++ b/usr.sbin/ppp/ppp/lcpproto.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: lcpproto.h,v 1.1 1997/11/23 20:27:34 brian Exp $ + * $Id: lcpproto.h,v 1.1 1998/08/31 00:22:23 brian Exp $ * * TODO: */ @@ -26,14 +26,18 @@ #define PROTO_IP 0x0021 /* IP */ #define PROTO_VJUNCOMP 0x002f /* VJ Uncompressed */ #define PROTO_VJCOMP 0x002d /* VJ Compressed */ +#define PROTO_MP 0x003d /* Multilink fragment */ #define PROTO_ICOMPD 0x00fb /* Individual link compressed */ #define PROTO_COMPD 0x00fd /* Compressed datagram */ +#define PROTO_COMPRESSIBLE(p) (((p) & 0xffe1) == 0x21) + #define PROTO_IPCP 0x8021 #define PROTO_ICCP 0x80fb #define PROTO_CCP 0x80fd #define PROTO_LCP 0xc021 #define PROTO_PAP 0xc023 +#define PROTO_CBCP 0xc029 #define PROTO_LQR 0xc025 #define PROTO_CHAP 0xc223 diff --git a/usr.sbin/ppp/ppp/link.c b/usr.sbin/ppp/ppp/link.c new file mode 100644 index 00000000000..6866d4e6a94 --- /dev/null +++ b/usr.sbin/ppp/ppp/link.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: link.c,v 1.1 1998/08/31 00:22:23 brian Exp $ + * + */ + +#include <sys/types.h> + +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "lqr.h" +#include "hdlc.h" +#include "throughput.h" +#include "lcpproto.h" +#include "fsm.h" +#include "descriptor.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "prompt.h" + +void +link_AddInOctets(struct link *l, int n) +{ + throughput_addin(&l->throughput, n); +} + +void +link_AddOutOctets(struct link *l, int n) +{ + throughput_addout(&l->throughput, n); +} + +void +link_SequenceQueue(struct link *l) +{ + log_Printf(LogDEBUG, "link_SequenceQueue\n"); + while (l->Queue[PRI_NORMAL].qlen) + mbuf_Enqueue(l->Queue + PRI_LINK, mbuf_Dequeue(l->Queue + PRI_NORMAL)); +} + +void +link_DeleteQueue(struct link *l) +{ + struct mqueue *queue; + + for (queue = l->Queue; queue < l->Queue + LINK_QUEUES; queue++) + while (queue->top) + mbuf_Free(mbuf_Dequeue(queue)); +} + +int +link_QueueLen(struct link *l) +{ + int i, len; + + for (i = 0, len = 0; i < LINK_QUEUES; i++) + len += l->Queue[i].qlen; + + return len; +} + +int +link_QueueBytes(struct link *l) +{ + int i, len, bytes; + struct mbuf *m; + + bytes = 0; + for (i = 0, len = 0; i < LINK_QUEUES; i++) { + len = l->Queue[i].qlen; + m = l->Queue[i].top; + while (len--) { + bytes += mbuf_Length(m); + m = m->pnext; + } + } + + return bytes; +} + +struct mbuf * +link_Dequeue(struct link *l) +{ + int pri; + struct mbuf *bp; + + for (bp = (struct mbuf *)0, pri = LINK_QUEUES - 1; pri >= 0; pri--) + if (l->Queue[pri].qlen) { + bp = mbuf_Dequeue(l->Queue + pri); + log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d," + " containing %d more packets\n", pri, l->Queue[pri].qlen); + break; + } + + return bp; +} + +/* + * Write to the link. Actualy, requested packets are queued, and go out + * at some later time depending on the physical link implementation. + */ +void +link_Write(struct link *l, int pri, const char *ptr, int count) +{ + struct mbuf *bp; + + if(pri < 0 || pri >= LINK_QUEUES) + pri = 0; + + bp = mbuf_Alloc(count, MB_LINK); + memcpy(MBUF_CTOP(bp), ptr, count); + + mbuf_Enqueue(l->Queue + pri, bp); +} + +void +link_Output(struct link *l, int pri, struct mbuf *bp) +{ + struct mbuf *wp; + int len; + + if(pri < 0 || pri >= LINK_QUEUES) + pri = 0; + + len = mbuf_Length(bp); + wp = mbuf_Alloc(len, MB_LINK); + mbuf_Read(bp, MBUF_CTOP(wp), len); + mbuf_Enqueue(l->Queue + pri, wp); +} + +static struct protostatheader { + u_short number; + const char *name; +} ProtocolStat[NPROTOSTAT] = { + { PROTO_IP, "IP" }, + { PROTO_VJUNCOMP, "VJ_UNCOMP" }, + { PROTO_VJCOMP, "VJ_COMP" }, + { PROTO_COMPD, "COMPD" }, + { PROTO_ICOMPD, "ICOMPD" }, + { PROTO_LCP, "LCP" }, + { PROTO_IPCP, "IPCP" }, + { PROTO_CCP, "CCP" }, + { PROTO_PAP, "PAP" }, + { PROTO_LQR, "LQR" }, + { PROTO_CHAP, "CHAP" }, + { PROTO_MP, "MULTILINK" }, + { 0, "Others" } +}; + +void +link_ProtocolRecord(struct link *l, u_short proto, int type) +{ + int i; + + for (i = 0; i < NPROTOSTAT; i++) + if (ProtocolStat[i].number == proto) + break; + + if (type == PROTO_IN) + l->proto_in[i]++; + else + l->proto_out[i]++; +} + +void +link_ReportProtocolStatus(struct link *l, struct prompt *prompt) +{ + int i; + + prompt_Printf(prompt, " Protocol in out " + "Protocol in out\n"); + for (i = 0; i < NPROTOSTAT; i++) { + prompt_Printf(prompt, " %-9s: %8lu, %8lu", + ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]); + if ((i % 2) == 0) + prompt_Printf(prompt, "\n"); + } + if (!(i % 2)) + prompt_Printf(prompt, "\n"); +} diff --git a/usr.sbin/ppp/ppp/link.h b/usr.sbin/ppp/ppp/link.h new file mode 100644 index 00000000000..87a5402d2c2 --- /dev/null +++ b/usr.sbin/ppp/ppp/link.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: link.h,v 1.1 1998/08/31 00:22:23 brian Exp $ + * + */ + + +#define PHYSICAL_LINK 1 +#define MP_LINK 2 + +#define LINK_QUEUES (PRI_MAX + 1) +#define NPROTOSTAT 13 + +struct bundle; +struct prompt; + +struct link { + int type; /* _LINK type */ + const char *name; /* Points to datalink::name */ + int len; /* full size of parent struct */ + struct pppThroughput throughput; /* Link throughput statistics */ + struct mqueue Queue[LINK_QUEUES]; /* Our output queue of mbufs */ + + u_long proto_in[NPROTOSTAT]; /* outgoing protocol stats */ + u_long proto_out[NPROTOSTAT]; /* incoming protocol stats */ + + struct lcp lcp; /* Our line control FSM */ + struct ccp ccp; /* Our compression FSM */ +}; + +extern void link_AddInOctets(struct link *, int); +extern void link_AddOutOctets(struct link *, int); + +extern void link_SequenceQueue(struct link *); +extern void link_DeleteQueue(struct link *); +extern int link_QueueLen(struct link *); +extern int link_QueueBytes(struct link *); +extern struct mbuf *link_Dequeue(struct link *); +extern void link_Write(struct link *, int, const char *, int); +extern void link_StartOutput(struct link *, struct bundle *); +extern void link_Output(struct link *, int, struct mbuf *); + +#define PROTO_IN 1 /* third arg to link_ProtocolRecord */ +#define PROTO_OUT 2 +extern void link_ProtocolRecord(struct link *, u_short, int); +extern void link_ReportProtocolStatus(struct link *, struct prompt *); diff --git a/usr.sbin/ppp/ppp/log.c b/usr.sbin/ppp/ppp/log.c new file mode 100644 index 00000000000..82c6f33e96a --- /dev/null +++ b/usr.sbin/ppp/ppp/log.c @@ -0,0 +1,467 @@ +/*- + * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: log.c,v 1.1 1998/08/31 00:22:23 brian Exp $ + */ + +#include <sys/types.h> + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "descriptor.h" +#include "prompt.h" + +static const char *LogNames[] = { + "Async", + "CBCP", + "CCP", + "Chat", + "Command", + "Connect", + "Debug", + "HDLC", + "ID0", + "IPCP", + "LCP", + "LQM", + "Phase", + "TCP/IP", + "Timer", + "Tun", + "Warning", + "Error", + "Alert" +}; + +#define MSK(n) (1<<((n)-1)) + +static u_long LogMask = MSK(LogPHASE); +static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); +static int LogTunno = -1; +static struct prompt *promptlist; /* Where to log local stuff */ +int log_PromptListChanged; + +struct prompt * +log_PromptList() +{ + return promptlist; +} + +void +log_RegisterPrompt(struct prompt *prompt) +{ + prompt->next = promptlist; + promptlist = prompt; + prompt->active = 1; + log_DiscardAllLocal(&prompt->logmask); +} + +void +log_ActivatePrompt(struct prompt *prompt) +{ + prompt->active = 1; + LogMaskLocal |= prompt->logmask; +} + +static void +LogSetMaskLocal(void) +{ + struct prompt *p; + + LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); + for (p = promptlist; p; p = p->next) + LogMaskLocal |= p->logmask; +} + +void +log_DeactivatePrompt(struct prompt *prompt) +{ + if (prompt->active) { + prompt->active = 0; + LogSetMaskLocal(); + } +} + +void +log_UnRegisterPrompt(struct prompt *prompt) +{ + if (prompt) { + struct prompt **p; + + for (p = &promptlist; *p; p = &(*p)->next) + if (*p == prompt) { + *p = prompt->next; + prompt->next = NULL; + break; + } + LogSetMaskLocal(); + log_PromptListChanged++; + } +} + +void +log_DestroyPrompts(struct server *s) +{ + struct prompt *p, *pn; + + p = promptlist; + while (p) { + pn = p->next; + if (s && p->owner != s) { + p->next = NULL; + prompt_Destroy(p, 1); + } + p = pn; + } +} + +void +log_DisplayPrompts() +{ + struct prompt *p; + + for (p = promptlist; p; p = p->next) + prompt_Required(p); +} + +void +log_WritePrompts(struct datalink *dl, const char *fmt,...) +{ + va_list ap; + struct prompt *p; + + va_start(ap, fmt); + for (p = promptlist; p; p = p->next) + if (prompt_IsTermMode(p, dl)) + prompt_vPrintf(p, fmt, ap); + va_end(ap); +} + +void +log_SetTtyCommandMode(struct datalink *dl) +{ + struct prompt *p; + + for (p = promptlist; p; p = p->next) + if (prompt_IsTermMode(p, dl)) + prompt_TtyCommandMode(p); +} + +static int +syslogLevel(int lev) +{ + switch (lev) { + case LogDEBUG: + case LogTIMER: + return LOG_DEBUG; + case LogWARN: + return LOG_WARNING; + case LogERROR: + return LOG_ERR; + case LogALERT: + return LOG_ALERT; + } + return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0; +} + +const char * +log_Name(int id) +{ + return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1]; +} + +void +log_Keep(int id) +{ + if (id >= LogMIN && id <= LogMAXCONF) + LogMask |= MSK(id); +} + +void +log_KeepLocal(int id, u_long *mask) +{ + if (id >= LogMIN && id <= LogMAXCONF) { + LogMaskLocal |= MSK(id); + *mask |= MSK(id); + } +} + +void +log_Discard(int id) +{ + if (id >= LogMIN && id <= LogMAXCONF) + LogMask &= ~MSK(id); +} + +void +log_DiscardLocal(int id, u_long *mask) +{ + if (id >= LogMIN && id <= LogMAXCONF) { + *mask &= ~MSK(id); + LogSetMaskLocal(); + } +} + +void +log_DiscardAll() +{ + LogMask = 0; +} + +void +log_DiscardAllLocal(u_long *mask) +{ + *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); + LogSetMaskLocal(); +} + +int +log_IsKept(int id) +{ + if (id < LogMIN || id > LogMAX) + return 0; + if (id > LogMAXCONF) + return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG; + + return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) | + ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0); +} + +int +log_IsKeptLocal(int id, u_long mask) +{ + if (id < LogMIN || id > LogMAX) + return 0; + if (id > LogMAXCONF) + return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG; + + return ((mask & MSK(id)) ? LOG_KEPT_LOCAL : 0) | + ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0); +} + +void +log_Open(const char *Name) +{ + openlog(Name, LOG_PID, LOG_DAEMON); +} + +void +log_SetTun(int tunno) +{ + LogTunno = tunno; +} + +void +log_Close() +{ + closelog(); + LogTunno = -1; +} + +void +log_Printf(int lev, const char *fmt,...) +{ + va_list ap; + struct prompt *prompt; + + va_start(ap, fmt); + if (log_IsKept(lev)) { + char nfmt[200]; + + if ((log_IsKept(lev) & LOG_KEPT_LOCAL) && promptlist) { + if ((log_IsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1) + snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME, + LogTunno, log_Name(lev), fmt); + else + snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt); + + for (prompt = promptlist; prompt; prompt = prompt->next) + if (lev > LogMAXCONF || (prompt->logmask & MSK(lev))) + prompt_vPrintf(prompt, nfmt, ap); + } + + if ((log_IsKept(lev) & LOG_KEPT_SYSLOG) && + (lev != LogWARN || !promptlist)) { + if ((log_IsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1) + snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME, + LogTunno, log_Name(lev), fmt); + else + snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt); + vsyslog(syslogLevel(lev), nfmt, ap); + } + } + va_end(ap); +} + +void +log_DumpBp(int lev, const char *hdr, const struct mbuf *bp) +{ + if (log_IsKept(lev)) { + char buf[50]; + char *b; + const u_char *ptr; + int f; + + if (hdr && *hdr) + log_Printf(lev, "%s\n", hdr); + + b = buf; + do { + f = bp->cnt; + ptr = CONST_MBUF_CTOP(bp); + while (f--) { + sprintf(b, " %02x", (int) *ptr++); + b += 3; + if (b == buf + sizeof buf - 2) { + strcpy(b, "\n"); + log_Printf(lev, buf); + b = buf; + } + } + } while ((bp = bp->next) != NULL); + + if (b > buf) { + strcpy(b, "\n"); + log_Printf(lev, buf); + } + } +} + +void +log_DumpBuff(int lev, const char *hdr, const u_char * ptr, int n) +{ + if (log_IsKept(lev)) { + char buf[50]; + char *b; + + if (hdr && *hdr) + log_Printf(lev, "%s\n", hdr); + while (n > 0) { + b = buf; + for (b = buf; b != buf + sizeof buf - 2 && n--; b += 3) + sprintf(b, " %02x", (int) *ptr++); + strcpy(b, "\n"); + log_Printf(lev, buf); + } + } +} + +int +log_ShowLevel(struct cmdargs const *arg) +{ + int i; + + prompt_Printf(arg->prompt, "Log: "); + for (i = LogMIN; i <= LogMAX; i++) + if (log_IsKept(i) & LOG_KEPT_SYSLOG) + prompt_Printf(arg->prompt, " %s", log_Name(i)); + + prompt_Printf(arg->prompt, "\nLocal:"); + for (i = LogMIN; i <= LogMAX; i++) + if (log_IsKeptLocal(i, arg->prompt->logmask) & LOG_KEPT_LOCAL) + prompt_Printf(arg->prompt, " %s", log_Name(i)); + + prompt_Printf(arg->prompt, "\n"); + + return 0; +} + +int +log_SetLevel(struct cmdargs const *arg) +{ + int i, res, argc, local; + char const *const *argv, *argp; + + argc = arg->argc - arg->argn; + argv = arg->argv + arg->argn; + res = 0; + + if (argc == 0 || strcasecmp(argv[0], "local")) + local = 0; + else { + if (arg->prompt == NULL) { + log_Printf(LogWARN, "set log local: Only available on the command line\n"); + return 1; + } + argc--; + argv++; + local = 1; + } + + if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) { + if (local) + log_DiscardAllLocal(&arg->prompt->logmask); + else + log_DiscardAll(); + } + + while (argc--) { + argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv; + for (i = LogMIN; i <= LogMAX; i++) + if (strcasecmp(argp, log_Name(i)) == 0) { + if (**argv == '-') { + if (local) + log_DiscardLocal(i, &arg->prompt->logmask); + else + log_Discard(i); + } else if (local) + log_KeepLocal(i, &arg->prompt->logmask); + else + log_Keep(i); + break; + } + if (i > LogMAX) { + log_Printf(LogWARN, "%s: Invalid log value\n", argp); + res = -1; + } + argv++; + } + return res; +} + +int +log_ShowWho(struct cmdargs const *arg) +{ + struct prompt *p; + + for (p = promptlist; p; p = p->next) { + prompt_Printf(arg->prompt, "%s (%s)", p->src.type, p->src.from); + if (p == arg->prompt) + prompt_Printf(arg->prompt, " *"); + if (!p->active) + prompt_Printf(arg->prompt, " ^Z"); + prompt_Printf(arg->prompt, "\n"); + } + + return 0; +} diff --git a/usr.sbin/ppp/log.h b/usr.sbin/ppp/ppp/log.h index 7efc57341db..b399ca16ff7 100644 --- a/usr.sbin/ppp/log.h +++ b/usr.sbin/ppp/ppp/log.h @@ -23,12 +23,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: log.h,v 1.2 1997/12/21 14:27:09 brian Exp $ + * $Id: log.h,v 1.1 1998/08/31 00:22:23 brian Exp $ */ #define LogMIN (1) #define LogASYNC (1) /* syslog(LOG_INFO, ....) */ -#define LogCARRIER (2) +#define LogCBCP (2) #define LogCCP (3) #define LogCHAT (4) #define LogCOMMAND (5) @@ -38,10 +38,10 @@ #define LogID0 (9) #define LogIPCP (10) #define LogLCP (11) -#define LogLINK (12) -#define LogLQM (13) -#define LogPHASE (14) -#define LogTCPIP (15) +#define LogLQM (12) +#define LogPHASE (13) +#define LogTCPIP (14) +#define LogTIMER (15) /* syslog(LOG_DEBUG, ....) */ #define LogTUN (16) /* If set, tun%d is output with each message */ #define LogMAXCONF (16) #define LogWARN (17) /* Sent to VarTerm else syslog(LOG_WARNING, ) */ @@ -49,20 +49,48 @@ #define LogALERT (19) /* syslog(LOG_ALERT, ....) */ #define LogMAX (19) +struct mbuf; +struct cmdargs; +struct prompt; +struct server; +struct datalink; + /* The first int arg for all of the following is one of the above values */ -extern const char *LogName(int); -extern void LogKeep(int); -extern void LogKeepLocal(int); -extern void LogDiscard(int); -extern void LogDiscardLocal(int); -extern void LogDiscardAll(void); -extern void LogDiscardAllLocal(void); -#define LOG_KEPT_SYSLOG (1) /* Results of LogIsKept() */ -#define LOG_KEPT_LOCAL (2) /* Results of LogIsKept() */ -extern int LogIsKept(int); -extern void LogOpen(const char *); -extern void LogSetTun(int); -extern void LogClose(void); -extern void LogPrintf(int, const char *,...); -extern void LogDumpBp(int, const char *, const struct mbuf *); -extern void LogDumpBuff(int, const char *, const u_char *, int); +extern const char *log_Name(int); +extern void log_Keep(int); +extern void log_KeepLocal(int, u_long *); +extern void log_Discard(int); +extern void log_DiscardLocal(int, u_long *); +extern void log_DiscardAll(void); +extern void log_DiscardAllLocal(u_long *); +#define LOG_KEPT_SYSLOG (1) /* Results of log_IsKept() */ +#define LOG_KEPT_LOCAL (2) /* Results of log_IsKept() */ +extern int log_IsKept(int); +extern int log_IsKeptLocal(int, u_long); +extern void log_Open(const char *); +extern void log_SetTun(int); +extern void log_Close(void); +#ifdef __GNUC__ +extern void log_Printf(int, const char *,...) + __attribute__ ((format (printf, 2, 3))); +extern void log_WritePrompts(struct datalink *, const char *, ...) + __attribute__ ((format (printf, 2, 3))); +#else +extern void log_Printf(int, const char *,...); +extern void log_WritePrompts(struct datalink *, const char *, ...); +#endif +extern void log_DumpBp(int, const char *, const struct mbuf *); +extern void log_DumpBuff(int, const char *, const u_char *, int); +extern int log_ShowLevel(struct cmdargs const *); +extern int log_SetLevel(struct cmdargs const *); +extern int log_ShowWho(struct cmdargs const *); + +extern int log_PromptListChanged; +extern void log_RegisterPrompt(struct prompt *); +extern void log_UnRegisterPrompt(struct prompt *); +extern void log_DestroyPrompts(struct server *); +extern void log_DisplayPrompts(void); +extern void log_ActivatePrompt(struct prompt *); +extern void log_DeactivatePrompt(struct prompt *); +extern void log_SetTtyCommandMode(struct datalink *); +extern struct prompt *log_PromptList(void); diff --git a/usr.sbin/ppp/ppp/lqr.c b/usr.sbin/ppp/ppp/lqr.c new file mode 100644 index 00000000000..690d75d193e --- /dev/null +++ b/usr.sbin/ppp/ppp/lqr.c @@ -0,0 +1,320 @@ +/* + * PPP Line Quality Monitoring (LQM) Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lqr.c,v 1.1 1998/08/31 00:22:23 brian Exp $ + * + * o LQR based on RFC1333 + * + * TODO: + * o LQM policy + * o Allow user to configure LQM method and interval. + */ + +#include <sys/types.h> +#include <sys/un.h> + +#include <string.h> +#include <termios.h> + +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "lcpproto.h" +#include "lcp.h" +#include "lqr.h" +#include "hdlc.h" +#include "async.h" +#include "throughput.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "mp.h" +#include "chat.h" +#include "auth.h" +#include "chap.h" +#include "command.h" +#include "cbcp.h" +#include "datalink.h" + +struct echolqr { + u_int32_t magic; + u_int32_t signature; + u_int32_t sequence; +}; + +#define SIGNATURE 0x594e4f54 + +static void +SendEchoReq(struct lcp *lcp) +{ + struct hdlc *hdlc = &link2physical(lcp->fsm.link)->hdlc; + struct echolqr echo; + + echo.magic = htonl(lcp->want_magic); + echo.signature = htonl(SIGNATURE); + echo.sequence = htonl(hdlc->lqm.echo.seq_sent); + fsm_Output(&lcp->fsm, CODE_ECHOREQ, hdlc->lqm.echo.seq_sent++, + (u_char *)&echo, sizeof echo); +} + +void +lqr_RecvEcho(struct fsm *fp, struct mbuf * bp) +{ + struct hdlc *hdlc = &link2physical(fp->link)->hdlc; + struct echolqr *lqr; + u_int32_t seq; + + if (mbuf_Length(bp) == sizeof(struct echolqr)) { + lqr = (struct echolqr *) MBUF_CTOP(bp); + if (ntohl(lqr->signature) == SIGNATURE) { + seq = ntohl(lqr->sequence); + /* careful not to update lqm.echo.seq_recv with older values */ + if ((hdlc->lqm.echo.seq_recv > (u_int32_t)0 - 5 && seq < 5) || + (hdlc->lqm.echo.seq_recv <= (u_int32_t)0 - 5 && + seq > hdlc->lqm.echo.seq_recv)) + hdlc->lqm.echo.seq_recv = seq; + } else + log_Printf(LogWARN, "lqr_RecvEcho: Got sig 0x%08lx, not 0x%08lx !\n", + (u_long)ntohl(lqr->signature), (u_long)SIGNATURE); + } else + log_Printf(LogWARN, "lqr_RecvEcho: Got packet size %d, expecting %ld !\n", + mbuf_Length(bp), (long)sizeof(struct echolqr)); +} + +void +lqr_ChangeOrder(struct lqrdata * src, struct lqrdata * dst) +{ + u_int32_t *sp, *dp; + int n; + + sp = (u_int32_t *) src; + dp = (u_int32_t *) dst; + for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_int32_t); n++) + *dp++ = ntohl(*sp++); +} + +static void +SendLqrData(struct lcp *lcp) +{ + struct mbuf *bp; + + bp = mbuf_Alloc(sizeof(struct lqrdata), MB_LQR); + hdlc_Output(lcp->fsm.link, PRI_LINK, PROTO_LQR, bp); +} + +static void +SendLqrReport(void *v) +{ + struct lcp *lcp = (struct lcp *)v; + struct physical *p = link2physical(lcp->fsm.link); + + timer_Stop(&p->hdlc.lqm.timer); + + if (p->hdlc.lqm.method & LQM_LQR) { + if (p->hdlc.lqm.lqr.resent > 5) { + /* XXX: Should implement LQM strategy */ + log_Printf(LogPHASE, "%s: ** Too many LQR packets lost **\n", + lcp->fsm.link->name); + log_Printf(LogLQM, "%s: Too many LQR packets lost\n", + lcp->fsm.link->name); + p->hdlc.lqm.method = 0; + datalink_Down(p->dl, CLOSE_NORMAL); + } else { + SendLqrData(lcp); + p->hdlc.lqm.lqr.resent++; + } + } else if (p->hdlc.lqm.method & LQM_ECHO) { + if ((p->hdlc.lqm.echo.seq_sent > 5 && + p->hdlc.lqm.echo.seq_sent - 5 > p->hdlc.lqm.echo.seq_recv) || + (p->hdlc.lqm.echo.seq_sent <= 5 && + p->hdlc.lqm.echo.seq_sent > p->hdlc.lqm.echo.seq_recv + 5)) { + log_Printf(LogPHASE, "%s: ** Too many ECHO LQR packets lost **\n", + lcp->fsm.link->name); + log_Printf(LogLQM, "%s: Too many ECHO LQR packets lost\n", + lcp->fsm.link->name); + p->hdlc.lqm.method = 0; + datalink_Down(p->dl, CLOSE_NORMAL); + } else + SendEchoReq(lcp); + } + if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) + timer_Start(&p->hdlc.lqm.timer); +} + +void +lqr_Input(struct physical *physical, struct mbuf *bp) +{ + int len; + + len = mbuf_Length(bp); + if (len != sizeof(struct lqrdata)) + log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n", + len, (long)sizeof(struct lqrdata)); + else if (!IsAccepted(physical->link.lcp.cfg.lqr) && + !(physical->hdlc.lqm.method & LQM_LQR)) { + bp->offset -= 2; + bp->cnt += 2; + lcp_SendProtoRej(physical->hdlc.lqm.owner, MBUF_CTOP(bp), bp->cnt); + } else { + struct lqrdata *lqr; + struct lcp *lcp; + u_int32_t lastLQR; + + lqr = (struct lqrdata *)MBUF_CTOP(bp); + lcp = physical->hdlc.lqm.owner; + if (ntohl(lqr->MagicNumber) != physical->hdlc.lqm.owner->his_magic) + log_Printf(LogWARN, "lqr_Input: magic 0x%08lx is wrong," + " expecting 0x%08lx\n", + (u_long)ntohl(lqr->MagicNumber), + (u_long)physical->hdlc.lqm.owner->his_magic); + else { + /* + * Remember our PeerInLQRs, then convert byte order and save + */ + lastLQR = physical->hdlc.lqm.lqr.peer.PeerInLQRs; + + lqr_ChangeOrder(lqr, &physical->hdlc.lqm.lqr.peer); + lqr_Dump(physical->link.name, "Input", &physical->hdlc.lqm.lqr.peer); + /* we have received an LQR from peer */ + physical->hdlc.lqm.lqr.resent = 0; + + /* + * Generate an LQR response if we're not running an LQR timer OR + * two successive LQR's PeerInLQRs are the same OR we're not going to + * send our next one before the peers max timeout. + */ + if (physical->hdlc.lqm.timer.load == 0 || + !(physical->hdlc.lqm.method & LQM_LQR) || + (lastLQR && lastLQR == physical->hdlc.lqm.lqr.peer.PeerInLQRs) || + (physical->hdlc.lqm.lqr.peer_timeout && + physical->hdlc.lqm.timer.rest * 100 / SECTICKS > + physical->hdlc.lqm.lqr.peer_timeout)) + SendLqrData(physical->hdlc.lqm.owner); + } + } + mbuf_Free(bp); +} + +/* + * When LCP is reached to opened state, We'll start LQM activity. + */ + +static void +lqr_Setup(struct lcp *lcp) +{ + struct physical *physical = link2physical(lcp->fsm.link); + + physical->hdlc.lqm.lqr.resent = 0; + physical->hdlc.lqm.echo.seq_sent = 0; + physical->hdlc.lqm.echo.seq_recv = 0; + memset(&physical->hdlc.lqm.lqr.peer, '\0', + sizeof physical->hdlc.lqm.lqr.peer); + + physical->hdlc.lqm.method = LQM_ECHO; + if (IsEnabled(lcp->cfg.lqr) && !REJECTED(lcp, TY_QUALPROTO)) + physical->hdlc.lqm.method |= LQM_LQR; + timer_Stop(&physical->hdlc.lqm.timer); + + physical->hdlc.lqm.lqr.peer_timeout = lcp->his_lqrperiod; + if (lcp->his_lqrperiod) + log_Printf(LogLQM, "%s: Expecting LQR every %d.%02d secs\n", + physical->link.name, lcp->his_lqrperiod / 100, + lcp->his_lqrperiod % 100); + + if (lcp->want_lqrperiod) { + log_Printf(LogLQM, "%s: Will send %s every %d.%02d secs\n", + physical->link.name, + physical->hdlc.lqm.method & LQM_LQR ? "LQR" : "ECHO LQR", + lcp->want_lqrperiod / 100, lcp->want_lqrperiod % 100); + physical->hdlc.lqm.timer.load = lcp->want_lqrperiod * SECTICKS / 100; + physical->hdlc.lqm.timer.func = SendLqrReport; + physical->hdlc.lqm.timer.name = "lqm"; + physical->hdlc.lqm.timer.arg = lcp; + } else { + physical->hdlc.lqm.timer.load = 0; + if (!lcp->his_lqrperiod) + log_Printf(LogLQM, "%s: LQR/ECHO LQR not negotiated\n", + physical->link.name); + } +} + +void +lqr_Start(struct lcp *lcp) +{ + struct physical *p = link2physical(lcp->fsm.link); + + lqr_Setup(lcp); + if (p->hdlc.lqm.timer.load) + SendLqrReport(lcp); +} + +void +lqr_reStart(struct lcp *lcp) +{ + struct physical *p = link2physical(lcp->fsm.link); + + lqr_Setup(lcp); + if (p->hdlc.lqm.timer.load) + timer_Start(&p->hdlc.lqm.timer); +} + +void +lqr_StopTimer(struct physical *physical) +{ + timer_Stop(&physical->hdlc.lqm.timer); +} + +void +lqr_Stop(struct physical *physical, int method) +{ + if (method == LQM_LQR) + log_Printf(LogLQM, "%s: Stop sending LQR, Use LCP ECHO instead.\n", + physical->link.name); + if (method == LQM_ECHO) + log_Printf(LogLQM, "%s: Stop sending LCP ECHO.\n", + physical->link.name); + physical->hdlc.lqm.method &= ~method; + if (physical->hdlc.lqm.method) + SendLqrReport(physical->hdlc.lqm.owner); + else + timer_Stop(&physical->hdlc.lqm.timer); +} + +void +lqr_Dump(const char *link, const char *message, const struct lqrdata *lqr) +{ + if (log_IsKept(LogLQM)) { + log_Printf(LogLQM, "%s: %s:\n", link, message); + log_Printf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", + lqr->MagicNumber, lqr->LastOutLQRs); + log_Printf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", + lqr->LastOutPackets, lqr->LastOutOctets); + log_Printf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", + lqr->PeerInLQRs, lqr->PeerInPackets); + log_Printf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", + lqr->PeerInDiscards, lqr->PeerInErrors); + log_Printf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", + lqr->PeerInOctets, lqr->PeerOutLQRs); + log_Printf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", + lqr->PeerOutPackets, lqr->PeerOutOctets); + } +} diff --git a/usr.sbin/ppp/ppp/lqr.h b/usr.sbin/ppp/ppp/lqr.h new file mode 100644 index 00000000000..d5de2074c8d --- /dev/null +++ b/usr.sbin/ppp/ppp/lqr.h @@ -0,0 +1,59 @@ +/* + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lqr.h,v 1.1 1998/08/31 00:22:23 brian Exp $ + * + * TODO: + */ + +/* + * Structure of LQR packet defined in RFC1989 + */ +struct lqrdata { + u_int32_t MagicNumber; + u_int32_t LastOutLQRs; /* most recently received PeerOutLQRs */ + u_int32_t LastOutPackets; /* most recently received PeerOutPackets */ + u_int32_t LastOutOctets; /* most recently received PeerOutOctets */ + u_int32_t PeerInLQRs; /* Peers SaveInLQRs */ + u_int32_t PeerInPackets; /* Peers SaveInPackets */ + u_int32_t PeerInDiscards; /* Peers SaveInDiscards */ + u_int32_t PeerInErrors; /* Peers SaveInErrors */ + u_int32_t PeerInOctets; /* Peers SaveInOctets */ + u_int32_t PeerOutLQRs; /* Peers OutLQRs (hdlc.h) */ + u_int32_t PeerOutPackets; /* Peers OutPackets (hdlc.h) */ + u_int32_t PeerOutOctets; /* Peers OutOctets (hdlc.h) */ +}; + +/* + * We support LQR and ECHO as LQM method + */ +#define LQM_LQR 1 +#define LQM_ECHO 2 + +struct mbuf; +struct physical; +struct lcp; +struct fsm; + +extern void lqr_Dump(const char *, const char *, const struct lqrdata *); +extern void lqr_ChangeOrder(struct lqrdata *, struct lqrdata *); +extern void lqr_Start(struct lcp *); +extern void lqr_reStart(struct lcp *); +extern void lqr_Stop(struct physical *, int); +extern void lqr_StopTimer(struct physical *); +extern void lqr_RecvEcho(struct fsm *, struct mbuf *); +extern void lqr_Input(struct physical *, struct mbuf *); diff --git a/usr.sbin/ppp/ppp/main.c b/usr.sbin/ppp/ppp/main.c new file mode 100644 index 00000000000..1ba84b71c67 --- /dev/null +++ b/usr.sbin/ppp/ppp/main.c @@ -0,0 +1,555 @@ +/* + * User Process PPP + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: main.c,v 1.1 1998/08/31 00:22:24 brian Exp $ + * + * TODO: + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#ifndef NOALIAS +#include <alias.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <termios.h> +#include <unistd.h> + +#include "probe.h" +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "id.h" +#include "timer.h" +#include "fsm.h" +#include "lqr.h" +#include "hdlc.h" +#include "lcp.h" +#include "ccp.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" +#include "auth.h" +#include "systems.h" +#include "sig.h" +#include "main.h" +#include "server.h" +#include "prompt.h" +#include "chat.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" + +#ifndef O_NONBLOCK +#ifdef O_NDELAY +#define O_NONBLOCK O_NDELAY +#endif +#endif + +static void DoLoop(struct bundle *); +static void TerminalStop(int); +static const char *ex_desc(int); + +static struct bundle *SignalBundle; +static struct prompt *SignalPrompt; + +void +Cleanup(int excode) +{ + SignalBundle->CleaningUp = 1; + bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); +} + +void +AbortProgram(int excode) +{ + server_Close(SignalBundle); + log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); + bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); + bundle_Destroy(SignalBundle); + log_Close(); + exit(excode); +} + +static void +CloseConnection(int signo) +{ + /* NOTE, these are manual, we've done a setsid() */ + sig_signal(SIGINT, SIG_IGN); + log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); + bundle_Down(SignalBundle, CLOSE_STAYDOWN); + sig_signal(SIGINT, CloseConnection); +} + +static void +CloseSession(int signo) +{ + log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); + Cleanup(EX_TERM); +} + +static pid_t BGPid = 0; + +static void +KillChild(int signo) +{ + log_Printf(LogPHASE, "Parent: Signal %d\n", signo); + kill(BGPid, SIGINT); +} + +static void +TerminalCont(int signo) +{ + signal(SIGCONT, SIG_DFL); + prompt_Continue(SignalPrompt); +} + +static void +TerminalStop(int signo) +{ + prompt_Suspend(SignalPrompt); + signal(SIGCONT, TerminalCont); + raise(SIGSTOP); +} + +static void +BringDownServer(int signo) +{ + /* Drops all child prompts too ! */ + server_Close(SignalBundle); +} + +static const char * +ex_desc(int ex) +{ + static char num[12]; /* Used immediately if returned */ + static const char *desc[] = { + "normal", "start", "sock", "modem", "dial", "dead", "done", + "reboot", "errdead", "hangup", "term", "nodial", "nologin" + }; + + if (ex >= 0 && ex < sizeof desc / sizeof *desc) + return desc[ex]; + snprintf(num, sizeof num, "%d", ex); + return num; +} + +static void +Usage(void) +{ + fprintf(stderr, + "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" +#ifndef NOALIAS + " [ -alias ]" +#endif + " [system]\n"); + exit(EX_START); +} + +static char * +ProcessArgs(int argc, char **argv, int *mode, int *alias) +{ + int optc, labelrequired, newmode; + char *cp; + + optc = labelrequired = 0; + *mode = PHYS_INTERACTIVE; + *alias = 0; + while (argc > 0 && **argv == '-') { + cp = *argv + 1; + newmode = Nam2mode(cp); + switch (newmode) { + case PHYS_NONE: + if (strcmp(cp, "alias") == 0) { +#ifdef NOALIAS + log_Printf(LogWARN, "Cannot load alias library\n"); +#else + *alias = 1; +#endif + optc--; /* this option isn't exclusive */ + } else + Usage(); + break; + + case PHYS_ALL: + Usage(); + break; + + case PHYS_AUTO: + case PHYS_BACKGROUND: + case PHYS_DDIAL: + labelrequired = 1; + /* fall through */ + + default: + *mode = newmode; + } + optc++; + argv++; + argc--; + } + + if (argc > 1) { + fprintf(stderr, "You may specify only one system label.\n"); + exit(EX_START); + } + + if (optc > 1) { + fprintf(stderr, "You may specify only one mode.\n"); + exit(EX_START); + } + + if (labelrequired && argc != 1) { + fprintf(stderr, "Destination system must be specified in" + " auto, background or ddial mode.\n"); + exit(EX_START); + } + + return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ +} + +int +main(int argc, char **argv) +{ + char *name, *label; + int nfds, mode, alias; + struct bundle *bundle; + struct prompt *prompt; + + nfds = getdtablesize(); + if (nfds >= FD_SETSIZE) + /* + * If we've got loads of file descriptors, make sure they're all + * closed. If they aren't, we may end up with a seg fault when our + * `fd_set's get too big when select()ing ! + */ + while (--nfds > 2) + close(nfds); + + name = strrchr(argv[0], '/'); + log_Open(name ? name + 1 : argv[0]); + +#ifndef NOALIAS + PacketAliasInit(); +#endif + label = ProcessArgs(argc - 1, argv + 1, &mode, &alias); + +#ifdef __FreeBSD__ + /* + * A FreeBSD hack to dodge a bug in the tty driver that drops output + * occasionally.... I must find the real reason some time. To display + * the dodgy behaviour, comment out this bit, make yourself a large + * routing table and then run ppp in interactive mode. The `show route' + * command will drop chunks of data !!! + */ + if (mode == PHYS_INTERACTIVE) { + close(STDIN_FILENO); + if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { + fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); + return 2; + } + } +#endif + + /* Allow output for the moment (except in direct mode) */ + if (mode == PHYS_DIRECT) + prompt = NULL; + else { + SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); + prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(mode)); + } + + ID0init(); + if (ID0realuid() != 0) { + char conf[200], *ptr; + + snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); + do { + if (!access(conf, W_OK)) { + log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", + conf); + return -1; + } + ptr = conf + strlen(conf)-2; + while (ptr > conf && *ptr != '/') + *ptr-- = '\0'; + } while (ptr >= conf); + } + + if (!system_IsValid(label, prompt, mode)) { + fprintf(stderr, "You may not use ppp in this mode with this label\n"); + if (mode == PHYS_DIRECT) { + const char *l; + l = label ? label : "default"; + log_Printf(LogWARN, "Label %s rejected -direct connection\n", l); + } + log_Close(); + return 1; + } + + if ((bundle = bundle_Create(TUN_PREFIX, mode, (const char **)argv)) == NULL) { + log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno)); + return EX_START; + } + if (prompt) { + prompt->bundle = bundle; /* couldn't do it earlier */ + prompt_Printf(prompt, "Using interface: %s\n", bundle->ifp.Name); + } + SignalBundle = bundle; + bundle->AliasEnabled = alias; + + if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) + prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); + + sig_signal(SIGHUP, CloseSession); + sig_signal(SIGTERM, CloseSession); + sig_signal(SIGINT, CloseConnection); + sig_signal(SIGQUIT, CloseSession); + sig_signal(SIGALRM, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + if (mode == PHYS_INTERACTIVE) + sig_signal(SIGTSTP, TerminalStop); + + sig_signal(SIGUSR2, BringDownServer); + + if (label) { + /* + * Set label both before and after system_Select ! + * This way, "set enddisc label" works during system_Select, and we + * also end up with the correct label if we have embedded load + * commands. + */ + bundle_SetLabel(bundle, label); + if (system_Select(bundle, label, CONFFILE, prompt, NULL) < 0) { + prompt_Printf(prompt, "Destination system (%s) not found.\n", label); + AbortProgram(EX_START); + } + bundle_SetLabel(bundle, label); + if (mode == PHYS_AUTO && + bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { + prompt_Printf(prompt, "You must \"set ifaddr\" with a peer address " + "in label %s for auto mode.\n", label); + AbortProgram(EX_START); + } + } + + if (mode != PHYS_INTERACTIVE) { + if (mode != PHYS_DIRECT) { + int bgpipe[2]; + pid_t bgpid; + + if (mode == PHYS_BACKGROUND && pipe(bgpipe)) { + log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); + AbortProgram(EX_SOCK); + } + + bgpid = fork(); + if (bgpid == -1) { + log_Printf(LogERROR, "fork: %s\n", strerror(errno)); + AbortProgram(EX_SOCK); + } + + if (bgpid) { + char c = EX_NORMAL; + + if (mode == PHYS_BACKGROUND) { + close(bgpipe[1]); + BGPid = bgpid; + /* If we get a signal, kill the child */ + signal(SIGHUP, KillChild); + signal(SIGTERM, KillChild); + signal(SIGINT, KillChild); + signal(SIGQUIT, KillChild); + + /* Wait for our child to close its pipe before we exit */ + if (read(bgpipe[0], &c, 1) != 1) { + prompt_Printf(prompt, "Child exit, no status.\n"); + log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); + } else if (c == EX_NORMAL) { + prompt_Printf(prompt, "PPP enabled.\n"); + log_Printf(LogPHASE, "Parent: PPP enabled.\n"); + } else { + prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); + log_Printf(LogPHASE, "Parent: Child failed (%s).\n", + ex_desc((int) c)); + } + close(bgpipe[0]); + } + return c; + } else if (mode == PHYS_BACKGROUND) { + close(bgpipe[0]); + bundle->notify.fd = bgpipe[1]; + } + + bundle_LockTun(bundle); /* we have a new pid */ + + /* -auto, -dedicated, -ddial & -background */ + prompt_Destroy(prompt, 0); + close(STDOUT_FILENO); + close(STDERR_FILENO); + close(STDIN_FILENO); + setsid(); + } else { + /* -direct: STDIN_FILENO gets used by modem_Open */ + prompt_TtyInit(NULL); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + } else { + /* Interactive mode */ + close(STDERR_FILENO); + prompt_TtyInit(prompt); + prompt_TtyCommandMode(prompt); + prompt_Required(prompt); + } + + log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode)); + DoLoop(bundle); + AbortProgram(EX_NORMAL); + + return EX_NORMAL; +} + +static void +DoLoop(struct bundle *bundle) +{ + fd_set rfds, wfds, efds; + int i, nfds, nothing_done; + struct probe probe; + + probe_Init(&probe); + + do { + nfds = 0; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + + /* All our datalinks, the tun device and the MP socket */ + descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); + + /* All our prompts and the diagnostic socket */ + descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); + + if (bundle_IsDead(bundle)) + /* Don't select - we'll be here forever */ + break; + + i = select(nfds, &rfds, &wfds, &efds, NULL); + + if (i < 0 && errno != EINTR) { + log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); + if (log_IsKept(LogTIMER)) { + struct timeval t; + + for (i = 0; i <= nfds; i++) { + if (FD_ISSET(i, &rfds)) { + log_Printf(LogTIMER, "Read set contains %d\n", i); + FD_CLR(i, &rfds); + t.tv_sec = t.tv_usec = 0; + if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { + log_Printf(LogTIMER, "The culprit !\n"); + break; + } + } + if (FD_ISSET(i, &wfds)) { + log_Printf(LogTIMER, "Write set contains %d\n", i); + FD_CLR(i, &wfds); + t.tv_sec = t.tv_usec = 0; + if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { + log_Printf(LogTIMER, "The culprit !\n"); + break; + } + } + if (FD_ISSET(i, &efds)) { + log_Printf(LogTIMER, "Error set contains %d\n", i); + FD_CLR(i, &efds); + t.tv_sec = t.tv_usec = 0; + if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { + log_Printf(LogTIMER, "The culprit !\n"); + break; + } + } + } + } + break; + } + + sig_Handle(); + + if (i <= 0) + continue; + + for (i = 0; i <= nfds; i++) + if (FD_ISSET(i, &efds)) { + log_Printf(LogERROR, "Exception detected on descriptor %d\n", i); + break; + } + + if (i <= nfds) + break; + + nothing_done = 1; + + if (descriptor_IsSet(&server.desc, &rfds)) { + descriptor_Read(&server.desc, bundle, &rfds); + nothing_done = 0; + } + + if (descriptor_IsSet(&bundle->desc, &rfds)) { + descriptor_Read(&bundle->desc, bundle, &rfds); + nothing_done = 0; + } + + if (descriptor_IsSet(&bundle->desc, &wfds)) + if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { + /* + * This is disasterous. The OS has told us that something is + * writable, and all our write()s have failed. Rather than + * going back immediately to do our UpdateSet()s and select(), + * we sleep for a bit to avoid gobbling up all cpu time. + */ + struct timeval t; + + t.tv_sec = 0; + t.tv_usec = 100000; + select(0, NULL, NULL, NULL, &t); + } + + } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); + + log_Printf(LogDEBUG, "DoLoop done.\n"); +} diff --git a/usr.sbin/ppp/arp.h b/usr.sbin/ppp/ppp/main.h index b5d2b2e7ddc..88318476a33 100644 --- a/usr.sbin/ppp/arp.h +++ b/usr.sbin/ppp/ppp/main.h @@ -17,9 +17,9 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: arp.h,v 1.2 1998/01/19 02:57:33 brian Exp $ + * $Id: main.h,v 1.1 1998/08/31 00:22:24 brian Exp $ * */ -extern int cifproxyarp(int, struct in_addr); -extern int sifproxyarp(int, struct in_addr); +extern void Cleanup(int); +extern void AbortProgram(int); diff --git a/usr.sbin/ppp/ppp/mbuf.c b/usr.sbin/ppp/ppp/mbuf.c new file mode 100644 index 00000000000..41de244acd0 --- /dev/null +++ b/usr.sbin/ppp/ppp/mbuf.c @@ -0,0 +1,211 @@ +/* + * PPP Memory handling module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: mbuf.c,v 1.1 1998/08/31 00:22:24 brian Exp $ + * + */ +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "descriptor.h" +#include "prompt.h" +#include "main.h" + +static struct memmap { + struct mbuf *queue; + int fragments, octets; +} MemMap[MB_MAX + 2]; + +static int totalalloced; + +int +mbuf_Length(struct mbuf * bp) +{ + int len; + + for (len = 0; bp; bp = bp->next) + len += bp->cnt; + return (len); +} + +struct mbuf * +mbuf_Alloc(int cnt, int type) +{ + struct mbuf *bp; + + if (type > MB_MAX) + log_Printf(LogERROR, "Bad mbuf type %d\n", type); + bp = malloc(sizeof(struct mbuf) + cnt); + if (bp == NULL) { + log_Printf(LogALERT, "failed to allocate memory: %ld\n", + (long)sizeof(struct mbuf)); + AbortProgram(EX_OSERR); + } + memset(bp, '\0', sizeof(struct mbuf)); + MemMap[type].fragments++; + MemMap[type].octets += cnt; + totalalloced += cnt; + bp->size = bp->cnt = cnt; + bp->type = type; + bp->pnext = NULL; + return (bp); +} + +struct mbuf * +mbuf_FreeSeg(struct mbuf * bp) +{ + struct mbuf *nbp; + + if (bp) { + nbp = bp->next; + MemMap[bp->type].fragments--; + MemMap[bp->type].octets -= bp->size; + totalalloced -= bp->size; + free(bp); + return (nbp); + } + return (bp); +} + +void +mbuf_Free(struct mbuf * bp) +{ + while (bp) + bp = mbuf_FreeSeg(bp); +} + +struct mbuf * +mbuf_Read(struct mbuf * bp, u_char * ptr, int len) +{ + int nb; + + while (bp && len > 0) { + if (len > bp->cnt) + nb = bp->cnt; + else + nb = len; + memcpy(ptr, MBUF_CTOP(bp), nb); + ptr += nb; + bp->cnt -= nb; + len -= nb; + bp->offset += nb; + if (bp->cnt == 0) { +#ifdef notdef + bp = bp->next; +#else + bp = mbuf_FreeSeg(bp); +#endif + } + } + return (bp); +} + +void +mbuf_Write(struct mbuf * bp, u_char * ptr, int cnt) +{ + int plen; + int nb; + + plen = mbuf_Length(bp); + if (plen < cnt) + cnt = plen; + + while (cnt > 0) { + nb = (cnt < bp->cnt) ? cnt : bp->cnt; + memcpy(MBUF_CTOP(bp), ptr, nb); + cnt -= bp->cnt; + bp = bp->next; + } +} + +int +mbuf_Show(struct cmdargs const *arg) +{ + int i; + static const char *mbuftype[] = { + "async", "fsm", "cbcp", "hdlcout", "ipin", "echo", "lqr", "link", + "vjcomp", "ipq", "mp" }; + + prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); + for (i = 1; i < MB_MAX; i += 2) + prompt_Printf(arg->prompt, "%10.10s: %04d (%06d)\t%10.10s: %04d (%06d)\n", + mbuftype[i-1], MemMap[i].fragments, MemMap[i].octets, mbuftype[i], + MemMap[i+1].fragments, MemMap[i+1].octets); + + if (i == MB_MAX) + prompt_Printf(arg->prompt, "%10.10s: %04d (%06d)\n", + mbuftype[i-1], MemMap[i].fragments, MemMap[i].octets); + + return 0; +} + +void +mbuf_Log() +{ + log_Printf(LogDEBUG, "mbuf_Log: mem alloced: %d\n", totalalloced); + log_Printf(LogDEBUG, "mbuf_Log: 1: %d 2: %d 3: %d 4: %d\n", + MemMap[1].octets, MemMap[2].octets, MemMap[3].octets, MemMap[4].octets); + log_Printf(LogDEBUG, "mbuf_Log: 5: %d 6: %d 7: %d 8: %d\n", + MemMap[5].octets, MemMap[6].octets, MemMap[7].octets, MemMap[8].octets); + log_Printf(LogDEBUG, "mbuf_Log: 9: %d 10: %d 11: %d\n", + MemMap[9].octets, MemMap[10].octets, MemMap[11].octets); +} + +struct mbuf * +mbuf_Dequeue(struct mqueue *q) +{ + struct mbuf *bp; + + log_Printf(LogDEBUG, "mbuf_Dequeue: queue len = %d\n", q->qlen); + bp = q->top; + if (bp) { + q->top = q->top->pnext; + q->qlen--; + if (q->top == NULL) { + q->last = q->top; + if (q->qlen) + log_Printf(LogERROR, "mbuf_Dequeue: Not zero (%d)!!!\n", q->qlen); + } + bp->pnext = NULL; + } + + return bp; +} + + +void +mbuf_Enqueue(struct mqueue *queue, struct mbuf *bp) +{ + if (queue->last) { + queue->last->pnext = bp; + queue->last = bp; + } else + queue->last = queue->top = bp; + queue->qlen++; + log_Printf(LogDEBUG, "mbuf_Enqueue: len = %d\n", queue->qlen); +} diff --git a/usr.sbin/ppp/mbuf.h b/usr.sbin/ppp/ppp/mbuf.h index d2eeae96f13..104f44661b8 100644 --- a/usr.sbin/ppp/mbuf.h +++ b/usr.sbin/ppp/ppp/mbuf.h @@ -15,19 +15,19 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: mbuf.h,v 1.3 1998/01/21 02:13:37 brian Exp $ + * $Id: mbuf.h,v 1.1 1998/08/31 00:22:24 brian Exp $ * * TODO: */ struct mbuf { - u_char *base; /* pointer to top of buffer space */ - short size; /* size allocated from base */ - short offset; /* offset to start position */ + short size; /* size allocated (excluding header) */ + short offset; /* offset from header end to start position */ short cnt; /* available byte count in buffer */ - short type; + short type; /* MB_* below */ struct mbuf *next; /* link to next mbuf */ struct mbuf *pnext; /* link to next packet */ + /* buffer space is malloc()d directly after the header */ }; struct mqueue { @@ -36,25 +36,31 @@ struct mqueue { int qlen; }; -#define MBUF_CTOP(bp) (bp->base + bp->offset) +#define MBUF_CTOP(bp) ((u_char *)((bp)+1) + (bp)->offset) +#define CONST_MBUF_CTOP(bp) ((const u_char *)((bp)+1) + (bp)->offset) #define MB_ASYNC 1 #define MB_FSM 2 -#define MB_HDLCOUT 3 -#define MB_IPIN 4 -#define MB_ECHO 5 -#define MB_LQR 6 -#define MB_MODEM 7 -#define MB_VJCOMP 8 -#define MB_LOG 9 +#define MB_CBCP 3 +#define MB_HDLCOUT 4 +#define MB_IPIN 5 +#define MB_ECHO 6 +#define MB_LQR 7 +#define MB_LINK 8 +#define MB_VJCOMP 9 #define MB_IPQ 10 -#define MB_MAX MB_IPQ +#define MB_MP 11 +#define MB_MAX MB_MP -extern int plength(struct mbuf *); -extern struct mbuf *mballoc(int, int); -extern struct mbuf *mbfree(struct mbuf *); -extern void pfree(struct mbuf *); -extern void mbwrite(struct mbuf *, u_char *, int); -extern struct mbuf *mbread(struct mbuf *, u_char *, int); -extern void LogMemory(void); -extern int ShowMemMap(struct cmdargs const *); +struct cmdargs; + +extern int mbuf_Length(struct mbuf *); +extern struct mbuf *mbuf_Alloc(int, int); +extern struct mbuf *mbuf_FreeSeg(struct mbuf *); +extern void mbuf_Free(struct mbuf *); +extern void mbuf_Write(struct mbuf *, u_char *, int); +extern struct mbuf *mbuf_Read(struct mbuf *, u_char *, int); +extern void mbuf_Log(void); +extern int mbuf_Show(struct cmdargs const *); +extern void mbuf_Enqueue(struct mqueue *, struct mbuf *); +extern struct mbuf *mbuf_Dequeue(struct mqueue *); diff --git a/usr.sbin/ppp/ppp/modem.c b/usr.sbin/ppp/ppp/modem.c new file mode 100644 index 00000000000..34ec8945f97 --- /dev/null +++ b/usr.sbin/ppp/ppp/modem.c @@ -0,0 +1,1097 @@ +/* + * PPP Modem handling module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: modem.c,v 1.1 1998/08/31 00:22:24 brian Exp $ + * + * TODO: + */ +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/tty.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <unistd.h> +#ifdef __OpenBSD__ +#include <sys/ioctl.h> +#include <util.h> +#else +#include <libutil.h> +#endif + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "id.h" +#include "timer.h" +#include "fsm.h" +#include "lqr.h" +#include "hdlc.h" +#include "lcp.h" +#include "modem.h" +#include "throughput.h" +#include "async.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "prompt.h" +#include "chat.h" +#include "auth.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" + + +static int modem_DescriptorWrite(struct descriptor *, struct bundle *, + const fd_set *); +static void modem_DescriptorRead(struct descriptor *, struct bundle *, + const fd_set *); +static int modem_UpdateSet(struct descriptor *, fd_set *, fd_set *, fd_set *, + int *); + +struct physical * +modem_Create(struct datalink *dl, int type) +{ + struct physical *p; + + p = (struct physical *)malloc(sizeof(struct physical)); + if (!p) + return NULL; + + p->link.type = PHYSICAL_LINK; + p->link.name = dl->name; + p->link.len = sizeof *p; + throughput_init(&p->link.throughput); + memset(&p->Timer, '\0', sizeof p->Timer); + memset(p->link.Queue, '\0', sizeof p->link.Queue); + memset(p->link.proto_in, '\0', sizeof p->link.proto_in); + memset(p->link.proto_out, '\0', sizeof p->link.proto_out); + + p->desc.type = PHYSICAL_DESCRIPTOR; + p->desc.UpdateSet = modem_UpdateSet; + p->desc.IsSet = physical_IsSet; + p->desc.Read = modem_DescriptorRead; + p->desc.Write = modem_DescriptorWrite; + p->type = type; + + hdlc_Init(&p->hdlc, &p->link.lcp); + async_Init(&p->async); + + p->fd = -1; + p->mbits = 0; + p->dev_is_modem = 0; + p->out = NULL; + p->connect_count = 0; + p->dl = dl; + + *p->name.full = '\0'; + p->name.base = p->name.full; + + p->Utmp = 0; + p->session_owner = (pid_t)-1; + + p->cfg.rts_cts = MODEM_CTSRTS; + p->cfg.speed = MODEM_SPEED; + p->cfg.parity = CS8; + strncpy(p->cfg.devlist, MODEM_LIST, sizeof p->cfg.devlist - 1); + p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0'; + + lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp); + ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp); + + return p; +} + +/* XXX-ML this should probably change when we add support for other + types of devices */ +#define Online(modem) ((modem)->mbits & TIOCM_CD) + +static void modem_LogicalClose(struct physical *); + +static const struct speeds { + int nspeed; + speed_t speed; +} speeds[] = { +#ifdef B50 + { 50, B50, }, +#endif +#ifdef B75 + { 75, B75, }, +#endif +#ifdef B110 + { 110, B110, }, +#endif +#ifdef B134 + { 134, B134, }, +#endif +#ifdef B150 + { 150, B150, }, +#endif +#ifdef B200 + { 200, B200, }, +#endif +#ifdef B300 + { 300, B300, }, +#endif +#ifdef B600 + { 600, B600, }, +#endif +#ifdef B1200 + { 1200, B1200, }, +#endif +#ifdef B1800 + { 1800, B1800, }, +#endif +#ifdef B2400 + { 2400, B2400, }, +#endif +#ifdef B4800 + { 4800, B4800, }, +#endif +#ifdef B9600 + { 9600, B9600, }, +#endif +#ifdef B19200 + { 19200, B19200, }, +#endif +#ifdef B38400 + { 38400, B38400, }, +#endif +#ifndef _POSIX_SOURCE +#ifdef B7200 + { 7200, B7200, }, +#endif +#ifdef B14400 + { 14400, B14400, }, +#endif +#ifdef B28800 + { 28800, B28800, }, +#endif +#ifdef B57600 + { 57600, B57600, }, +#endif +#ifdef B76800 + { 76800, B76800, }, +#endif +#ifdef B115200 + { 115200, B115200, }, +#endif +#ifdef B230400 + { 230400, B230400, }, +#endif +#ifdef EXTA + { 19200, EXTA, }, +#endif +#ifdef EXTB + { 38400, EXTB, }, +#endif +#endif /* _POSIX_SOURCE */ + { 0, 0 } +}; + +static int +SpeedToInt(speed_t speed) +{ + const struct speeds *sp; + + for (sp = speeds; sp->nspeed; sp++) { + if (sp->speed == speed) { + return (sp->nspeed); + } + } + return 0; +} + +speed_t +IntToSpeed(int nspeed) +{ + const struct speeds *sp; + + for (sp = speeds; sp->nspeed; sp++) { + if (sp->nspeed == nspeed) { + return (sp->speed); + } + } + return B0; +} + +static void +modem_SetDevice(struct physical *physical, const char *name) +{ + int len = strlen(_PATH_DEV); + + strncpy(physical->name.full, name, sizeof physical->name.full - 1); + physical->name.full[sizeof physical->name.full - 1] = '\0'; + physical->name.base = strncmp(physical->name.full, _PATH_DEV, len) ? + physical->name.full : physical->name.full + len; +} + +/* + * modem_Timeout() watches DCD signal and notifies if it's status is changed. + * + */ +static void +modem_Timeout(void *data) +{ + struct physical *modem = data; + int ombits = modem->mbits; + int change; + + timer_Stop(&modem->Timer); + timer_Start(&modem->Timer); + + if (modem->dev_is_modem) { + if (modem->fd >= 0) { + if (ioctl(modem->fd, TIOCMGET, &modem->mbits) < 0) { + log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", modem->link.name, + strerror(errno)); + datalink_Down(modem->dl, CLOSE_NORMAL); + return; + } + } else + modem->mbits = 0; + change = ombits ^ modem->mbits; + if (change & TIOCM_CD) { + if (modem->mbits & TIOCM_CD) + log_Printf(LogDEBUG, "%s: offline -> online\n", modem->link.name); + else { + log_Printf(LogDEBUG, "%s: online -> offline\n", modem->link.name); + log_Printf(LogPHASE, "%s: Carrier lost\n", modem->link.name); + datalink_Down(modem->dl, CLOSE_NORMAL); + } + } else + log_Printf(LogDEBUG, "%s: Still %sline\n", modem->link.name, + Online(modem) ? "on" : "off"); + } else if (!Online(modem)) { + /* mbits was set to zero in modem_Open() */ + modem->mbits = TIOCM_CD; + } +} + +static void +modem_StartTimer(struct bundle *bundle, struct physical *modem) +{ + struct pppTimer *ModemTimer; + + ModemTimer = &modem->Timer; + + timer_Stop(ModemTimer); + ModemTimer->load = SECTICKS; + ModemTimer->func = modem_Timeout; + ModemTimer->name = "modem CD"; + ModemTimer->arg = modem; + log_Printf(LogDEBUG, "%s: Using modem_Timeout [%p]\n", + modem->link.name, modem_Timeout); + timer_Start(ModemTimer); +} + +static const struct parity { + const char *name; + const char *name1; + int set; +} validparity[] = { + { "even", "P_EVEN", CS7 | PARENB }, + { "odd", "P_ODD", CS7 | PARENB | PARODD }, + { "none", "P_ZERO", CS8 }, + { NULL, 0 }, +}; + +static int +GetParityValue(const char *str) +{ + const struct parity *pp; + + for (pp = validparity; pp->name; pp++) { + if (strcasecmp(pp->name, str) == 0 || + strcasecmp(pp->name1, str) == 0) { + return pp->set; + } + } + return (-1); +} + +int +modem_SetParity(struct physical *modem, const char *str) +{ + struct termios rstio; + int val; + + val = GetParityValue(str); + if (val > 0) { + modem->cfg.parity = val; + tcgetattr(modem->fd, &rstio); + rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); + rstio.c_cflag |= val; + tcsetattr(modem->fd, TCSADRAIN, &rstio); + return 0; + } + log_Printf(LogWARN, "%s: %s: Invalid parity\n", modem->link.name, str); + return -1; +} + +static int +OpenConnection(const char *name, char *host, char *port) +{ + struct sockaddr_in dest; + int sock; + struct hostent *hp; + struct servent *sp; + + dest.sin_family = AF_INET; + dest.sin_addr.s_addr = inet_addr(host); + if (dest.sin_addr.s_addr == INADDR_NONE) { + hp = gethostbyname(host); + if (hp) { + memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], 4); + } else { + log_Printf(LogWARN, "%s: %s: unknown host\n", name, host); + return (-1); + } + } + dest.sin_port = htons(atoi(port)); + if (dest.sin_port == 0) { + sp = getservbyname(port, "tcp"); + if (sp) { + dest.sin_port = sp->s_port; + } else { + log_Printf(LogWARN, "%s: %s: unknown service\n", name, port); + return (-1); + } + } + log_Printf(LogPHASE, "%s: Connecting to %s:%s\n", name, host, port); + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + return (sock); + } + if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) { + log_Printf(LogWARN, "%s: connect: %s\n", name, strerror(errno)); + close(sock); + return (-1); + } + return (sock); +} + +static int +modem_lock(struct physical *modem, int tunno) +{ + int res; + FILE *lockfile; + char fn[MAXPATHLEN]; + + if (*modem->name.full != '/') + return 0; + + if (modem->type != PHYS_DIRECT && + (res = ID0uu_lock(modem->name.base)) != UU_LOCK_OK) { + if (res == UU_LOCK_INUSE) + log_Printf(LogPHASE, "%s: %s is in use\n", + modem->link.name, modem->name.full); + else + log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n", + modem->link.name, modem->name.full, uu_lockerr(res)); + return (-1); + } + + snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, modem->name.base); + lockfile = ID0fopen(fn, "w"); + if (lockfile != NULL) { + fprintf(lockfile, "%s%d\n", TUN_NAME, tunno); + fclose(lockfile); + } +#ifndef RELEASE_CRUNCH + else + log_Printf(LogALERT, "%s: Can't create %s: %s\n", + modem->link.name, fn, strerror(errno)); +#endif + + return 0; +} + +static void +modem_Unlock(struct physical *modem) +{ + char fn[MAXPATHLEN]; + + if (*modem->name.full != '/') + return; + + snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, modem->name.base); +#ifndef RELEASE_CRUNCH + if (ID0unlink(fn) == -1) + log_Printf(LogALERT, "%s: Can't remove %s: %s\n", + modem->link.name, fn, strerror(errno)); +#else + ID0unlink(fn); +#endif + + if (modem->type != PHYS_DIRECT && ID0uu_unlock(modem->name.base) == -1) + log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", modem->link.name, fn); +} + +static void +modem_Found(struct physical *modem, struct bundle *bundle) +{ + throughput_start(&modem->link.throughput, "modem throughput", + Enabled(bundle, OPT_THROUGHPUT)); + modem->connect_count++; + log_Printf(LogPHASE, "%s: Connected!\n", modem->link.name); +} + +int +modem_Open(struct physical *modem, struct bundle *bundle) +{ + struct termios rstio; + int oldflag; + char *host, *port; + char *cp; + char tmpDeviceList[sizeof modem->cfg.devlist]; + char *tmpDevice; + + if (modem->fd >= 0) + log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", modem->link.name); + /* We're going back into "term" mode */ + else if (modem->type == PHYS_DIRECT) { + if (isatty(STDIN_FILENO)) { + log_Printf(LogDEBUG, "%s: Open(direct): Modem is a tty\n", + modem->link.name); + modem_SetDevice(modem, ttyname(STDIN_FILENO)); + if (modem_lock(modem, bundle->unit) == -1) { + close(STDIN_FILENO); + return -1; + } + modem->fd = STDIN_FILENO; + modem_Found(modem, bundle); + } else { + log_Printf(LogDEBUG, "%s: Open(direct): Modem is not a tty\n", + modem->link.name); + modem_SetDevice(modem, ""); + /* We don't call modem_Timeout() with this type of connection */ + modem_Found(modem, bundle); + return modem->fd = STDIN_FILENO; + } + } else { + strncpy(tmpDeviceList, modem->cfg.devlist, sizeof tmpDeviceList - 1); + tmpDeviceList[sizeof tmpDeviceList - 1] = '\0'; + + for(tmpDevice=strtok(tmpDeviceList, ", "); tmpDevice && modem->fd < 0; + tmpDevice=strtok(NULL,", ")) { + modem_SetDevice(modem, tmpDevice); + + if (*modem->name.full == '/') { + if (modem_lock(modem, bundle->unit) != -1) { + modem->fd = ID0open(modem->name.full, O_RDWR | O_NONBLOCK); + if (modem->fd < 0) { + log_Printf(LogPHASE, "%s: Open(\"%s\"): %s\n", + modem->link.name, modem->name.full, strerror(errno)); + modem_Unlock(modem); + } else { + modem_Found(modem, bundle); + log_Printf(LogDEBUG, "%s: Opened %s\n", + modem->link.name, modem->name.full); + } + } + } else if (*modem->name.full == '!') { + /* PPP via an external program */ + /* + * XXX: Fix me - this should be another sort of link (similar to a + * physical + */ + int fids[2]; + + modem->name.base = modem->name.full + 1; + if (pipe(fids) < 0) + log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n", + strerror(errno)); + else { + int stat; + pid_t pid; + + stat = fcntl(fids[0], F_GETFL, 0); + if (stat > 0) { + stat |= O_NONBLOCK; + fcntl(fids[0], F_SETFL, stat); + } + switch ((pid = fork())) { + case -1: + log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n", + strerror(errno)); + break; + case 0: + close(fids[0]); + timer_TermService(); + + fids[1] = fcntl(fids[1], F_DUPFD, 3); + dup2(fids[1], STDIN_FILENO); + dup2(fids[1], STDOUT_FILENO); + dup2(fids[1], STDERR_FILENO); + setuid(geteuid()); + if (fork()) + exit(127); + execlp(modem->name.base, modem->name.base, NULL); + fprintf(stderr, "execvp failed: %s: %s\n", modem->name.base, + strerror(errno)); + exit(127); + break; + default: + close(fids[1]); + modem->fd = fids[0]; + waitpid(pid, &stat, 0); + break; + } + } + } else { + /* PPP over TCP */ + /* + * XXX: Fix me - this should be another sort of link (similar to a + * physical + */ + cp = strchr(modem->name.full, ':'); + if (cp) { + *cp = '\0'; + host = modem->name.full; + port = cp + 1; + if (*host && *port) { + modem->fd = OpenConnection(modem->link.name, host, port); + *cp = ':'; /* Don't destroy name.full */ + if (modem->fd >= 0) { + modem_Found(modem, bundle); + log_Printf(LogDEBUG, "%s: Opened socket %s\n", modem->link.name, + modem->name.full); + } + } else { + *cp = ':'; /* Don't destroy name.full */ + log_Printf(LogWARN, "%s: Invalid host:port: \"%s\"\n", + modem->link.name, modem->name.full); + } + } else { + log_Printf(LogWARN, "%s: Device (%s) must begin with a '/'," + " a '!' or be a host:port pair\n", modem->link.name, + modem->name.full); + } + } + } + + if (modem->fd < 0) + return modem->fd; + } + + /* + * If we are working on tty device, change it's mode into the one desired + * for further operation. + */ + modem->mbits = 0; + modem->dev_is_modem = isatty(modem->fd) || physical_IsSync(modem); + if (modem->dev_is_modem && !physical_IsSync(modem)) { + tcgetattr(modem->fd, &rstio); + modem->ios = rstio; + log_Printf(LogDEBUG, "%s: Open: modem (get): fd = %d, iflag = %lx, " + "oflag = %lx, cflag = %lx\n", modem->link.name, modem->fd, + (u_long)rstio.c_iflag, (u_long)rstio.c_oflag, + (u_long)rstio.c_cflag); + cfmakeraw(&rstio); + if (modem->cfg.rts_cts) + rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; + else { + rstio.c_cflag |= CLOCAL; + rstio.c_iflag |= IXOFF; + } + rstio.c_iflag |= IXON; + if (modem->type != PHYS_DEDICATED) + rstio.c_cflag |= HUPCL; + + if (modem->type != PHYS_DIRECT) { + /* Change tty speed when we're not in -direct mode */ + rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); + rstio.c_cflag |= modem->cfg.parity; + if (cfsetspeed(&rstio, IntToSpeed(modem->cfg.speed)) == -1) + log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n", + modem->link.name, modem->name.full, modem->cfg.speed); + } + tcsetattr(modem->fd, TCSADRAIN, &rstio); + log_Printf(LogDEBUG, "%s: modem (put): iflag = %lx, oflag = %lx, " + "cflag = %lx\n", modem->link.name, (u_long)rstio.c_iflag, + (u_long)rstio.c_oflag, (u_long)rstio.c_cflag); + + if (ioctl(modem->fd, TIOCMGET, &modem->mbits) == -1) { + if (modem->type != PHYS_DIRECT) { + log_Printf(LogWARN, "%s: Open: Cannot get modem status: %s\n", + modem->link.name, strerror(errno)); + modem_LogicalClose(modem); + return (-1); + } else + modem->mbits = TIOCM_CD; + } + log_Printf(LogDEBUG, "%s: Open: modem control = %o\n", + modem->link.name, modem->mbits); + + oldflag = fcntl(modem->fd, F_GETFL, 0); + if (oldflag < 0) { + log_Printf(LogWARN, "%s: Open: Cannot get modem flags: %s\n", + modem->link.name, strerror(errno)); + modem_LogicalClose(modem); + return (-1); + } + fcntl(modem->fd, F_SETFL, oldflag & ~O_NONBLOCK); + } + + return modem->fd; +} + +int +modem_Speed(struct physical *modem) +{ + struct termios rstio; + + if (!physical_IsATTY(modem)) + return 115200; + + tcgetattr(modem->fd, &rstio); + return (SpeedToInt(cfgetispeed(&rstio))); +} + +/* + * Put modem tty line into raw mode which is necessary in packet mode operation + */ +int +modem_Raw(struct physical *modem, struct bundle *bundle) +{ + struct termios rstio; + int oldflag; + + log_Printf(LogDEBUG, "%s: Entering modem_Raw\n", modem->link.name); + + if (!isatty(modem->fd) || physical_IsSync(modem)) + return 0; + + if (modem->type != PHYS_DIRECT && modem->fd >= 0 && !Online(modem)) + log_Printf(LogDEBUG, "%s: Raw: modem = %d, mbits = %x\n", + modem->link.name, modem->fd, modem->mbits); + + tcgetattr(modem->fd, &rstio); + cfmakeraw(&rstio); + if (modem->cfg.rts_cts) + rstio.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; + else + rstio.c_cflag |= CLOCAL; + + if (modem->type != PHYS_DEDICATED) + rstio.c_cflag |= HUPCL; + + tcsetattr(modem->fd, TCSANOW, &rstio); + + oldflag = fcntl(modem->fd, F_GETFL, 0); + if (oldflag < 0) + return (-1); + fcntl(modem->fd, F_SETFL, oldflag | O_NONBLOCK); + + if (modem->dev_is_modem && ioctl(modem->fd, TIOCMGET, &modem->mbits) == 0 && + (modem->mbits & TIOCM_CD)) { + modem_StartTimer(bundle, modem); + modem_Timeout(modem); + } else + log_Printf(LogDEBUG, "%s: %s doesn't support CD\n", + modem->link.name, modem->name.full); + + return 0; +} + +static void +modem_Unraw(struct physical *modem) +{ + int oldflag; + + if (isatty(modem->fd) && !physical_IsSync(modem)) { + tcsetattr(modem->fd, TCSAFLUSH, &modem->ios); + oldflag = fcntl(modem->fd, F_GETFL, 0); + if (oldflag < 0) + return; + (void) fcntl(modem->fd, F_SETFL, oldflag & ~O_NONBLOCK); + } +} + +static void +modem_PhysicalClose(struct physical *modem) +{ + int newsid; + + log_Printf(LogDEBUG, "%s: Physical Close\n", modem->link.name); + timer_Stop(&modem->Timer); + newsid = tcgetpgrp(modem->fd) == getpgrp(); + close(modem->fd); + modem->fd = -1; + log_SetTtyCommandMode(modem->dl); + throughput_stop(&modem->link.throughput); + throughput_log(&modem->link.throughput, LogPHASE, modem->link.name); + if (modem->session_owner != (pid_t)-1) { + ID0kill(modem->session_owner, SIGHUP); + modem->session_owner = (pid_t)-1; + } + if (newsid) + bundle_setsid(modem->dl->bundle, 0); +} + +void +modem_Offline(struct physical *modem) +{ + if (modem->fd >= 0) { + struct termios tio; + + timer_Stop(&modem->Timer); + modem->mbits &= ~TIOCM_DTR; + if (isatty(modem->fd) && Online(modem)) { + tcgetattr(modem->fd, &tio); + if (cfsetspeed(&tio, B0) == -1) + log_Printf(LogWARN, "%s: Unable to set modem to speed 0\n", + modem->link.name); + else + tcsetattr(modem->fd, TCSANOW, &tio); + /* nointr_sleep(1); */ + } + log_Printf(LogPHASE, "%s: Disconnected!\n", modem->link.name); + } +} + +void +modem_Close(struct physical *modem) +{ + if (modem->fd < 0) + return; + + log_Printf(LogDEBUG, "%s: Close\n", modem->link.name); + + if (!isatty(modem->fd)) { + modem_PhysicalClose(modem); + *modem->name.full = '\0'; + modem->name.base = modem->name.full; + return; + } + + if (modem->fd >= 0) { + tcflush(modem->fd, TCIOFLUSH); + modem_Unraw(modem); + modem_LogicalClose(modem); + } +} + +void +modem_Destroy(struct physical *modem) +{ + modem_Close(modem); + free(modem); +} + +static void +modem_LogicalClose(struct physical *modem) +{ + log_Printf(LogDEBUG, "%s: Logical Close\n", modem->link.name); + if (modem->fd >= 0) { + physical_Logout(modem); + modem_PhysicalClose(modem); + modem_Unlock(modem); + } + *modem->name.full = '\0'; + modem->name.base = modem->name.full; +} + +static int +modem_DescriptorWrite(struct descriptor *d, struct bundle *bundle, + const fd_set *fdset) +{ + struct physical *modem = descriptor2physical(d); + int nb, nw, result = 0; + + if (modem->out == NULL) + modem->out = link_Dequeue(&modem->link); + + if (modem->out) { + nb = modem->out->cnt; + nw = physical_Write(modem, MBUF_CTOP(modem->out), nb); + log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%d) to %d\n", + modem->link.name, nw, nb, modem->fd); + if (nw > 0) { + modem->out->cnt -= nw; + modem->out->offset += nw; + if (modem->out->cnt == 0) + modem->out = mbuf_FreeSeg(modem->out); + result = 1; + } else if (nw < 0) { + if (errno != EAGAIN) { + log_Printf(LogPHASE, "%s: write (%d): %s\n", modem->link.name, + modem->fd, strerror(errno)); + datalink_Down(modem->dl, CLOSE_NORMAL); + } + result = 1; + } + /* else we shouldn't really have been called ! select() is broken ! */ + } + + return result; +} + +int +modem_ShowStatus(struct cmdargs const *arg) +{ + struct physical *modem = arg->cx->physical; +#ifdef TIOCOUTQ + int nb; +#endif + + prompt_Printf(arg->prompt, "Name: %s\n", modem->link.name); + prompt_Printf(arg->prompt, " State: "); + if (modem->fd >= 0) { + if (isatty(modem->fd)) + prompt_Printf(arg->prompt, "open, %s carrier\n", + Online(modem) ? "with" : "no"); + else + prompt_Printf(arg->prompt, "open\n"); + } else + prompt_Printf(arg->prompt, "closed\n"); + prompt_Printf(arg->prompt, " Device: %s", + *modem->name.full ? modem->name.full : + modem->type == PHYS_DIRECT ? "unknown" : "N/A"); + if (modem->session_owner != (pid_t)-1) + prompt_Printf(arg->prompt, " (session owner: %d)", + (int)modem->session_owner); + + prompt_Printf(arg->prompt, "\n Link Type: %s\n", mode2Nam(modem->type)); + prompt_Printf(arg->prompt, " Connect Count: %d\n", + modem->connect_count); +#ifdef TIOCOUTQ + if (modem->fd >= 0 && ioctl(modem->fd, TIOCOUTQ, &nb) >= 0) + prompt_Printf(arg->prompt, " Physical outq: %d\n", nb); +#endif + + prompt_Printf(arg->prompt, " Queued Packets: %d\n", + link_QueueLen(&modem->link)); + prompt_Printf(arg->prompt, " Phone Number: %s\n", arg->cx->phone.chosen); + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + prompt_Printf(arg->prompt, " Device List: %s\n", modem->cfg.devlist); + prompt_Printf(arg->prompt, " Characteristics: "); + if (physical_IsSync(arg->cx->physical)) + prompt_Printf(arg->prompt, "sync"); + else + prompt_Printf(arg->prompt, "%dbps", modem->cfg.speed); + + switch (modem->cfg.parity & CSIZE) { + case CS7: + prompt_Printf(arg->prompt, ", cs7"); + break; + case CS8: + prompt_Printf(arg->prompt, ", cs8"); + break; + } + if (modem->cfg.parity & PARENB) { + if (modem->cfg.parity & PARODD) + prompt_Printf(arg->prompt, ", odd parity"); + else + prompt_Printf(arg->prompt, ", even parity"); + } else + prompt_Printf(arg->prompt, ", no parity"); + + prompt_Printf(arg->prompt, ", CTS/RTS %s\n", + (modem->cfg.rts_cts ? "on" : "off")); + + + prompt_Printf(arg->prompt, "\n"); + throughput_disp(&modem->link.throughput, arg->prompt); + + return 0; +} + +static void +modem_DescriptorRead(struct descriptor *d, struct bundle *bundle, + const fd_set *fdset) +{ + struct physical *p = descriptor2physical(d); + u_char rbuff[MAX_MRU], *cp; + int n; + + /* something to read from modem */ + n = physical_Read(p, rbuff, sizeof rbuff); + log_Printf(LogDEBUG, "%s: DescriptorRead: read %d from %d\n", + p->link.name, n, p->fd); + if (n <= 0) { + if (n < 0) + log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd, + strerror(errno)); + else + log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n", + p->link.name, p->fd); + datalink_Down(p->dl, CLOSE_NORMAL); + return; + } + log_DumpBuff(LogASYNC, "ReadFromModem", rbuff, n); + + if (p->link.lcp.fsm.state <= ST_CLOSED) { + /* In -dedicated mode, we just discard input until LCP is started */ + if (p->type != PHYS_DEDICATED) { + cp = hdlc_Detect(p, rbuff, n); + if (cp) { + /* LCP packet is detected. Turn ourselves into packet mode */ + if (cp != rbuff) + /* Get rid of the bit before the HDLC header */ + log_WritePrompts(p->dl, "%.*s\r\n", (int)(cp - rbuff), rbuff); + log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n", + p->link.name); + datalink_Up(p->dl, 0, 1); + } else + log_WritePrompts(p->dl, "%.*s", n, rbuff); + } + } else if (n > 0) + async_Input(bundle, rbuff, n, p); +} + +static int +modem_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + return physical_UpdateSet(d, r, w, e, n, 0); +} + +struct physical * +iov2modem(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, int fd) +{ + struct physical *p; + int len; + + p = (struct physical *)iov[(*niov)++].iov_base; + p->link.name = dl->name; + throughput_init(&p->link.throughput); + memset(&p->Timer, '\0', sizeof p->Timer); + memset(p->link.Queue, '\0', sizeof p->link.Queue); + + p->desc.UpdateSet = modem_UpdateSet; + p->desc.IsSet = physical_IsSet; + p->desc.Read = modem_DescriptorRead; + p->desc.Write = modem_DescriptorWrite; + p->type = PHYS_DIRECT; + p->dl = dl; + len = strlen(_PATH_DEV); + p->name.base = strncmp(p->name.full, _PATH_DEV, len) ? + p->name.full : p->name.full + len; + p->out = NULL; + p->connect_count = 1; + + p->link.lcp.fsm.bundle = dl->bundle; + p->link.lcp.fsm.link = &p->link; + memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer); + memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer); + memset(&p->link.lcp.fsm.StoppedTimer, '\0', + sizeof p->link.lcp.fsm.StoppedTimer); + p->link.lcp.fsm.parent = &dl->fsmp; + lcp_SetupCallbacks(&p->link.lcp); + + p->link.ccp.fsm.bundle = dl->bundle; + p->link.ccp.fsm.link = &p->link; + /* Our in.state & out.state are NULL (no link-level ccp yet) */ + memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer); + memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer); + memset(&p->link.ccp.fsm.StoppedTimer, '\0', + sizeof p->link.ccp.fsm.StoppedTimer); + p->link.ccp.fsm.parent = &dl->fsmp; + ccp_SetupCallbacks(&p->link.ccp); + + p->hdlc.lqm.owner = &p->link.lcp; + p->hdlc.ReportTimer.state = TIMER_STOPPED; + p->hdlc.lqm.timer.state = TIMER_STOPPED; + + p->fd = fd; + + if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) + lqr_reStart(&p->link.lcp); + hdlc_StartTimer(&p->hdlc); + + throughput_start(&p->link.throughput, "modem throughput", + Enabled(dl->bundle, OPT_THROUGHPUT)); + if (p->Timer.state != TIMER_STOPPED) { + p->Timer.state = TIMER_STOPPED; /* Special - see modem2iov() */ + modem_StartTimer(dl->bundle, p); + } + + return p; +} + +int +modem2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov, + pid_t newpid) +{ + if (p) { + hdlc_StopTimer(&p->hdlc); + lqr_StopTimer(p); + timer_Stop(&p->link.lcp.fsm.FsmTimer); + timer_Stop(&p->link.ccp.fsm.FsmTimer); + timer_Stop(&p->link.lcp.fsm.OpenTimer); + timer_Stop(&p->link.ccp.fsm.OpenTimer); + timer_Stop(&p->link.lcp.fsm.StoppedTimer); + timer_Stop(&p->link.ccp.fsm.StoppedTimer); + if (p->Timer.state != TIMER_STOPPED) { + timer_Stop(&p->Timer); + p->Timer.state = TIMER_RUNNING; /* Special - see iov2modem() */ + } + if (tcgetpgrp(p->fd) == getpgrp()) + p->session_owner = getpid(); /* So I'll eventually get HUP'd */ + timer_Stop(&p->link.throughput.Timer); + modem_ChangedPid(p, newpid); + } + + if (*niov >= maxiov) { + log_Printf(LogERROR, "modem2iov: No room for physical !\n"); + if (p) + free(p); + return -1; + } + + iov[*niov].iov_base = p ? p : malloc(sizeof *p); + iov[*niov].iov_len = sizeof *p; + (*niov)++; + + return p ? p->fd : 0; +} + +void +modem_ChangedPid(struct physical *p, pid_t newpid) +{ + if (p->fd >= 0 && p->type != PHYS_DIRECT) { + int res; + + if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK) + log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res)); + } +} diff --git a/usr.sbin/ppp/modem.h b/usr.sbin/ppp/ppp/modem.h index 858ef1eeb4c..c2adf2cc9bb 100644 --- a/usr.sbin/ppp/modem.h +++ b/usr.sbin/ppp/ppp/modem.h @@ -15,27 +15,29 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: modem.h,v 1.3 1998/01/21 02:13:38 brian Exp $ + * $Id: modem.h,v 1.1 1998/08/31 00:22:24 brian Exp $ * * TODO: */ -extern int RawModem(void); -extern void WriteModem(int, const char *, int); -extern void ModemStartOutput(int); -extern int OpenModem(void); -extern int ModemSpeed(void); -extern int ModemQlen(void); -extern int DialModem(void); +struct iovec; +struct datalink; +struct physical; +struct bundle; +struct ccp; +struct cmdargs; + +extern int modem_Raw(struct physical *, struct bundle *); +extern struct physical *modem_Create(struct datalink *, int); +extern int modem_Open(struct physical *, struct bundle *); +extern int modem_Speed(struct physical *); extern speed_t IntToSpeed(int); -extern void ModemTimeout(void *v); -extern void DownConnection(void); -extern void ModemOutput(int, struct mbuf *); -extern int ChangeParity(const char *); -extern void HangupModem(int); -extern int ShowModemStatus(struct cmdargs const *); -extern void Enqueue(struct mqueue *, struct mbuf *); -extern struct mbuf *Dequeue(struct mqueue *); -extern void SequenceQueues(void); -extern void ModemAddInOctets(int); -extern void ModemAddOutOctets(int); +extern int modem_SetParity(struct physical *, const char *); +extern int modem_ShowStatus(struct cmdargs const *); +extern void modem_Close(struct physical *); +extern void modem_Offline(struct physical *); +extern void modem_Destroy(struct physical *); +extern struct physical *iov2modem(struct datalink *, struct iovec *, int *, + int, int); +extern int modem2iov(struct physical *, struct iovec *, int *, int, pid_t); +extern void modem_ChangedPid(struct physical *, pid_t); diff --git a/usr.sbin/ppp/ppp/mp.c b/usr.sbin/ppp/ppp/mp.c new file mode 100644 index 00000000000..5aecbb1633a --- /dev/null +++ b/usr.sbin/ppp/ppp/mp.c @@ -0,0 +1,1021 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: mp.c,v 1.1 1998/08/31 00:22:25 brian Exp $ + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <net/if_dl.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <errno.h> +#include <paths.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "timer.h" +#include "fsm.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "auth.h" +#include "lcp.h" +#include "async.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "chat.h" +#include "lcpproto.h" +#include "filter.h" +#include "mp.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" +#include "bundle.h" +#include "ip.h" +#include "prompt.h" +#include "id.h" +#include "arp.h" + +void +peerid_Init(struct peerid *peer) +{ + peer->enddisc.class = 0; + *peer->enddisc.address = '\0'; + peer->enddisc.len = 0; + *peer->authname = '\0'; +} + +int +peerid_Equal(const struct peerid *p1, const struct peerid *p2) +{ + return !strcmp(p1->authname, p2->authname) && + p1->enddisc.class == p2->enddisc.class && + p1->enddisc.len == p2->enddisc.len && + !memcmp(p1->enddisc.address, p2->enddisc.address, p1->enddisc.len); +} + +static u_int32_t +inc_seq(unsigned is12bit, u_int32_t seq) +{ + seq++; + if (is12bit) { + if (seq & 0xfffff000) + seq = 0; + } else if (seq & 0xff000000) + seq = 0; + return seq; +} + +static int +isbefore(unsigned is12bit, u_int32_t seq1, u_int32_t seq2) +{ + u_int32_t max = (is12bit ? 0xfff : 0xffffff) - 0x200; + + if (seq1 > max) { + if (seq2 < 0x200 || seq2 > seq1) + return 1; + } else if ((seq1 > 0x200 || seq2 <= max) && seq1 < seq2) + return 1; + + return 0; +} + +static int +mp_ReadHeader(struct mp *mp, struct mbuf *m, struct mp_header *header) +{ + if (mp->local_is12bit) { + header->seq = ntohs(*(u_int16_t *)MBUF_CTOP(m)); + if (header->seq & 0x3000) { + log_Printf(LogWARN, "Oops - MP header without required zero bits\n"); + return 0; + } + header->begin = header->seq & 0x8000 ? 1 : 0; + header->end = header->seq & 0x4000 ? 1 : 0; + header->seq &= 0x0fff; + return 2; + } else { + header->seq = ntohl(*(u_int32_t *)MBUF_CTOP(m)); + if (header->seq & 0x3f000000) { + log_Printf(LogWARN, "Oops - MP header without required zero bits\n"); + return 0; + } + header->begin = header->seq & 0x80000000 ? 1 : 0; + header->end = header->seq & 0x40000000 ? 1 : 0; + header->seq &= 0x00ffffff; + return 4; + } +} + +static void +mp_LayerStart(void *v, struct fsm *fp) +{ + /* The given FSM (ccp) is about to start up ! */ +} + +static void +mp_LayerUp(void *v, struct fsm *fp) +{ + /* The given fsm (ccp) is now up */ +} + +static void +mp_LayerDown(void *v, struct fsm *fp) +{ + /* The given FSM (ccp) has been told to come down */ +} + +static void +mp_LayerFinish(void *v, struct fsm *fp) +{ + /* The given fsm (ccp) is now down */ + if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) + fsm_Open(fp); /* CCP goes to ST_STOPPED */ +} + +void +mp_Init(struct mp *mp, struct bundle *bundle) +{ + mp->peer_is12bit = mp->local_is12bit = 0; + mp->peer_mrru = mp->local_mrru = 0; + + peerid_Init(&mp->peer); + + mp->out.seq = 0; + mp->out.link = 0; + mp->seq.min_in = 0; + mp->seq.next_in = 0; + mp->inbufs = NULL; + mp->bundle = bundle; + + mp->link.type = MP_LINK; + mp->link.name = "mp"; + mp->link.len = sizeof *mp; + + throughput_init(&mp->link.throughput); + memset(mp->link.Queue, '\0', sizeof mp->link.Queue); + memset(mp->link.proto_in, '\0', sizeof mp->link.proto_in); + memset(mp->link.proto_out, '\0', sizeof mp->link.proto_out); + + mp->fsmp.LayerStart = mp_LayerStart; + mp->fsmp.LayerUp = mp_LayerUp; + mp->fsmp.LayerDown = mp_LayerDown; + mp->fsmp.LayerFinish = mp_LayerFinish; + mp->fsmp.object = mp; + + mpserver_Init(&mp->server); + + mp->cfg.mrru = 0; + mp->cfg.shortseq = NEG_ENABLED|NEG_ACCEPTED; + mp->cfg.enddisc.class = 0; + *mp->cfg.enddisc.address = '\0'; + mp->cfg.enddisc.len = 0; + + lcp_Init(&mp->link.lcp, mp->bundle, &mp->link, NULL); + ccp_Init(&mp->link.ccp, mp->bundle, &mp->link, &mp->fsmp); +} + +int +mp_Up(struct mp *mp, struct datalink *dl) +{ + struct lcp *lcp = &dl->physical->link.lcp; + + if (mp->active) { + /* We're adding a link - do a last validation on our parameters */ + if (!peerid_Equal(&dl->peer, &mp->peer)) { + log_Printf(LogPHASE, "%s: Inappropriate peer !\n", dl->name); + return MP_FAILED; + } + if (mp->local_mrru != lcp->want_mrru || + mp->peer_mrru != lcp->his_mrru || + mp->local_is12bit != lcp->want_shortseq || + mp->peer_is12bit != lcp->his_shortseq) { + log_Printf(LogPHASE, "%s: Invalid MRRU/SHORTSEQ MP parameters !\n", + dl->name); + return MP_FAILED; + } + return MP_ADDED; + } else { + /* First link in multilink mode */ + + mp->local_mrru = lcp->want_mrru; + mp->peer_mrru = lcp->his_mrru; + mp->local_is12bit = lcp->want_shortseq; + mp->peer_is12bit = lcp->his_shortseq; + mp->peer = dl->peer; + + throughput_init(&mp->link.throughput); + memset(mp->link.Queue, '\0', sizeof mp->link.Queue); + memset(mp->link.proto_in, '\0', sizeof mp->link.proto_in); + memset(mp->link.proto_out, '\0', sizeof mp->link.proto_out); + + mp->out.seq = 0; + mp->out.link = 0; + mp->seq.min_in = 0; + mp->seq.next_in = 0; + + /* + * Now we create our server socket. + * If it already exists, join it. Otherwise, create and own it + */ + switch (mpserver_Open(&mp->server, &mp->peer)) { + case MPSERVER_CONNECTED: + log_Printf(LogPHASE, "mp: Transfer link on %s\n", + mp->server.socket.sun_path); + mp->server.send.dl = dl; /* Defer 'till it's safe to send */ + return MP_LINKSENT; + case MPSERVER_FAILED: + return MP_FAILED; + case MPSERVER_LISTENING: + log_Printf(LogPHASE, "mp: Listening on %s\n", mp->server.socket.sun_path); + log_Printf(LogPHASE, " First link: %s\n", dl->name); + + /* Re-point our IPCP layer at our MP link */ + ipcp_SetLink(&mp->bundle->ncp.ipcp, &mp->link); + + /* Our lcp's already up 'cos of the NULL parent */ + if (ccp_SetOpenMode(&mp->link.ccp)) { + fsm_Up(&mp->link.ccp.fsm); + fsm_Open(&mp->link.ccp.fsm); + } + + mp->active = 1; + break; + } + } + + return MP_UP; +} + +void +mp_Down(struct mp *mp) +{ + if (mp->active) { + struct mbuf *next; + + /* Don't want any more of these */ + mpserver_Close(&mp->server); + + /* CCP goes down with a bang */ + fsm2initial(&mp->link.ccp.fsm); + + /* Received fragments go in the bit-bucket */ + while (mp->inbufs) { + next = mp->inbufs->pnext; + mbuf_Free(mp->inbufs); + mp->inbufs = next; + } + + peerid_Init(&mp->peer); + mp->active = 0; + } +} + +void +mp_linkInit(struct mp_link *mplink) +{ + mplink->seq = 0; + mplink->weight = 1500; +} + +void +mp_Input(struct mp *mp, struct mbuf *m, struct physical *p) +{ + struct mp_header mh, h; + struct mbuf *q, *last; + int32_t seq; + + /* + * When `m' and `p' are NULL, it means our oldest link has gone down. + * We want to determine a new min, and process any intermediate stuff + * as normal + */ + + if (m && mp_ReadHeader(mp, m, &mh) == 0) { + mbuf_Free(m); + return; + } + + if (p) { + seq = p->dl->mp.seq; + p->dl->mp.seq = mh.seq; + } else + seq = mp->seq.min_in; + + if (mp->seq.min_in == seq) { + /* + * We've received new data on the link that has our min (oldest) seq. + * Figure out which link now has the smallest (oldest) seq. + */ + struct datalink *dl; + + mp->seq.min_in = (u_int32_t)-1; + for (dl = mp->bundle->links; dl; dl = dl->next) + if (dl->state == DATALINK_OPEN && + (mp->seq.min_in == -1 || + isbefore(mp->local_is12bit, dl->mp.seq, mp->seq.min_in))) + mp->seq.min_in = dl->mp.seq; + } + + /* + * Now process as many of our fragments as we can, adding our new + * fragment in as we go, and ordering with the oldest at the top of + * the queue. + */ + + if (!mp->inbufs) { + mp->inbufs = m; + m = NULL; + } + + last = NULL; + seq = mp->seq.next_in; + q = mp->inbufs; + while (q) { + mp_ReadHeader(mp, q, &h); + if (m && isbefore(mp->local_is12bit, mh.seq, h.seq)) { + /* Our received fragment fits in before this one, so link it in */ + if (last) + last->pnext = m; + else + mp->inbufs = m; + m->pnext = q; + q = m; + h = mh; + m = NULL; + } + + if (h.seq != seq) { + /* we're missing something :-( */ + if (mp->seq.min_in > seq) { + /* we're never gonna get it */ + struct mbuf *next; + + /* Zap all older fragments */ + while (mp->inbufs != q) { + log_Printf(LogDEBUG, "Drop frag\n"); + next = mp->inbufs->pnext; + mbuf_Free(mp->inbufs); + mp->inbufs = next; + } + + /* + * Zap everything until the next `end' fragment OR just before + * the next `begin' fragment OR 'till seq.min_in - whichever + * comes first. + */ + do { + mp_ReadHeader(mp, mp->inbufs, &h); + if (h.begin) { + /* We might be able to process this ! */ + h.seq--; /* We're gonna look for fragment with h.seq+1 */ + break; + } + next = mp->inbufs->pnext; + log_Printf(LogDEBUG, "Drop frag %u\n", h.seq); + mbuf_Free(mp->inbufs); + mp->inbufs = next; + } while (mp->inbufs && (h.seq >= mp->seq.min_in || h.end)); + + /* + * Continue processing things from here. + * This deals with the possibility that we received a fragment + * on the slowest link that invalidates some of our data (because + * of the hole at `q'), but where there are subsequent `whole' + * packets that have already been received. + */ + + mp->seq.next_in = seq = inc_seq(mp->local_is12bit, h.seq); + last = NULL; + q = mp->inbufs; + } else + /* we may still receive the missing fragment */ + break; + } else if (h.end) { + /* We've got something, reassemble */ + struct mbuf **frag = &q; + int len; + u_long first = -1; + + do { + *frag = mp->inbufs; + mp->inbufs = mp->inbufs->pnext; + len = mp_ReadHeader(mp, *frag, &h); + if (first == -1) + first = h.seq; + (*frag)->offset += len; + (*frag)->cnt -= len; + (*frag)->pnext = NULL; + if (frag == &q && !h.begin) { + log_Printf(LogWARN, "Oops - MP frag %lu should have a begin flag\n", + (u_long)h.seq); + mbuf_Free(q); + q = NULL; + } else if (frag != &q && h.begin) { + log_Printf(LogWARN, "Oops - MP frag %lu should have an end flag\n", + (u_long)h.seq - 1); + /* + * Stuff our fragment back at the front of the queue and zap + * our half-assembed packet. + */ + (*frag)->pnext = mp->inbufs; + mp->inbufs = *frag; + *frag = NULL; + mbuf_Free(q); + q = NULL; + frag = &q; + h.end = 0; /* just in case it's a whole packet */ + } else + do + frag = &(*frag)->next; + while (*frag != NULL); + } while (!h.end); + + if (q) { + u_short proto; + u_char ch; + + q = mbuf_Read(q, &ch, 1); + proto = ch; + if (!(proto & 1)) { + q = mbuf_Read(q, &ch, 1); + proto <<= 8; + proto += ch; + } + if (log_IsKept(LogDEBUG)) + log_Printf(LogDEBUG, "MP: Reassembled frags %ld-%lu, length %d\n", + first, (u_long)h.seq, mbuf_Length(q)); + hdlc_DecodePacket(mp->bundle, proto, q, &mp->link); + } + + mp->seq.next_in = seq = inc_seq(mp->local_is12bit, h.seq); + last = NULL; + q = mp->inbufs; + } else { + /* Look for the next fragment */ + seq = inc_seq(mp->local_is12bit, seq); + last = q; + q = q->pnext; + } + } + + if (m) { + /* We still have to find a home for our new fragment */ + last = NULL; + for (q = mp->inbufs; q; last = q, q = q->pnext) { + mp_ReadHeader(mp, q, &h); + if (isbefore(mp->local_is12bit, mh.seq, h.seq)) + break; + } + /* Our received fragment fits in here */ + if (last) + last->pnext = m; + else + mp->inbufs = m; + m->pnext = q; + } +} + +static void +mp_Output(struct mp *mp, struct link *l, struct mbuf *m, u_int32_t begin, + u_int32_t end) +{ + struct mbuf *mo; + + /* Stuff an MP header on the front of our packet and send it */ + mo = mbuf_Alloc(4, MB_MP); + mo->next = m; + if (mp->peer_is12bit) { + u_int16_t *seq16; + + seq16 = (u_int16_t *)MBUF_CTOP(mo); + *seq16 = htons((begin << 15) | (end << 14) | (u_int16_t)mp->out.seq); + mo->cnt = 2; + } else { + u_int32_t *seq32; + + seq32 = (u_int32_t *)MBUF_CTOP(mo); + *seq32 = htonl((begin << 31) | (end << 30) | (u_int32_t)mp->out.seq); + mo->cnt = 4; + } + if (log_IsKept(LogDEBUG)) + log_Printf(LogDEBUG, "MP[frag %d]: Send %d bytes on link `%s'\n", + mp->out.seq, mbuf_Length(mo), l->name); + mp->out.seq = inc_seq(mp->peer_is12bit, mp->out.seq); + + if (!ccp_Compress(&l->ccp, l, PRI_NORMAL, PROTO_MP, mo)) + hdlc_Output(l, PRI_NORMAL, PROTO_MP, mo); +} + +int +mp_FillQueues(struct bundle *bundle) +{ + struct mp *mp = &bundle->ncp.mp; + struct datalink *dl, *fdl; + int total, add, len, thislink, nlinks; + u_int32_t begin, end; + struct mbuf *m, *mo; + + thislink = nlinks = 0; + for (fdl = NULL, dl = bundle->links; dl; dl = dl->next) { + /* Include non-open links here as mp->out.link will stay more correct */ + if (!fdl) { + if (thislink == mp->out.link) + fdl = dl; + else + thislink++; + } + nlinks++; + } + + if (!fdl) { + fdl = bundle->links; + if (!fdl) + return 0; + thislink = 0; + } + + total = 0; + for (dl = fdl; nlinks > 0; dl = dl->next, nlinks--, thislink++) { + if (!dl) { + dl = bundle->links; + thislink = 0; + } + + if (dl->state != DATALINK_OPEN) + continue; + + if (dl->physical->out) + /* this link has suffered a short write. Let it continue */ + continue; + + add = link_QueueLen(&dl->physical->link); + total += add; + if (add) + /* this link has got stuff already queued. Let it continue */ + continue; + + if (!link_QueueLen(&mp->link) && !ip_FlushPacket(&mp->link, bundle)) + /* Nothing else to send */ + break; + + m = link_Dequeue(&mp->link); + len = mbuf_Length(m); + begin = 1; + end = 0; + + while (!end) { + if (dl->state == DATALINK_OPEN) { + if (len <= dl->mp.weight + LINK_MINWEIGHT) { + /* + * XXX: Should we remember how much of our `weight' wasn't sent + * so that we can compensate next time ? + */ + mo = m; + end = 1; + } else { + mo = mbuf_Alloc(dl->mp.weight, MB_MP); + mo->cnt = dl->mp.weight; + len -= mo->cnt; + m = mbuf_Read(m, MBUF_CTOP(mo), mo->cnt); + } + mp_Output(mp, &dl->physical->link, mo, begin, end); + begin = 0; + } + + if (!end) { + nlinks--; + dl = dl->next; + if (!dl) { + dl = bundle->links; + thislink = 0; + } else + thislink++; + } + } + } + mp->out.link = thislink; /* Start here next time */ + + return total; +} + +int +mp_SetDatalinkWeight(struct cmdargs const *arg) +{ + int val; + + if (arg->argc != arg->argn+1) + return -1; + + val = atoi(arg->argv[arg->argn]); + if (val < LINK_MINWEIGHT) { + log_Printf(LogWARN, "Link weights must not be less than %d\n", + LINK_MINWEIGHT); + return 1; + } + arg->cx->mp.weight = val; + return 0; +} + +int +mp_ShowStatus(struct cmdargs const *arg) +{ + struct mp *mp = &arg->bundle->ncp.mp; + + prompt_Printf(arg->prompt, "Multilink is %sactive\n", mp->active ? "" : "in"); + if (mp->active) { + struct mbuf *m; + int bufs = 0; + + prompt_Printf(arg->prompt, "Socket: %s\n", + mp->server.socket.sun_path); + for (m = mp->inbufs; m; m = m->pnext) + bufs++; + prompt_Printf(arg->prompt, "Pending frags: %d\n", bufs); + } + + prompt_Printf(arg->prompt, "\nMy Side:\n"); + if (mp->active) { + prompt_Printf(arg->prompt, " MRRU: %u\n", mp->local_mrru); + prompt_Printf(arg->prompt, " Short Seq: %s\n", + mp->local_is12bit ? "on" : "off"); + } + prompt_Printf(arg->prompt, " Discriminator: %s\n", + mp_Enddisc(mp->cfg.enddisc.class, mp->cfg.enddisc.address, + mp->cfg.enddisc.len)); + + prompt_Printf(arg->prompt, "\nHis Side:\n"); + if (mp->active) { + prompt_Printf(arg->prompt, " Auth Name: %s\n", mp->peer.authname); + prompt_Printf(arg->prompt, " Next SEQ: %u\n", mp->out.seq); + prompt_Printf(arg->prompt, " MRRU: %u\n", mp->peer_mrru); + prompt_Printf(arg->prompt, " Short Seq: %s\n", + mp->peer_is12bit ? "on" : "off"); + } + prompt_Printf(arg->prompt, " Discriminator: %s\n", + mp_Enddisc(mp->peer.enddisc.class, mp->peer.enddisc.address, + mp->peer.enddisc.len)); + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + + prompt_Printf(arg->prompt, " MRRU: "); + if (mp->cfg.mrru) + prompt_Printf(arg->prompt, "%d (multilink enabled)\n", mp->cfg.mrru); + else + prompt_Printf(arg->prompt, "disabled\n"); + prompt_Printf(arg->prompt, " Short Seq: %s\n", + command_ShowNegval(mp->cfg.shortseq)); + + return 0; +} + +const char * +mp_Enddisc(u_char c, const char *address, int len) +{ + static char result[100]; /* Used immediately after it's returned */ + int f, header; + + switch (c) { + case ENDDISC_NULL: + sprintf(result, "Null Class"); + break; + + case ENDDISC_LOCAL: + snprintf(result, sizeof result, "Local Addr: %.*s", len, address); + break; + + case ENDDISC_IP: + if (len == 4) + snprintf(result, sizeof result, "IP %s", + inet_ntoa(*(const struct in_addr *)address)); + else + sprintf(result, "IP[%d] ???", len); + break; + + case ENDDISC_MAC: + if (len == 6) { + const u_char *m = (const u_char *)address; + snprintf(result, sizeof result, "MAC %02x:%02x:%02x:%02x:%02x:%02x", + m[0], m[1], m[2], m[3], m[4], m[5]); + } else + sprintf(result, "MAC[%d] ???", len); + break; + + case ENDDISC_MAGIC: + sprintf(result, "Magic: 0x"); + header = strlen(result); + if (len > sizeof result - header - 1) + len = sizeof result - header - 1; + for (f = 0; f < len; f++) + sprintf(result + header + 2 * f, "%02x", address[f]); + break; + + case ENDDISC_PSN: + snprintf(result, sizeof result, "PSN: %.*s", len, address); + break; + + default: + sprintf(result, "%d: ", (int)c); + header = strlen(result); + if (len > sizeof result - header - 1) + len = sizeof result - header - 1; + for (f = 0; f < len; f++) + sprintf(result + header + 2 * f, "%02x", address[f]); + break; + } + return result; +} + +int +mp_SetEnddisc(struct cmdargs const *arg) +{ + struct mp *mp = &arg->bundle->ncp.mp; + struct in_addr addr; + + if (bundle_Phase(arg->bundle) != PHASE_DEAD) { + log_Printf(LogWARN, "set enddisc: Only available at phase DEAD\n"); + return 1; + } + + if (arg->argc == arg->argn) { + mp->cfg.enddisc.class = 0; + *mp->cfg.enddisc.address = '\0'; + mp->cfg.enddisc.len = 0; + } else if (arg->argc > arg->argn) { + if (!strcasecmp(arg->argv[arg->argn], "label")) { + mp->cfg.enddisc.class = ENDDISC_LOCAL; + strcpy(mp->cfg.enddisc.address, arg->bundle->cfg.label); + mp->cfg.enddisc.len = strlen(mp->cfg.enddisc.address); + } else if (!strcasecmp(arg->argv[arg->argn], "ip")) { + if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY) + addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr; + else + addr = arg->bundle->ncp.ipcp.my_ip; + memcpy(mp->cfg.enddisc.address, &addr.s_addr, sizeof addr.s_addr); + mp->cfg.enddisc.class = ENDDISC_IP; + mp->cfg.enddisc.len = sizeof arg->bundle->ncp.ipcp.my_ip.s_addr; + } else if (!strcasecmp(arg->argv[arg->argn], "mac")) { + struct sockaddr_dl hwaddr; + int s; + + if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY) + addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr; + else + addr = arg->bundle->ncp.ipcp.my_ip; + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "set enddisc: socket(): %s\n", strerror(errno)); + return 2; + } + if (get_ether_addr(s, addr, &hwaddr)) { + mp->cfg.enddisc.class = ENDDISC_MAC; + memcpy(mp->cfg.enddisc.address, hwaddr.sdl_data + hwaddr.sdl_nlen, + hwaddr.sdl_alen); + mp->cfg.enddisc.len = hwaddr.sdl_alen; + } else { + log_Printf(LogWARN, "set enddisc: Can't locate MAC address for %s\n", + inet_ntoa(addr)); + close(s); + return 4; + } + close(s); + } else if (!strcasecmp(arg->argv[arg->argn], "magic")) { + int f; + + randinit(); + for (f = 0; f < 20; f += sizeof(long)) + *(long *)(mp->cfg.enddisc.address + f) = random(); + mp->cfg.enddisc.class = ENDDISC_MAGIC; + mp->cfg.enddisc.len = 20; + } else if (!strcasecmp(arg->argv[arg->argn], "psn")) { + if (arg->argc > arg->argn+1) { + mp->cfg.enddisc.class = ENDDISC_PSN; + strcpy(mp->cfg.enddisc.address, arg->argv[arg->argn+1]); + mp->cfg.enddisc.len = strlen(mp->cfg.enddisc.address); + } else { + log_Printf(LogWARN, "PSN endpoint requires additional data\n"); + return 5; + } + } else { + log_Printf(LogWARN, "%s: Unrecognised endpoint type\n", + arg->argv[arg->argn]); + return 6; + } + } + + return 0; +} + +static int +mpserver_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, + int *n) +{ + struct mpserver *s = descriptor2mpserver(d); + int result; + + result = 0; + if (s->send.dl != NULL) { + /* We've connect()ed */ + if (!link_QueueLen(&s->send.dl->physical->link) && + !s->send.dl->physical->out) { + /* Only send if we've transmitted all our data (i.e. the ConfigAck) */ + result -= datalink_RemoveFromSet(s->send.dl, r, w, e); + bundle_SendDatalink(s->send.dl, s->fd, &s->socket); + s->send.dl = NULL; + s->fd = -1; + } else + /* Never read from a datalink that's on death row ! */ + result -= datalink_RemoveFromSet(s->send.dl, r, NULL, NULL); + } else if (r && s->fd >= 0) { + if (*n < s->fd + 1) + *n = s->fd + 1; + FD_SET(s->fd, r); + log_Printf(LogTIMER, "mp: fdset(r) %d\n", s->fd); + result++; + } + return result; +} + +static int +mpserver_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct mpserver *s = descriptor2mpserver(d); + return s->fd >= 0 && FD_ISSET(s->fd, fdset); +} + +static void +mpserver_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct mpserver *s = descriptor2mpserver(d); + struct sockaddr in; + int fd, size; + + size = sizeof in; + fd = accept(s->fd, &in, &size); + if (fd < 0) { + log_Printf(LogERROR, "mpserver_Read: accept(): %s\n", strerror(errno)); + return; + } + + if (in.sa_family == AF_LOCAL) + bundle_ReceiveDatalink(bundle, fd, (struct sockaddr_un *)&in); + else + close(fd); +} + +static int +mpserver_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + /* We never want to write here ! */ + log_Printf(LogALERT, "mpserver_Write: Internal error: Bad call !\n"); + return 0; +} + +void +mpserver_Init(struct mpserver *s) +{ + s->desc.type = MPSERVER_DESCRIPTOR; + s->desc.UpdateSet = mpserver_UpdateSet; + s->desc.IsSet = mpserver_IsSet; + s->desc.Read = mpserver_Read; + s->desc.Write = mpserver_Write; + s->send.dl = NULL; + s->fd = -1; + memset(&s->socket, '\0', sizeof s->socket); +} + +int +mpserver_Open(struct mpserver *s, struct peerid *peer) +{ + int f, l; + mode_t mask; + + if (s->fd != -1) { + log_Printf(LogALERT, "Internal error ! mpserver already open\n"); + mpserver_Close(s); + } + + l = snprintf(s->socket.sun_path, sizeof s->socket.sun_path, "%sppp-%s-%02x-", + _PATH_VARRUN, peer->authname, peer->enddisc.class); + + for (f = 0; f < peer->enddisc.len && l < sizeof s->socket.sun_path - 2; f++) { + snprintf(s->socket.sun_path + l, sizeof s->socket.sun_path - l, + "%02x", *(u_char *)(peer->enddisc.address+f)); + l += 2; + } + + s->socket.sun_family = AF_LOCAL; + s->socket.sun_len = sizeof s->socket; + s->fd = ID0socket(PF_LOCAL, SOCK_STREAM, 0); + if (s->fd < 0) { + log_Printf(LogERROR, "mpserver: socket: %s\n", strerror(errno)); + return MPSERVER_FAILED; + } + + setsockopt(s->fd, SOL_SOCKET, SO_REUSEADDR, (struct sockaddr *)&s->socket, + sizeof s->socket); + mask = umask(0177); + if (ID0bind_un(s->fd, &s->socket) < 0) { + if (errno != EADDRINUSE) { + log_Printf(LogPHASE, "mpserver: can't create bundle socket %s (%s)\n", + s->socket.sun_path, strerror(errno)); + umask(mask); + close(s->fd); + s->fd = -1; + return MPSERVER_FAILED; + } + umask(mask); + if (ID0connect_un(s->fd, &s->socket) < 0) { + log_Printf(LogPHASE, "mpserver: can't connect to bundle socket %s (%s)\n", + s->socket.sun_path, strerror(errno)); + if (errno == ECONNREFUSED) + log_Printf(LogPHASE, " Has the previous server died badly ?\n"); + close(s->fd); + s->fd = -1; + return MPSERVER_FAILED; + } + + /* Donate our link to the other guy */ + return MPSERVER_CONNECTED; + } + + /* Listen for other ppp invocations that want to donate links */ + if (listen(s->fd, 5) != 0) { + log_Printf(LogERROR, "mpserver: Unable to listen to socket" + " - BUNDLE overload?\n"); + mpserver_Close(s); + } + + return MPSERVER_LISTENING; +} + +void +mpserver_Close(struct mpserver *s) +{ + if (s->send.dl != NULL) { + bundle_SendDatalink(s->send.dl, s->fd, &s->socket); + s->send.dl = NULL; + s->fd = -1; + } else if (s->fd >= 0) { + close(s->fd); + if (ID0unlink(s->socket.sun_path) == -1) + log_Printf(LogERROR, "%s: Failed to remove: %s\n", s->socket.sun_path, + strerror(errno)); + memset(&s->socket, '\0', sizeof s->socket); + s->fd = -1; + } +} + +void +mp_LinkLost(struct mp *mp, struct datalink *dl) +{ + if (mp->seq.min_in == dl->mp.seq) + /* We've lost the link that's holding everything up ! */ + mp_Input(mp, NULL, NULL); +} + +void +mp_DeleteQueue(struct mp *mp) +{ + link_DeleteQueue(&mp->link); +} diff --git a/usr.sbin/ppp/ppp/mp.h b/usr.sbin/ppp/ppp/mp.h new file mode 100644 index 00000000000..7bf1aa30755 --- /dev/null +++ b/usr.sbin/ppp/ppp/mp.h @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: mp.h,v 1.1 1998/08/31 00:22:25 brian Exp $ + */ + +struct mbuf; +struct physical; +struct bundle; +struct cmdargs; +struct datalink; + +#define ENDDISC_NULL 0 +#define ENDDISC_LOCAL 1 +#define ENDDISC_IP 2 +#define ENDDISC_MAC 3 +#define ENDDISC_MAGIC 4 +#define ENDDISC_PSN 5 + +#define MP_LINKSENT 0 /* We attached the link to another ppp */ +#define MP_UP 1 /* We've started MP */ +#define MP_ADDED 2 /* We've added the link to our MP */ +#define MP_FAILED 3 /* No go */ + +#define MPSERVER_CONNECTED 0 +#define MPSERVER_LISTENING 1 +#define MPSERVER_FAILED 2 + +struct enddisc { + u_char class; + char address[50]; + int len; +}; + +struct peerid { + struct enddisc enddisc; /* Peers endpoint discriminator */ + char authname[50]; /* Peers name (authenticated) */ +}; + +struct mpserver { + struct descriptor desc; + int fd; /* listen()ing or connect()ing here */ + struct sockaddr_un socket; /* On this socket */ + + struct { + struct datalink *dl; /* Send this datalink */ + } send; /* (in UpdateSet()) */ +}; + +struct mp { + struct link link; + + unsigned active : 1; + unsigned peer_is12bit : 1; /* 12/24bit seq nos */ + unsigned local_is12bit : 1; + u_short peer_mrru; + u_short local_mrru; + + struct peerid peer; /* Who are we talking to */ + struct mpserver server; /* Our ``sharing'' socket */ + + struct { + u_int32_t seq; /* next outgoing seq */ + int link; /* Next link to send on */ + } out; + + struct { + u_int32_t min_in; /* minimum received incoming seq */ + u_int32_t next_in; /* next incoming seq to process */ + } seq; + + struct { + u_short mrru; /* Max Reconstructed Receive Unit */ + unsigned shortseq : 2; /* I want short Sequence Numbers */ + struct enddisc enddisc; /* endpoint discriminator */ + } cfg; + + struct mbuf *inbufs; /* Received fragments */ + struct fsm_parent fsmp; /* Our callback functions */ + struct bundle *bundle; /* Parent */ +}; + +struct mp_link { + u_int32_t seq; /* 12 or 24 bit incoming seq */ + int weight; /* bytes to send with each write */ +}; + +struct mp_header { + unsigned begin : 1; + unsigned end : 1; + u_int32_t seq; +}; + +#define descriptor2mpserver(d) \ + ((d)->type == MPSERVER_DESCRIPTOR ? (struct mpserver *)(d) : NULL) +#define mpserver_IsOpen(s) ((s)->fd != -1) + +extern void peerid_Init(struct peerid *); +extern int peerid_Equal(const struct peerid *, const struct peerid *); +extern void mpserver_Init(struct mpserver *); +extern int mpserver_Open(struct mpserver *, struct peerid *); +extern void mpserver_Close(struct mpserver *); +extern void mp_Init(struct mp *, struct bundle *); +extern void mp_linkInit(struct mp_link *); +extern int mp_Up(struct mp *, struct datalink *); +extern void mp_Down(struct mp *); +extern void mp_Input(struct mp *, struct mbuf *, struct physical *); +extern int mp_FillQueues(struct bundle *); +extern int mp_SetDatalinkWeight(struct cmdargs const *); +extern int mp_ShowStatus(struct cmdargs const *); +extern const char *mp_Enddisc(u_char, const char *, int); +extern int mp_SetEnddisc(struct cmdargs const *); +extern void mp_LinkLost(struct mp *, struct datalink *); +extern void mp_DeleteQueue(struct mp *); diff --git a/usr.sbin/ppp/ppp/pap.c b/usr.sbin/ppp/ppp/pap.c new file mode 100644 index 00000000000..8ebc8a8f8c6 --- /dev/null +++ b/usr.sbin/ppp/ppp/pap.c @@ -0,0 +1,202 @@ +/* + * PPP PAP Module + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993-94, Internet Initiative Japan, Inc. + * All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: pap.c,v 1.1 1998/08/31 00:22:25 brian Exp $ + * + * TODO: + */ +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <string.h> +#include <termios.h> + +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "lcp.h" +#include "auth.h" +#include "pap.h" +#include "lqr.h" +#include "hdlc.h" +#include "lcpproto.h" +#include "async.h" +#include "throughput.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "mp.h" +#include "bundle.h" +#include "chat.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" + +static const char *papcodes[] = { "???", "REQUEST", "SUCCESS", "FAILURE" }; + +void +pap_SendChallenge(struct authinfo *auth, int papid, struct physical *physical) +{ + struct fsmheader lh; + struct mbuf *bp; + u_char *cp; + int namelen, keylen, plen; + + namelen = strlen(physical->dl->bundle->cfg.auth.name); + keylen = strlen(physical->dl->bundle->cfg.auth.key); + plen = namelen + keylen + 2; + log_Printf(LogDEBUG, "pap_SendChallenge: namelen = %d, keylen = %d\n", + namelen, keylen); + log_Printf(LogPHASE, "Pap Output: %s ********\n", + physical->dl->bundle->cfg.auth.name); + if (*physical->dl->bundle->cfg.auth.name == '\0') + log_Printf(LogWARN, "Sending empty PAP authname!\n"); + lh.code = PAP_REQUEST; + lh.id = papid; + lh.length = htons(plen + sizeof(struct fsmheader)); + bp = mbuf_Alloc(plen + sizeof(struct fsmheader), MB_FSM); + memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); + cp = MBUF_CTOP(bp) + sizeof(struct fsmheader); + *cp++ = namelen; + memcpy(cp, physical->dl->bundle->cfg.auth.name, namelen); + cp += namelen; + *cp++ = keylen; + memcpy(cp, physical->dl->bundle->cfg.auth.key, keylen); + + hdlc_Output(&physical->link, PRI_LINK, PROTO_PAP, bp); +} + +static void +SendPapCode(int id, int code, const char *message, struct physical *physical) +{ + struct fsmheader lh; + struct mbuf *bp; + u_char *cp; + int plen, mlen; + + lh.code = code; + lh.id = id; + mlen = strlen(message); + plen = mlen + 1; + lh.length = htons(plen + sizeof(struct fsmheader)); + bp = mbuf_Alloc(plen + sizeof(struct fsmheader), MB_FSM); + memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); + cp = MBUF_CTOP(bp) + sizeof(struct fsmheader); + *cp++ = mlen; + memcpy(cp, message, mlen); + log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]); + hdlc_Output(&physical->link, PRI_LINK, PROTO_PAP, bp); +} + +/* + * Validate given username and passwrd against with secret table + */ +static int +PapValidate(struct bundle *bundle, u_char *name, u_char *key, + struct physical *physical) +{ + int nlen, klen; + + nlen = *name++; + klen = *key; + *key++ = 0; + key[klen] = 0; + log_Printf(LogDEBUG, "PapValidate: name %s (%d), key %s (%d)\n", + name, nlen, key, klen); + + return auth_Validate(bundle, name, key, physical); +} + +void +pap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) +{ + int len = mbuf_Length(bp); + struct fsmheader *php; + u_char *cp; + + if (len >= sizeof(struct fsmheader)) { + php = (struct fsmheader *) MBUF_CTOP(bp); + if (len >= ntohs(php->length)) { + if (php->code < PAP_REQUEST || php->code > PAP_NAK) + php->code = 0; + switch (php->code) { + case PAP_REQUEST: + cp = (u_char *) (php + 1); + log_Printf(LogPHASE, "Pap Input: %s (%.*s)\n", + papcodes[php->code], *cp, cp + 1); + if (PapValidate(bundle, cp, cp + *cp + 1, physical)) { + datalink_GotAuthname(physical->dl, cp+1, *cp); + SendPapCode(php->id, PAP_ACK, "Greetings!!", physical); + physical->link.lcp.auth_ineed = 0; + if (Enabled(bundle, OPT_UTMP)) + physical_Login(physical, cp + 1); + + if (physical->link.lcp.auth_iwait == 0) + /* + * Either I didn't need to authenticate, or I've already been + * told that I got the answer right. + */ + datalink_AuthOk(physical->dl); + + } else { + SendPapCode(php->id, PAP_NAK, "Login incorrect", physical); + datalink_AuthNotOk(physical->dl); + } + break; + case PAP_ACK: + auth_StopTimer(&physical->dl->pap); + cp = (u_char *) (php + 1); + len = *cp++; + cp[len] = 0; + log_Printf(LogPHASE, "Pap Input: %s (%s)\n", papcodes[php->code], cp); + if (physical->link.lcp.auth_iwait == PROTO_PAP) { + physical->link.lcp.auth_iwait = 0; + if (physical->link.lcp.auth_ineed == 0) + /* + * We've succeeded in our ``login'' + * If we're not expecting the peer to authenticate (or he already + * has), proceed to network phase. + */ + datalink_AuthOk(physical->dl); + } + break; + case PAP_NAK: + auth_StopTimer(&physical->dl->pap); + cp = (u_char *) (php + 1); + len = *cp++; + cp[len] = 0; + log_Printf(LogPHASE, "Pap Input: %s (%s)\n", papcodes[php->code], cp); + datalink_AuthNotOk(physical->dl); + break; + } + } + } + mbuf_Free(bp); +} diff --git a/usr.sbin/ppp/pap.h b/usr.sbin/ppp/ppp/pap.h index 60862b826ed..a07e2ba9d41 100644 --- a/usr.sbin/ppp/pap.h +++ b/usr.sbin/ppp/ppp/pap.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pap.h,v 1.1 1997/11/23 20:27:35 brian Exp $ + * $Id: pap.h,v 1.1 1998/08/31 00:22:25 brian Exp $ * * TODO: */ @@ -24,6 +24,10 @@ #define PAP_ACK 2 #define PAP_NAK 3 -extern struct authinfo AuthPapInfo; +struct mbuf; +struct physical; +struct authinfo; +struct bundle; -extern void PapInput(struct mbuf *); +extern void pap_Input(struct bundle *, struct mbuf *, struct physical *); +extern void pap_SendChallenge(struct authinfo *, int, struct physical *); diff --git a/usr.sbin/ppp/ppp/physical.c b/usr.sbin/ppp/ppp/physical.c new file mode 100644 index 00000000000..9cf0b29d9cd --- /dev/null +++ b/usr.sbin/ppp/ppp/physical.c @@ -0,0 +1,239 @@ +/* + * Written by Eivind Eklund <eivind@yes.no> + * for Yes Interactive + * + * Copyright (C) 1998, Yes Interactive. All rights reserved. + * + * Redistribution and use in any form is permitted. Redistribution in + * source form should include the above copyright and this set of + * conditions, because large sections american law seems to have been + * created by a bunch of jerks on drugs that are now illegal, forcing + * me to include this copyright-stuff instead of placing this in the + * public domain. The name of of 'Yes Interactive' or 'Eivind Eklund' + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: physical.c,v 1.1 1998/08/31 00:22:25 brian Exp $ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <utmp.h> +#include <sys/tty.h> + +#include "defs.h" +#include "mbuf.h" +#include "timer.h" +#include "lqr.h" +#include "hdlc.h" +#include "throughput.h" +#include "fsm.h" +#include "lcp.h" +#include "async.h" +#include "ccp.h" +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "log.h" +#include "id.h" + +/* External calls - should possibly be moved inline */ +extern int IntToSpeed(int); + + +int +physical_GetFD(struct physical *phys) { + return phys->fd; +} + +int +physical_IsATTY(struct physical *phys) { + return isatty(phys->fd); +} + +int +physical_IsSync(struct physical *phys) { + return phys->cfg.speed == 0; +} + +const char *physical_GetDevice(struct physical *phys) +{ + return phys->name.full; +} + +void +physical_SetDeviceList(struct physical *p, int argc, const char *const *argv) +{ + int f, pos; + + p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0'; + for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) { + if (pos) + p->cfg.devlist[pos++] = ' '; + strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1); + pos += strlen(p->cfg.devlist + pos); + } +} + + +int +physical_SetSpeed(struct physical *phys, int speed) { + if (IntToSpeed(speed) != B0) { + phys->cfg.speed = speed; + return 1; + } else { + return 0; + } +} + +void +physical_SetSync(struct physical *phys) { + phys->cfg.speed = 0; +} + + +int +physical_SetRtsCts(struct physical *phys, int enable) { + phys->cfg.rts_cts = enable ? 1 : 0; + return 1; +} + +/* Encapsulation for a read on the FD. Avoids some exposure, and + concentrates control. */ +ssize_t +physical_Read(struct physical *phys, void *buf, size_t nbytes) { + return read(phys->fd, buf, nbytes); +} + +ssize_t +physical_Write(struct physical *phys, const void *buf, size_t nbytes) { + return write(phys->fd, buf, nbytes); +} + +int +physical_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, + int *n, int force) +{ + struct physical *p = descriptor2physical(d); + int sets; + + sets = 0; + if (p->fd >= 0) { + if (r) { + FD_SET(p->fd, r); + log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd); + sets++; + } + if (e) { + FD_SET(p->fd, e); + log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd); + sets++; + } + if (w && (force || link_QueueLen(&p->link) || p->out)) { + FD_SET(p->fd, w); + log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd); + sets++; + } + if (sets && *n < p->fd + 1) + *n = p->fd + 1; + } + + return sets; +} + +int +physical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e) +{ + int sets; + + sets = 0; + if (p->fd >= 0) { + if (r && FD_ISSET(p->fd, r)) { + FD_CLR(p->fd, r); + log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd); + sets++; + } + if (e && FD_ISSET(p->fd, e)) { + FD_CLR(p->fd, e); + log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd); + sets++; + } + if (w && FD_ISSET(p->fd, w)) { + FD_CLR(p->fd, w); + log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd); + sets++; + } + } + + return sets; +} + +int +physical_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct physical *p = descriptor2physical(d); + return p->fd >= 0 && FD_ISSET(p->fd, fdset); +} + +void +physical_Login(struct physical *phys, const char *name) +{ + if (phys->type == PHYS_DIRECT && physical_IsATTY(phys)) { + if (phys->Utmp) + log_Printf(LogERROR, "Oops, already logged in on %s\n", phys->name.base); + else { + struct utmp ut; + const char *connstr; + + memset(&ut, 0, sizeof ut); + time(&ut.ut_time); + strncpy(ut.ut_name, name, sizeof ut.ut_name); + strncpy(ut.ut_line, phys->name.base, sizeof ut.ut_line); + if ((connstr = getenv("CONNECT"))) + /* mgetty sets this to the connection speed */ + strncpy(ut.ut_host, connstr, sizeof ut.ut_host); + ID0login(&ut); + phys->Utmp = 1; + } + } +} + +void +physical_Logout(struct physical *phys) +{ + if (phys->Utmp) { + ID0logout(phys->name.base); + phys->Utmp = 0; + } +} + +int +physical_SetMode(struct physical *p, int mode) +{ + if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) || + mode & (PHYS_DIRECT|PHYS_DEDICATED)) && + (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) { + log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name, + mode2Nam(p->type), mode2Nam(mode)); + return 0; + } + p->type = mode; + return 1; +} + +void +physical_DeleteQueue(struct physical *p) +{ + if (p->out) { + mbuf_Free(p->out); + p->out = NULL; + } + link_DeleteQueue(&p->link); +} diff --git a/usr.sbin/ppp/ppp/physical.h b/usr.sbin/ppp/ppp/physical.h new file mode 100644 index 00000000000..0081963ad42 --- /dev/null +++ b/usr.sbin/ppp/ppp/physical.h @@ -0,0 +1,103 @@ +/* + * Written by Eivind Eklund <eivind@yes.no> + * for Yes Interactive + * + * Copyright (C) 1998, Yes Interactive. All rights reserved. + * + * Redistribution and use in any form is permitted. Redistribution in + * source form should include the above copyright and this set of + * conditions, because large sections american law seems to have been + * created by a bunch of jerks on drugs that are now illegal, forcing + * me to include this copyright-stuff instead of placing this in the + * public domain. The name of of 'Yes Interactive' or 'Eivind Eklund' + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: physical.h,v 1.1 1998/08/31 00:22:25 brian Exp $ + * + */ + +struct bundle; + +struct physical { + struct link link; + struct descriptor desc; + int type; /* What sort of PHYS_* link are we ? */ + struct async async; /* Our async state */ + struct hdlc hdlc; /* Our hdlc state */ + int fd; /* File descriptor for this device */ + int mbits; /* Current DCD status */ + unsigned dev_is_modem : 1; /* Is the device an actual modem? + Faked for sync devices, though... + (Possibly this should be + dev_is_not_tcp?) XXX-ML */ + + struct mbuf *out; /* mbuf that suffered a short write */ + int connect_count; + struct datalink *dl; /* my owner */ + + struct { + char full[40]; + char *base; + } name; + + unsigned Utmp : 1; /* Are we in utmp ? */ + pid_t session_owner; /* HUP this when closing the link */ + + /* XXX-ML Most of the below is device specific, and probably do not + belong in the generic physical struct. It comes from modem.c. */ + + struct { + unsigned rts_cts : 1; /* Is rts/cts enabled? */ + unsigned parity; /* What parity is enabled? (TTY flags) */ + unsigned speed; /* Modem speed */ + char devlist[LINE_LEN]; /* Comma-separated list of devices */ + } cfg; + + struct termios ios; /* To be able to reset from raw mode */ + + struct pppTimer Timer; /* CD checks */ +}; + +#define field2phys(fp, name) \ + ((struct physical *)((char *)fp - (int)(&((struct physical *)0)->name))) + +#define link2physical(l) \ + ((l)->type == PHYSICAL_LINK ? field2phys(l, link) : NULL) + +#define descriptor2physical(d) \ + ((d)->type == PHYSICAL_DESCRIPTOR ? field2phys(d, desc) : NULL) + +extern int physical_GetFD(struct physical *); +extern int physical_IsATTY(struct physical *); +extern int physical_IsSync(struct physical *); +extern const char *physical_GetDevice(struct physical *); +extern void physical_SetDeviceList(struct physical *, int, const char *const *); +extern int physical_SetSpeed(struct physical *, int); + +/* + * XXX-ML I'm not certain this is the right way to handle this, but we + * can solve that later. + */ +extern void physical_SetSync(struct physical *); + +/* + * Can this be set? (Might not be a relevant attribute for this + * device, for instance) + */ +extern int physical_SetRtsCts(struct physical *, int); + +extern ssize_t physical_Read(struct physical *, void *, size_t); +extern ssize_t physical_Write(struct physical *, const void *, size_t); +extern int physical_UpdateSet(struct descriptor *, fd_set *, fd_set *, + fd_set *, int *, int); +extern int physical_IsSet(struct descriptor *, const fd_set *); +extern void physical_Login(struct physical *, const char *); +extern void physical_Logout(struct physical *); +extern int physical_RemoveFromSet(struct physical *, fd_set *, fd_set *, + fd_set *); +extern int physical_SetMode(struct physical *, int); +extern void physical_DeleteQueue(struct physical *); diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp/ppp.8 index b3948ab7d82..135ce08d56e 100644 --- a/usr.sbin/ppp/ppp.8 +++ b/usr.sbin/ppp/ppp/ppp.8 @@ -1,10 +1,10 @@ -.\" $Id: ppp.8,v 1.20 1998/06/12 17:45:14 brian Exp $ +.\" $Id: ppp.8,v 1.1 1998/08/31 00:22:26 brian Exp $ .Dd 20 September 1995 -.Os OpenBSD +.Os FreeBSD .Dt PPP 8 .Sh NAME .Nm ppp -.Nd Point to Point Protocol (a.k.a. iijppp) +.Nd Point to Point Protocol (a.k.a. user-ppp) .Sh SYNOPSIS .Nm .Oo @@ -74,6 +74,10 @@ command via its diagnostic socket. A will force an LCP renegotiation, and a .Dv SIGTERM will force it to exit. +.It Supports client callback. +.Nm Ppp +can use either the standard LCP callback protocol or the Microsoft +CallBack Control Protocol (ftp://ftp.microsoft.com/developr/rfc/cbcp.txt). .It Supports packet aliasing. Packet aliasing (a.k.a. IP masquerading) allows computers on a private, unregistered network to access the Internet. The @@ -97,24 +101,28 @@ connections on stdin/stdout. .It Supports PAP and CHAP authentication. With PAP or CHAP, it is possible to skip the Unix style .Xr login 1 -proceedure, and use the +procedure, and use the .Em PPP -protocol for authentication instead. +protocol for authentication instead. If the peer requests Microsoft +CHAP authentication and +.Nm +is compiled with DES support, an appropriate MD4/DES response will be +made. .It Supports Proxy Arp. When .Em PPP is set up as server, you can also configure it to do proxy arp for your connection. .It Supports packet filtering. -User can define four kinds of filters: -.Em ifilter -for incoming packets, -.Em ofilter -for outgoing packets, -.Em dfilter -to define a dialing trigger packet and -.Em afilter -for keeping a connection alive with the trigger packet. +User can define four kinds of filters: the +.Em in +filter for incoming packets, the +.Em out +filter for outgoing packets, the +.Em dial +filter to define a dialing trigger packet and the +.Em alive +filter for keeping a connection alive with the trigger packet. .It Tunnel driver supports bpf. The user can use .Xr tcpdump 1 @@ -122,23 +130,35 @@ to check the packet flow over the .Em PPP link. .It Supports PPP over TCP capability. -.It Supports IETF draft Predictor-1 compression. +If a device name is specified as +.Em host Ns No : Ns Em port , +.Nm +will open a TCP connection for transporting data rather than using a +conventional serial device. +.It Supports IETF draft Predictor-1 and DEFLATE compression. .Nm -supports not only VJ-compression but also Predictor-1 compression. +supports not only VJ-compression but also Predictor-1 and DEFLATE compression. Normally, a modem has built-in compression (e.g. v42.bis) and the system may receive higher data rates from it as a result of such compression. While this is generally a good thing in most other situations, this higher speed data imposes a penalty on the system by increasing the number of serial interrupts the system has to process in talking to the -modem and also increases latency. Unlike VJ-compression, Predictor-1 -compression pre-compresses +modem and also increases latency. Unlike VJ-compression, Predictor-1 and +DEFLATE compression pre-compresses .Em all -data flowing through the link, thus reducing overhead to a minimum. +network traffic flowing through the link, thus reducing overheads to a +minimum. .It Supports Microsoft's IPCP extensions. Name Server Addresses and NetBIOS Name Server Addresses can be negotiated with clients using the Microsoft .Em PPP stack (ie. Win95, WinNT) +.It Supports Multi-link PPP +It is possible to configure +.Nm +to open more than one physical connection to the peer, combining the +bandwidth of all links for better throughput. +.El .Sh PERMISSIONS .Nm Ppp is installed as user @@ -146,7 +166,7 @@ is installed as user and group .Dv network , with permissions -.Dv 4550 . +.Dv 4554 . By default, .Nm will not run if the invoking user id is not zero. This may be overridden @@ -168,8 +188,10 @@ zero. .Sh GETTING STARTED When you first run .Nm -you may need to deal with some initial configuration details. First, -your kernel should include a tunnel device (the GENERIC kernel includes +you may need to deal with some initial configuration details. +.Bl -bullet +.It +Your kernel must include a tunnel device (the GENERIC kernel includes one by default). If it doesn't, or if you require more than one tun interface, you'll need to rebuild your kernel with the following line in your kernel configuration file: @@ -181,7 +203,8 @@ where is the maximum number of .Em PPP connections you wish to support. -Second, check your +.It +Check your .Pa /dev directory for the tunnel device entries .Pa /dev/tunN , @@ -191,7 +214,22 @@ represents the number of the tun device, starting at zero. If they don't exist, you can create them by running "sh ./MAKEDEV tunN". This will create tun devices 0 through .Ar N . -Last of all, create a log file. +.It +Make sure that your system has a group named +.Dq network +in the +.Pa /etc/group +file and that that group contains the names of all users expected to use +.Nm ppp . +Refer to the +.Xr group 5 +manual page for details. Each of these uses must also be given access +using the +.Dq allow users +command in +.Pa /etc/ppp/ppp.conf . +.It +Create a log file. .Nm Ppp uses .Xr syslog 3 @@ -206,7 +244,9 @@ file: .Ed .Pp Make sure you use actual TABs here. If you use spaces, the line will be -silently ignored. +silently ignored by +.Xr syslogd 8 . +.Pp It is possible to have more than one .Em PPP log file by creating a link to the @@ -219,7 +259,7 @@ executable: and using .Bd -literal -offset indent !ppp0 -*.* /var/log/ppp0.log +*.*<TAB>/var/log/ppp0.log .Ed .Pp in @@ -230,6 +270,29 @@ signal to .Xr syslogd 8 after altering .Pa /etc/syslog.conf . +.It +Although not strictly relevant to +.Nm ppp Ns No s +operation, you should configure your resolver so that it works correctly. +This can be done by configuring a local DNS +.Pq using Xr named 8 +or by adding the correct +.Sq name-server +lines to the file +.Pa /etc/resolv.conf . +Refer to the +.Xr resolv.conf 5 +manual page for details. +.Pp +Alternatively, if the peer supports it, +.Nm +can be configured to ask the peer for the nameserver address(es) and to +update +.Pa /etc/resolv.conf +automatically. Refer to the +.Dq enable dns +command below for details. +.El .Sh MANUAL DIALING In the following examples, we assume that your machine name is .Dv awfulhak . @@ -288,19 +351,48 @@ When the peer starts to talk in detects this automatically and returns to command mode. .Bd -literal -offset indent ppp ON awfulhak> +Ppp ON awfulhak> +PPp ON awfulhak> PPP ON awfulhak> .Ed .Pp +If it does not, it's possible that the peer is waiting for your end to +start negotiating. To force +.Nm +to start sending PPP configuration packets to the peer, use the +.Dq ~p +command to enter packet mode. +.Pp You are now connected! Note that .Sq PPP in the prompt has changed to capital letters to indicate that you have -a peer connection. The show command can be used to see how things are -going: +a peer connection. If only some of the three Ps go uppercase, wait 'till +either everything is uppercase or lowercase. If they revert to lowercase, +it means that +.Nm +couldn't successfully negotiate with the peer. This is probably because +your PAP or CHAP authentication name or key is incorrect. A good first step +for troubleshooting at this point would be to +.Dq set log local phase . +Refer to the +.Dq set log +command description below for further details. +.Pp +When the link is established, the show command can be used to see how +things are going: .Bd -literal -offset indent +PPP ON awfulhak> show modem +* Modem related information is shown here * +PPP ON awfulhak> show ccp +* CCP (compression) related information is shown here * PPP ON awfulhak> show lcp -* LCP related information is shown here * +* LCP (line control) related information is shown here * PPP ON awfulhak> show ipcp -* IPCP related information is shown here * +* IPCP (IP) related information is shown here * +PPP ON awfulhak> show link +* Link (high level) related information is shown here * +PPP ON awfulhak> show bundle +* Logical (high level) connection related information is shown here * .Ed .Pp At this point, your machine has a host route to the peer. This means @@ -322,6 +414,12 @@ use the keyword in place of .Sq HISADDR . This will create a direct route on the tun interface. +If it fails due to an existing route, you can overwrite the existing +route using +.Bd -literal -offset indent +PPP ON awfulhak> add! default HISADDR +.Ed +.Pp You can now use your network applications (ping, telnet, ftp etc.) in other windows on your machine. Refer to the @@ -335,7 +433,7 @@ See the example definitions in .Pa /etc/ppp/ppp.conf is pretty simple). Each line contains one comment, inclusion, label or command: -.Bl -bullet -compact +.Bl -bullet .It A line starting with a .Pq Dq # @@ -393,11 +491,20 @@ portion of the prompt will change to # ppp MyISP ... ppp ON awfulhak> dial -dial OK! -login OK! +Ppp ON awfulhak> +PPp ON awfulhak> PPP ON awfulhak> .Ed .Pp +The Ppp prompt indicates that +.Nm +has entered the authentication phase. The PPp prompt indicates that +.Nm +has entered the network phase. The PPP prompt indicates that +.Nm +has successfully negotiated a network layer protocol and is in +a usable state. +.Pp If the .Pa /etc/ppp/ppp.linkup file is available, its contents are executed @@ -407,18 +514,37 @@ connection is established. See the provided .Dq pmdemand example in .Pa /etc/ppp/ppp.conf.sample -which adds a default route. The strings +which runs a script in the background after the connection is established. +The literal strings .Dv HISADDR , .Dv MYADDR and .Dv INTERFACE -are available as the relevent IP addresses and interface name. -Similarly, when a connection is closed, the +may be used, and will be replaced with the relevant IP addresses and interface +name. Similarly, when a connection is closed, the contents of the .Pa /etc/ppp/ppp.linkdown file are executed. Both of these files have the same format as .Pa /etc/ppp/ppp.conf . +.Pp +In previous versions of +.Nm ppp , +it was necessary to re-add routes such as the default route in the +.Pa ppp.linkup +file. +.Nm Ppp +now supports +.Sq sticky routes , +where all routes that contain the +.Dv HISADDR +or +.Dv MYADDR +literals will automatically be updated when the values of +.Dv HISADDR +and/or +.Dv MYADDR +change. .Sh BACKGROUND DIALING If you want to establish a connection using .Nm @@ -428,12 +554,7 @@ entry or an .Xr at 1 job) you should use the .Fl background -option. You must also specify the destination label in -.Pa /etc/ppp/ppp.conf -to use. This label must contain the -.Dq set ifaddr -command to define the remote peers IP address. (refer to -.Pa /etc/ppp/ppp.conf.sample ) +option. When .Fl background is specified, @@ -463,8 +584,6 @@ command to define the remote peers IP address. (refer to .Pa /etc/ppp/ppp.conf.sample ) .Bd -literal -offset indent # ppp -auto pmdemand -... -# .Ed .Pp When @@ -474,33 +593,26 @@ or is specified, .Nm runs as a daemon but you can still configure or examine its -configuration by using the diagnostic port as follows (this -can be done in -.Fl background -and -.Fl direct -mode too): +configuration by using the +.Dq set server +command in +.Pa /etc/ppp/ppp.conf , +.Pq for example, Dq set server +3000 mypasswd +and connecting to the diagnostic port as follows: .Bd -literal -offset indent -# pppctl -v 3000 show ipcp +# pppctl 3000 (assuming tun0 - see the ``set server'' description) Password: -IPCP [Opened] - his side: xxxx - .... +PPP ON awfulhak> show who +tcp (127.0.0.1:1028) * .Ed .Pp -Currently, -.Xr telnet 1 -may also be used to talk interactively. -.Pp -In order to achieve this, you must use the -.Dq set server -command as described below. It is possible to retrospectively make a running +The +.Dq show who +command lists users that are currently connected to .Nm -program listen on a diagnostic port by configuring -.Pa /etc/ppp/ppp.secret , -and sending it a -.Dv USR1 -signal. +itself. If the diagnostic socket is closed or changed to a different +socket, all connections are immediately dropped. +.Pp In .Fl auto mode, when an outgoing packet is detected, @@ -637,98 +749,126 @@ to enable a .Xr getty 8 on the port where the modem is attached. For example: +.Pp .Dl ttyd1 "/usr/libexec/getty std.38400" dialup on secure +.Pp Don't forget to send a .Dv HUP signal to the .Xr init 8 process to start the -.Xr getty 8 . -.Dl # kill -HUP 1 -.It -Prepare an account for the incoming user. -.Bd -literal -ppp:xxxx:66:66:PPP Login User:/home/ppp:/usr/local/bin/ppplogin -.Ed +.Xr getty 8 : .Pp +.Dl # kill -HUP 1 .It Create a .Pa /usr/local/bin/ppplogin file with the following contents: .Bd -literal -offset indent -#!/bin/sh -p -exec /usr/sbin/ppp -direct +#! /bin/sh +exec /usr/sbin/ppp -direct incoming .Ed .Pp -(You can specify a label name for further control.) -.Pp Direct mode .Pq Fl direct lets .Nm work with stdin and stdout. You can also use .Xr pppctl 8 -or -.Xr telnet 1 to connect to a configured diagnostic port, in the same manner as with client-side .Nm ppp . +.Pp +Here, the +.Ar incoming +section must be set up in +.Pa /etc/ppp/ppp.conf . +.Pp +Make sure that the +.Ar incoming +section contains the +.Dq allow users +command as appropriate. .It -Optional support for Microsoft's IPCP Name Server and NetBIOS -Name Server negotiation can be enabled use -.Dq enable msext -and -.Dq set ns pri-addr [sec-addr] -along with -.Dq set nbns pri-addr [sec-addr] -in your -.Pa /etc/ppp/ppp.conf -file. +Prepare an account for the incoming user. +.Bd -literal +ppp:xxxx:66:66:PPP Login User:/home/ppp:/usr/local/bin/ppplogin +.Ed +.Pp +Refer to the manual entries for +.Xr adduser 8 +and +.Xr vipw 8 +for details. +.It +Support for IPCP Domain Name Server and NetBIOS Name Server negotiation +can be enabled using the +.Dq accept dns +and +.Dq set nbns +commands. Refer to their descriptions below. .El .Pp .Sh RECEIVING INCOMING PPP CONNECTIONS (Method 2) -This method differs in that it recommends the use of -.Em mgetty+sendfax -to handle the modem connections. The latest versions (0.99 and higher) -can be compiled with the -.Dq AUTO_PPP -option to allow detection of clients speaking -.Em PPP -to the login prompt. -Follow these steps: +This method differs in that we use +.Nm ppp +to authenticate the connection rather than +.Xr login 1 : .Bl -enum .It -Get, configure, and install mgetty+sendfax v0.99 or later making -sure you have used the AUTO_PPP option. +Configure your default section in +.Pa /etc/gettytab +with automatic ppp recognition by specifying the +.Dq pp +capability: +.Bd -literal +default:\\ + :pp=/usr/local/bin/ppplogin:\\ + ..... +.Ed .It -Edit -.Pa /etc/ttys -to enable a mgetty on the port where the modem is attached. For -example: -.Dl cuaa1 "/usr/local/sbin/mgetty -s 57600" dialup on +Configure your serial device(s), enable a +.Xr getty 8 +and create +.Pa /usr/local/bin/ppplogin +as in the first three steps for method 1 above. .It -Prepare an account for the incoming user. +Add either +.Dq enable chap +or +.Dq enable pap +.Pq or both +to +.Pa /etc/ppp/ppp.conf +under the +.Sq incoming +label (or whatever label +.Pa ppplogin +uses). +.It +Create an entry in +.Pa /etc/ppp/ppp.secret +for each incoming user: .Bd -literal -Pfred:xxxx:66:66:Fred's PPP:/home/ppp:/etc/ppp/ppp-dialup +Pfred<TAB>xxxx +Pgeorge<TAB>yyyy .Ed -.Pp -.It -Examine the files -.Pa /etc/ppp/sample.ppp-dialup , -.Pa /etc/ppp/sample.ppp-pap-dialup -and -.Pa /etc/ppp/ppp.conf.sample -for ideas. -.Pa /etc/ppp/ppp-pap-dialup -is supposed to be called from -.Pa /usr/local/etc/mgetty+sendfax/login.conf -from a line like -.Dl /AutoPPP/ - - /etc/ppp/ppp-pap-dialup .El .Pp +Now, as soon as +.Xr getty 8 +detects a ppp connection (by recognising the HDLC frame headers), it runs +.Dq /usr/local/bin/ppplogin . +.Pp +It is +.Em VITAL +that either PAP or CHAP are enabled as above. If they are not, you are +allowing anybody to establish ppp session with your machine +.Em without +a password, opening yourself up to all sorts of potential attacks. .Sh AUTHENTICATING INCOMING CONNECTIONS Normally, the receiver of a connection requires that the peer -authenticates themself. This may be done using +authenticates itself. This may be done using .Xr login 1 , but alternatively, you can use PAP or CHAP. CHAP is the more secure of the two, but some clients may not support it. Once you decide which @@ -736,7 +876,7 @@ you wish to use, add the command .Sq enable chap or .Sq enable pap -to the relevent section of +to the relevant section of .Pa ppp.conf . .Pp You must then configure the @@ -751,7 +891,15 @@ The .Ar name and .Ar key -specify the client as expected. If the client does not offer a suitable +specify the client as expected. If +.Ar key +is +.Dq \&* +and PAP is being used, +.Nm +will look up the password database +.Pq Xr passwd 5 +when authenticating. If the client does not offer a suitable response based on any .Ar name No / Ar key combination in @@ -774,13 +922,15 @@ This will change the subsequent parsing of the and .Pa ppp.linkdown files. -.Sh PPP OVER TCP (a.k.a Tunneling) +.Sh PPP OVER TCP (a.k.a Tunnelling) Instead of running .Nm over a serial link, it is possible to use a TCP connection instead by specifying a host and port as the device: +.Pp .Dl set device ui-gate:6669 +.Pp Instead of opening a serial device, .Nm will open a TCP connection to the given machine on the given @@ -793,13 +943,17 @@ connection on the receiving machine (ui-gate). This is done by first updating .Pa /etc/services to name the service: +.Pp .Dl ppp-in 6669/tcp # Incoming PPP connections over TCP +.Pp and updating .Pa /etc/inetd.conf to tell .Xr inetd 8 how to deal with incoming connections on that port: +.Pp .Dl ppp-in stream tcp nowait root /usr/sbin/ppp ppp -direct ppp-in +.Pp Don't forget to send a .Dv HUP signal to @@ -815,7 +969,7 @@ on ui-gate (the receiver) should contain the following: ppp-in: set timeout 0 set ifaddr 10.0.4.1 10.0.4.2 - add 10.0.1.0 255.255.255.0 10.0.4.2 + add 10.0.1.0/24 10.0.4.2 .Ed .Pp You may also want to enable PAP or CHAP for security. To enable PAP, add @@ -830,6 +984,14 @@ You'll also need to create the following entry in MyAuthName MyAuthPasswd .Ed .Pp +If +.Ar MyAuthPasswd +is a +.Pq Dq * , +the password is looked up in the +.Xr passwd 5 +database. +.Pp The entry in .Pa /etc/ppp/ppp.conf on awfulhak (the initiator) should contain the following: @@ -838,10 +1000,10 @@ ui-gate: set escape 0xff set device ui-gate:ppp-in set dial - set timeout 30 15 5 - set log Phase Chat Connect Carrier hdlc LCP IPCP CCP tun + set timeout 30 + set log Phase Chat Connect hdlc LCP IPCP CCP tun set ifaddr 10.0.4.2 10.0.4.1 - add 10.0.2.0 255.255.255.0 10.0.4.1 + add 10.0.2.0/24 10.0.4.1 .Ed .Pp Again, if you're enabling PAP, you'll also need: @@ -853,7 +1015,9 @@ Again, if you're enabling PAP, you'll also need: We're assigning the address of 10.0.4.1 to ui-gate, and the address 10.0.4.2 to awfulhak. To open the connection, just type +.Pp .Dl awfulhak # ppp -background ui-gate +.Pp The result will be an additional "route" on awfulhak to the 10.0.2.0/24 network via the TCP connection, and an additional "route" on ui-gate to the 10.0.1.0/24 network. @@ -910,35 +1074,98 @@ and that other machines have designated the host as the gateway for the LAN. .Sh PACKET FILTERING This implementation supports packet filtering. There are four kinds of -filters; ifilter, ofilter, dfilter and afilter. Here are the basics: -.Bl -bullet -compact +filters; the +.Em in +filter, the +.Em out +filter, the +.Em dial +filter and the +.Em alive +filter. Here are the basics: +.Bl -bullet .It A filter definition has the following syntax: -set filter-name rule-no action [src_addr/src_width] [dst_addr/dst_width] -[proto [src [lt|eq|gt] port ]] [dst [lt|eq|gt] port] [estab] +.Pp +set filter +.Ar name +.Ar rule-no +.Ar action +.Op Ar src_addr Ns Op / Ns Ar width +.Op Ar dst_addr Ns Op / Ns Ar width +[ +.Ar proto +.Op src Op Ar cmp No Ar port +.Op dst Op Ar cmp No Ar port +.Op estab +.Op syn +.Op finrst +] .Bl -enum .It -.Sq filter-name -should be one of ifilter, ofilter, dfilter or afilter. +.Ar Name +should be one of +.Sq in , +.Sq out , +.Sq dial +or +.Sq alive . .It -There are two actions: -.Sq permit +.Ar Rule-no +is a numeric value between +.Sq 0 and +.Sq 19 +specifying the rule number. Rules are specified in numeric order according to +.Ar rule-no , +but only if rule +.Sq 0 +is defined. +.It +.Ar Action +is either +.Sq permit +or .Sq deny . If a given packet matches the rule, the associated action is taken immediately. .It -.Sq src_width +.Op Ar src_addr Ns Op / Ns Ar width and -.Sq dst_width -work like a netmask to represent an address range. +.Op Ar dst_addr Ns Op / Ns Ar width +are the source and destination IP number specifications. If +.Op / Ns Ar width +is specified, it gives the number of relevant netmask bits, +allowing the specification of an address range. .It -.Sq proto -must be one of icmp, udp or tcp. +.Ar Proto +must be one of +.Sq icmp , +.Sq udp +or +.Sq tcp . .It -.Sq port number -can be specified by number and service name from +.Ar Cmp +is one of +.Sq \< , +.Sq \&eq +or +.Sq \> , +meaning less-than, equal and greater-than respectively. +.Ar Port +can be specified as a numeric port or by service name from .Pa /etc/services . +.It +The +.Sq estab , +.Sq syn , +and +.Sq finrst +flags are only allowed when +.Ar proto +is set to +.Sq tcp , +and represent the TH_ACK, TH_SYN and TH_FIN or TH_RST TCP flags respectively. .El .Pp .It @@ -950,41 +1177,47 @@ If no rule is matched to a packet, that packet will be discarded (blocked). .It Use -.Dq set filter-name -1 +.Dq set filter Ar name No -1 to flush all rules. .El .Pp See -.Pa /etc/ppp/ppp.conf.filter.example . -.Sh SETTING IDLE, LINE QUALITY REQUEST, RETRY TIMER -To check/set idle timer, use the -.Dq show timeout +.Pa /etc/ppp/ppp.conf.example . +.Sh SETTING THE IDLE TIMER +To check/set the idle timer, use the +.Dq show bundle and -.Dq set timeout idle [LQR [FSM-resend]] +.Dq set timeout commands: .Bd -literal -offset indent ppp ON awfulhak> set timeout 600 .Ed .Pp -The timeout period is measured in seconds, the default values for which -are timeout = 180 or 3 min, lqrtimer = 30sec and retrytimer = 3sec. +The timeout period is measured in seconds, the default value for which +is 180 seconds +.Pq or 3 min . To disable the idle timer function, use the command .Bd -literal -offset indent ppp ON awfulhak> set timeout 0 .Ed .Pp In +.Fl ddial +and +.Fl direct +modes, the idle timeout is ignored. In .Fl auto -mode, an idle timeout causes the +mode, when the idle timeout causes the .Em PPP session to be -closed, though the +closed, the .Nm program itself remains running. Another trigger packet will cause it to -attempt to reestablish the link. +attempt to re-establish the link. .Sh PREDICTOR-1 and DEFLATE COMPRESSION -This version supports CCP and Predictor type 1 or deflate compression -based on the current IETF-draft specs. As a default behaviour, +.Nm Ppp +supports both Predictor type 1 and deflate compression. +By default, .Nm will attempt to use (or be willing to accept) both compression protocols when the peer agrees @@ -997,11 +1230,26 @@ and .Dq deny commands if you wish to disable this functionality. .Pp -It is possible to use a different algorithm in each direction by using -only one of +It is possible to use a different compression algorithm in each direction +by using only one of .Dq disable deflate and -.Dq deny deflate . +.Dq deny deflate +.Pq assuming that the peer supports both algorithms . +.Pp +By default, when negotiating DEFLATE, +.Nm +will use a window size of 15. Refer to the +.Dq set deflate +command if you wish to change this behaviour. +.Pp +A special algorithm called DEFLATE24 is also available, and is disabled +and denied by default. This is exactly the same as DEFLATE except that +it uses CCP ID 24 to negotiate. This allows +.Nm +to successfully negotiate DEFLATE with +.Nm pppd +version 2.3.*. .Sh CONTROLLING IP ADDRESS .Nm uses IPCP to negotiate IP addresses. Each side of the connection @@ -1029,15 +1277,18 @@ is the IP address which the remote side should use and .Sq netmask is the netmask that should be used. .Sq Src_addr -and +defaults to the current +.Xr hostname 1 , .Sq dst_addr -default to 0.0.0.0, and +defaults to 0.0.0.0, and .Sq netmask defaults to whatever mask is appropriate for .Sq src_addr . It is only possible to make .Sq netmask -smaller than the default. The usual value is 255.255.255.255. +smaller than the default. The usual value is 255.255.255.255, as +most kernels ignore the netmask of a POINTOPOINT interface. +.Pp Some incorrect .Em PPP implementations require that the peer negotiates a specific IP @@ -1052,6 +1303,7 @@ set ifaddr 192.244.177.38 192.244.177.2 255.255.255.255 0.0.0.0 .Ed .Pp The above specification means: +.Pp .Bl -bullet -compact .It I will first suggest that my IP address should be 0.0.0.0, but I @@ -1075,6 +1327,7 @@ user to specify IP address more loosely: .Pp A number followed by a slash (/) represent the number of bits significant in the IP address. The above example signifies that: +.Pp .Bl -bullet -compact .It I'd like to use 192.244.177.38 as my address if it is possible, but I'll @@ -1220,7 +1473,10 @@ logging) so that the actual password is not compromised .Ar chat logging is active rather than the actual password. .Pp -Login scripts vary greatly between ISPs. +Login scripts vary greatly between ISPs. If you're setting one up +for the first time, +.Em ENABLE CHAT LOGGING +so that you can see if your script is behaving as you expect. .It Use .Dq set line @@ -1266,16 +1522,13 @@ be ignored as it is less restrictive than the default mask for your An example for a connection where you don't know your IP number or your ISPs IP number would be: .Bd -literal -offset indent -set ifaddr 10.10.10.10/0 10.10.11.11/0 0.0.0.0 0.0.0.0 +set ifaddr 10.0.0.1/0 10.0.0.2/0 0.0.0.0 0.0.0.0 .Ed .Pp .It In most cases, your ISP will also be your default router. If this is -the case, and if you're using -.Fl auto -mode, add the lines +the case, add the line .Bd -literal -offset indent -delete ALL add default HISADDR .Ed .Pp @@ -1284,43 +1537,21 @@ to .Pp This tells .Nm -to delete all non-direct routing entries for the tun interface that -.Nm -is running on, then to add a default route to 10.10.11.11. If you're -not using -.Fl auto -mode, this isn't necessary as -.Nm -will dial immediately and may negotiate new IP numbers with the peer. +to add a default route to whatever the peer address is +.Pq 10.0.0.2 in this example . +This route is +.Sq sticky , +meaning that should the value of +.Dv HISADDR +change, the route will be updated accordingly. .Pp -If you're not using -.Fl auto -mode, or if you're using dynamic IP numbers, you must also put these -two lines in the -.Pa /etc/ppp/ppp.linkup -file: -.Bd -literal -offset indent -delete ALL -add default HISADDR -.Ed -.Pp -HISADDR is a macro meaning the "other side"s IP number, and is -available once an IP number has been agreed (using IPCP) or set -.Pq using Dq set ifaddr . -Now, once a connection is established, +Previous versions of .Nm -will delete all non-direct interface routes, and add a default route -pointing at the peers IP number. You should use the same label as the -one used in -.Pa /etc/ppp/ppp.conf . -.Pp -If commands are being typed interactively, the only requirement is -to type -.Bd -literal -offset indent -add default HISADDR -.Ed -.Pp -after a successful dial. +required a similar entry in the +.Pa /etc/ppp/ppp.linkup +file. Since the advent of +.Sq sticky routes , +his is no longer required. .It If your provider requests that you use PAP/CHAP authentication methods, add the next lines to your @@ -1334,6 +1565,20 @@ set authkey MyPassword Both are accepted by default, so .Nm will provide whatever your ISP requires. +.Pp +It should be noted that a login script is rarely (if ever) required +when PAP or CHAP are in use. +.It +Ask your ISP to authenticate your nameserver address(es) with the line +.Bd -literal -offset indent +enable dns +.Ed +Do +.Em NOT +do this if you are running an local DNS, as +.Nm +will simply circumvent its use by entering some nameserver lines in +.Pa /etc/resolv.conf . .El .Pp Please refer to @@ -1343,26 +1588,26 @@ and for some real examples. The pmdemand label should be appropriate for most ISPs. .Sh LOGGING FACILITY -.Nm +.Nm Ppp is able to generate the following log info either via .Xr syslog 3 or directly to the screen: .Bl -column SMMMMMM -offset indent .It Li Async Dump async level packet in hex -.It Li Carrier Log Chat lines with 'CARRIER' +.It Li CBCP Generate CBCP (CallBack Control Protocol) logs .It Li CCP Generate a CCP packet trace .It Li Chat Generate Chat script trace log .It Li Command Log commands executed .It Li Connect Generate complete Chat log -.It Li Debug Log (very verbose) debug information +.It Li Debug Log debug information .It Li HDLC Dump HDLC packet in hex .It Li ID0 Log all function calls specifically made as user id 0. .It Li IPCP Generate an IPCP packet trace .It Li LCP Generate an LCP packet trace -.It Li Link Log address assignments and link up/down events .It Li LQM Generate LQR report .It Li Phase Phase transition log output .It Li TCP/IP Dump all TCP/IP packets +.It Li Timer Log timer manipulation .It Li TUN Include the tun device on each log line .It Li Warning Output to the terminal device. If there is currently no terminal, output is sent to the log file using LOG_WARNING. @@ -1375,7 +1620,7 @@ The .Dq set log command allows you to set the logging output level. Multiple levels can be specified on a single command line. The default is equivalent to -.Dq set log Carrier Link Phase . +.Dq set log Phase . .Pp It is also possible to log directly to the screen. The syntax is the same except that the word @@ -1384,21 +1629,21 @@ should immediately follow .Dq set log . The default is .Dq set log local -(ie. no direct screen logging). +(ie. only the un-maskable warning, error and alert output). .Pp If The first argument to .Dq set log Op local begins with a '+' or a '-' character, the current log levels are not cleared, for example: .Bd -literal -offset indent -PPP ON awfulhak> set log carrier link phase +PPP ON awfulhak> set log phase PPP ON awfulhak> show log -Log: Carrier Link Phase Warning Error Alert +Log: Phase Warning Error Alert Local: Warning Error Alert -PPP ON awfulhak> set log -link +tcp/ip -warning +PPP ON awfulhak> set log +tcp/ip -warning PPP ON awfulhak> set log local +command PPP ON awfulhak> show log -Log: Carrier Phase TCP/IP Warning Error Alert +Log: Phase TCP/IP Warning Error Alert Local: Command Warning Error Alert .Ed .Pp @@ -1413,7 +1658,7 @@ locally. .Sh SIGNAL HANDLING .Nm Ppp deals with the following signals: -.Bl -tag -width 20 +.Bl -tag -width XX .It INT Receipt of this signal causes the termination of the current connection (if any). This will cause @@ -1427,19 +1672,173 @@ mode. These signals tell .Nm to exit. -.It USR1 -This signal, when not in interactive mode, tells -.Nm -to close any existing server socket and open an Internet socket using -port 3000 plus the current tunnel device number. This can only be -achieved if a suitable local password is specified in -.Pa /etc/ppp/ppp.secret . .It USR2 This signal, tells .Nm -to close any existing server socket. +to close any existing server socket, dropping all existing diagnostic +connections. .El .Pp +.Sh MULTI-LINK PPP +If you wish to use more than one physical link to connect to a +.Em PPP +peer, that peer must also understand the +.Em MULTI-LINK PPP +protocol. Refer to RFC 1990 for specification details. +.Pp +The peer is identified using a combination of his +.Dq endpoint discriminator +and his +.Dq authentication id . +Either or both of these may be specified. It is recommended that +at least one is specified, otherwise there is no way of ensuring that +all links are actually connected to the same peer program, and some +confusing lock-ups may result. Locally, these identification variables +are specified using the +.Dq set enddisc +and +.Dq set authname +commands. The +.Sq authname +.Pq and Sq authkey +must be agreed in advance with the peer. +.Pp +Multi-link capabilities are enabled using the +.Dq set mrru +command (set maximum reconstructed receive unit). Once multi-link +is enabled, +.Nm +will attempt to negotiate a multi-link connection with the peer. +.Pp +By default, only one +.Sq link +is available +.Pq called Sq deflink . +To create more links, the +.Dq clone +command is used. This command will clone existing links, where all +characteristics are the same except: +.Bl -enum +.It +The new link has its own name as specified on the +.Dq clone +command line. +.It +The new link is an +.Sq interactive +link. It's mode may subsequently be changed using the +.Dq set mode +command. +.It +The new link is in a +.Sq closed +state. +.El +.Pp +A summary of all available links can be seen using the +.Dq show links +command. +.Pp +Once a new link has been created, command usage varies. All link +specific commands must be prefixed with the +.Dq link Ar name +command, specifying on which link the command is to be applied. When +only a single link is available, +.Nm +is smart enough not to require the +.Dq link Ar name +prefix. +.Pp +Some commands can still be used without specifying a link - resulting +in an operation at the +.Sq bundle +level. For example, once two or more links are available, the command +.Dq show ccp +will show CCP configuration and statistics at the multi-link level, and +.Dq link deflink show ccp +will show the same information at the +.Dq deflink +link level. +.Pp +Armed with this information, the following configuration might be used: +.Pp +.Bd -literal -offset indent +mp: + set timeout 0 + set log phase chat + set device /dev/cuaa0 /dev/cuaa1 /dev/cuaa2 + set phone "123456789" + set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \\"\\" ATZ \e + OK-AT-OK \\\\dATDT\\\\T TIMEOUT 45 CONNECT" + set login + set ifaddr 10.0.0.1/0 10.0.0.2/0 + set authname ppp + set authkey ppppassword + + set mrru 1500 + clone 1,2,3 + link deflink remove +.Ed +.Pp +Note how all cloning is done at the end of the configuration. Usually, +the link will be configured first, then cloned. If you wish all links +to be up all the time, you can add the following line to the end of your +configuration. +.Pp +.Bd -literal -offset indent + link 1,2,3 set mode ddial +.Ed +.Pp +If you want the links to dial on demand, this command could be used: +.Pp +.Bd -literal -offset indent + link * set mode auto +.Ed +.Pp +Links may be tied to specific names by removing the +.Dq set device +line above, and specifying the following after the +.Dq clone +command: +.Pp +.Bd -literal -offset indent + link 1 set device /dev/cuaa0 + link 2 set device /dev/cuaa1 + link 3 set device /dev/cuaa2 +.Ed +.Pp +Use the +.Dq help +command to see which commands require context (using the +.Dq link +command), which have optional +context and which should not have any context. +.Pp +When +.Nm +has negotiated +.Em MULTI-LINK +mode with the peer, it creates a local domain socket in the +.Pa /var/run +directory. This socket is used to pass link information (including +the actual link file descriptor) between different +.Nm +invocations. This facilitates +.Nm ppp Ns No s +ability to be run from a +.Xr getty 8 +or directly from +.Pa /etc/gettydefs +(using the +.Sq pp= +capability), without needing to have initial control of the serial +line. Once +.Nm +negotiates multi-link mode, it will pass its open link to any +already running process. If there is no already running process, +.Nm +will act as the master, creating the socket and listening for new +connections. .Sh PPP COMMAND LIST This section lists the available commands and their effect. They are usable either from an interactive @@ -1449,8 +1848,8 @@ session, from a configuration file or from a or .Xr telnet 1 session. -.Bl -tag -width 20 -.It accept|deny|enable|disable option.... +.Bl -tag -width XX +.It accept|deny|enable|disable Ar option.... These directives tell .Nm how to negotiate the initial connection with the peer. Each @@ -1467,7 +1866,7 @@ means that the option will not be requested by us. .Pp .Dq Option may be one of the following: -.Bl -tag -width 20 +.Bl -tag -width XX .It acfcomp Default: Enabled and Accepted. ACFComp stands for Address and Control Field Compression. Non LCP packets usually have very similar address @@ -1500,9 +1899,10 @@ CHAP is accepted by default. Some .Em PPP implementations use "MS-CHAP" rather than MD5 when encrypting the -challenge. Refer to the description of the -.Dq set encrypt -command for further details. +challenge. MS-CHAP is a combination of MD4 and DES. If +.Nm +was built on a machine with DES libraries available, it will respond +to MS-CHAP authentication requests, but will never request them. .It deflate Default: Enabled and Accepted. This option decides if deflate compression will be used by the Compression Control Protocol (CCP). @@ -1528,24 +1928,76 @@ as specified in Type .Ar 24 is actually specified as -.Dq PPP Magnalink Variable Resource Compression +.Dq PPP Magna-link Variable Resource Compression in .Pa rfc1975 Ns No ! .Nm Ppp is capable of negotiating with .Nm pppd , but only if -.Dq pppd-deflate +.Dq deflate24 is .Ar enable Ns No d and .Ar accept Ns No ed . +.It deflate24 +Default: Disabled and Denied. This is a variance of the +.Ar deflate +option, allowing negotiation with the +.Xr pppd 8 +program. Refer to the +.Ar deflate +section above for details. It is disabled by default as it violates +.Pa rfc1975 . +.It dns +Default: Disabled and Denied. This option allows DNS negotiation. +.Pp +If +.Dq enable Ns No d, +.Nm +will request that the peer confirms the entries in +.Pa /etc/resolv.conf . +If the peer NAKs our request (suggesting new IP numbers), +.Pa /etc/resolv.conf +is updated and another request is sent to confirm the new entries. +.Pp +If +.Dq accept Ns No ed, +.Nm +will answer any DNS queries requested by the peer rather than rejecting +them. The answer is taken from +.Pa /etc/resolv.conf +unless the +.Dq set dns +command is used as an override. .It lqr Default: Disabled and Accepted. This option decides if Link Quality -Requests will be sent. LQR is a protocol that allows +Requests will be sent or accepted. LQR is a protocol that allows .Nm to determine that the link is down without relying on the modems -carrier detect. +carrier detect. When LQR is enabled, +.Nm +sends the +.Em QUALPROTO +option (see +.Dq set lqrperiod +below) as part of the LCP request. If the peer agrees, both sides will +exchange LQR packets at the agreed frequency, allowing detailed link +quality monitoring by enabling LQM logging. If the peer doesn't agree, +ppp will send ECHO LQR requests instead. These packets pass no +information of interest, but they +.Em MUST +be replied to by the peer. +.Pp +Whether using LQR or ECHO LQR, +.Nm +will abruptly drop the connection if 5 unacknowledged packets have been +sent rather than sending a 6th. A message is logged at the +.Em PHASE +level, and any appropriate +.Dq reconnect +values are honoured as if the peer were responsible for dropping the +connection. .It pap Default: Disabled and Accepted. PAP stands for Password Authentication Protocol. Only one of PAP and CHAP (above) may be negotiated. With @@ -1570,15 +2022,6 @@ and in .Pa /etc/ppp/ppp.conf . PAP is accepted by default. -.It pppd-deflate -Default: Disabled and Denied. This is a variance of the -.Ar deflate -option, allowing negotiation with the -.Xr pppd 8 -program. Refer to the -.Ar deflate -section above for details. It is disabled by default as it violates -.Pa rfc1975 . .It pred1 Default: Enabled and Accepted. This option decides if Predictor 1 compression will be used by the Compression Control Protocol (CCP). @@ -1586,41 +2029,96 @@ compression will be used by the Compression Control Protocol (CCP). Default: Enabled and Accepted. This option is used to negotiate PFC (Protocol Field Compression), a mechanism where the protocol field number is reduced to one octet rather than two. +.It shortseq +Default: Enabled and Accepted. This option determines if +.Nm +will request and accept requests for short +.Pq 12 bit +sequence numbers when negotiating multi-link mode. This is only +applicable if our MRRU is set (thus enabling multi-link). .It vjcomp -Default: Enabled and Accepted. This option decides if Van Jacobson +Default: Enabled and Accepted. This option determines if Van Jacobson header compression will be used. .El .Pp The following options are not actually negotiated with the peer. Therefore, accepting or denying them makes no sense. -.Bl -tag -width 20 -.It msext -Default: Disabled. This option allows the use of Microsoft's +.Bl -tag -width XX +.It idcheck +Default: Enabled. When +.Nm +exchanges low-level LCP, CCP and IPCP configuration traffic, the +.Em Identifier +field of any replies is expected to be the same as that of the request. +By default, +.Nm +drops any reply packets that do not contain the expected identifier +field, reporting the fact at the respective log level. If +.Ar idcheck +is disabled, +.Nm +will ignore the identifier field. +.It loopback +Default: Enabled. When +.Ar loopback +is enabled, +.Nm +will automatically loop back packets being sent +out with a destination address equal to that of the .Em PPP -extensions, supporting the negotiation of the DNS and the NetBIOS NS. -Enabling this allows us to pass back the values given in "set ns" -and "set nbns". +interface. If disabled, +.Nm +will send the packet, probably resulting in an ICMP redirect from +the other end. It is convenient to have this option enabled when +the interface is also the default route as it avoids the necessity +of a loopback route. .It passwdauth Default: Disabled. Enabling this option will tell the PAP authentication -code to use the password file (see +code to use the password database (see .Xr passwd 5 ) -to authenticate the caller rather than the +to authenticate the caller if they cannot be found in the .Pa /etc/ppp/ppp.secret file. +.Pa /etc/ppp/ppp.secret +is always checked first. If you wish to use passwords from +.Xr passwd 5 , +but also to specify an IP number or label for a given client, use +.Dq \&* +as the client password in +.Pa /etc/ppp/ppp.secret . .It proxy Default: Disabled. Enabling this option will tell .Nm to proxy ARP for the peer. +.It sroutes +Default: Enabled. When the +.Dq add +command is used with the +.Dv HISADDR +or +.Dv MYADDR +values, entries are stored in the +.Sq stick route +list. Each time +.Dv HISADDR +or +.Dv MYADDR +change, this list is re-applied to the routing table. +.Pp +Disabling this option will prevent the re-application of sticky routes, +although the +.Sq stick route +list will still be maintained. .It throughput -Default: Disabled. Enabling this option will tell +Default: Enabled. This option tells .Nm -to gather thoroughput statistics. Input and output is sampled over +to gather throughput statistics. Input and output is sampled over a rolling 5 second window, and current, best and total figures are -retained. This data is output when the relevent +retained. This data is output when the relevant .Em PPP layer shuts down, and is also available using the .Dq show -command. Troughput statistics are available at the +command. Throughput statistics are available at the .Dq IPCP and .Dq modem @@ -1638,25 +2136,31 @@ not to make any utmp or wtmp entries. This is usually only necessary if you require the user to both login and authenticate themselves. .El .Pp -.It add[!] dest mask gateway +.It add[!] Ar dest[/nn] [mask] gateway .Ar Dest -is the destination IP address and -.Ar mask -is its mask. +is the destination IP address. The netmask is specified either as a +number of bits with +.Ar /nn +or as an IP number using +.Ar mask . .Ar 0 0 -refers to the default route, and it is possible to use the symbolic name +or simply +.Ar 0 +with no mask refers to the default route. It is also possible to use the +literal name .Sq default -in place of both the -.Ar dest -and -.Ar mask -arguments. +instead of +.Ar 0 . .Ar Gateway is the next hop gateway to get to the given .Ar dest -machine/network. It is possible to use the symbolic names +machine/network. Refer to the +.Xr route 8 +command for further details. +.Pp +It is possible to use the symbolic names .Sq MYADDR -and +or .Sq HISADDR as the destination, and either .Sq HISADDR @@ -1667,7 +2171,7 @@ as the .Sq MYADDR is replaced with the interface address, .Sq HISADDR -is replaced with the interfaces destination address and +is replaced with the interface destination address and .Sq INTERFACE is replaced with the current interface name. If the interfaces destination address has not yet been assigned @@ -1677,23 +2181,32 @@ the current is used instead of .Sq HISADDR . .Pp -Refer to the -.Dq set ifaddr -command below for details of some restrictions regarding the use of this -command in the -.Pa ppp.conf -file. -.Pp If the .Ar add! command is used -.Pq note the following Dq \&! , +.Pq note the trailing Dq \&! , then if the route already exists, it will be updated as with the .Sq route change command (see .Xr route 8 for further details). -.It allow ..... +.Pp +Routes that contain the +.Dq HISADDR +or +.Dq MYADDR +constants are considered +.Sq sticky . +They are stored in a list (use +.Dq show ipcp +to see the list), and each time the value of +.Dv HISADDR +or +.Dv MYADDR +changes, the appropriate routing table entries are updated. This facility +may be disabled using +.Dq disable sroutes . +.It allow Ar command Op Ar args This command controls access to .Nm and its configuration files. It is possible to allow user-level access, @@ -1710,14 +2223,16 @@ in mode. .Pp User id 0 is immune to these commands. -.Bl -tag -width 20 -.It allow user|users logname... -By default, only user id 0 is allowed access. If this command is specified, -all of the listed users are allowed access to the section in which the +.Bl -tag -width XX +.It allow user[s] Ar logname... +By default, only user id 0 is allowed access to +.Nm ppp . +If this command is used, all of the listed users are allowed access to +the section in which the .Dq allow users command is found. The .Sq default -section is always checked first (although it is only ever automatically +section is always checked first (even though it is only ever automatically loaded at startup). Each successive .Dq allow users command overrides the previous one, so it's possible to allow users access @@ -1728,11 +2243,11 @@ section, and then specifying a new user list for that label. If user .Sq * is specified, access is allowed to all users. -.It allow mode|modes modelist... -By default, access using all +.It allow mode[s] Ar modelist... +By default, access using any .Nm -modes is possible. If this command is used, it restricts the access -modes allowed to load the label under which this command is specified. +mode is possible. If this command is used, it restricts the access +mode allowed to load the label under which this command is specified. Again, as with the .Dq allow users command, each @@ -1750,45 +2265,54 @@ Possible modes are: .Sq background and .Sq * . +.Pp +When running in multi-link mode, a section can be loaded if it allows +.Em any +of the currently existing line modes. .El .Pp -.It alias ..... +.It alias Ar command Op Ar args This command allows the control of the aliasing (or masquerading) facilities that are built into .Nm ppp . -Until this code is required, it is not loaded by -.Nm ppp , -and it is quite possible that the alias library is not installed -on your system (some administrators consider it a security risk). -If aliasing is enabled on your system, the following commands are -possible: -.Bl -tag -width 20 +If aliasing is enabled on your system (it may be omitted at compile time), +the following commands are possible: +.Bl -tag -width XX .It alias enable [yes|no] This command either switches aliasing on or turns it off. The .Fl alias command line flag is synonymous with .Dq alias enable yes . -.It alias port [proto targetIP:targetPORT [aliasIP:]aliasPORT] +.It alias port Op Ar proto targetIP:targetPORT [aliasIP:]aliasPORT This command allows us to redirect connections arriving at -.Dq aliasPORT -for machine [aliasIP] to -.Dq targetPORT +.Ar aliasPORT +for machine +.Ar aliasIP +to +.Ar targetPORT on -.Dq targetIP . -If proto is specified, only connections of the given protocol +.Ar targetIP . +.Ar Proto +may be either +.Sq tcp +or +.Sq udp , +and only connections of the given protocol are matched. This option is useful if you wish to run things like Internet phone on the machines behind your gateway. -.It alias addr [addr_local addr_alias] +.It alias addr Op Ar addr_local addr_alias This command allows data for -.Dq addr_alias +.Ar addr_alias to be redirected to -.Dq addr_local . +.Ar addr_local . It is useful if you own a small number of real IP numbers that you wish to map to specific machines behind your gateway. .It alias deny_incoming [yes|no] If set to yes, this command will refuse all incoming connections by dropping the packets in much the same way as a firewall would. +.It alias help|? +This command gives a summary of available alias commands. .It alias log [yes|no] This option causes various aliasing statistics and information to be logged to the file @@ -1806,35 +2330,116 @@ IRC connection. Only alter outgoing packets with an unregistered source ad- dress. According to RFC 1918, unregistered source addresses are 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. -.It alias help|? -This command gives a summary of available alias commands. .El .Pp -.It [!]bg command -The given command is executed in the background. -Any of the pseudo arguments -.Dv HISADDR , -.Dv INTERFACE -and -.Dv MYADDR -will be replaced with the appropriate values. If you wish to pause +These commands are also discussed in the file +.Pa README.alias +which comes with the source distribution. +.Pp +.It [!]bg Ar command +The given +.Ar command +is executed in the background with the following words replaced: +.Bl -tag -width PEER_ENDDISC +.It Li AUTHNAME +This is replaced with the local +.Ar authname +value. See the +.Dq set authname +command below. +.It Li ENDDISC +This is replaced with the local endpoint discriminator value. See the +.Dq set enddisc +command below. +.It Li HISADDR +This is replaced with the peers IP number. +.It Li INTERFACE +This is replaced with the name of the interface that's in use. +.It Li LABEL +This is replaced with the last label name used. A label may be specified +on the +.Nm +command line, via the +.Dq load +or +.Dq dial +commands and in the +.Pa ppp.secret +file. +.It Li MYADDR +This is replaced with the IP number assigned to the local interface. +.It Li PEER_ENDDISC +This is replaced with the value of the peers endpoint discriminator. +.It Li USER +This is replaced with the username that has been authenticated with PAP or +CHAP. Normally, this variable is assigned only in -direct mode. This value +is available irrespective of whether utmp logging is enabled. +.El +.Pp +If you wish to pause .Nm while the command executes, use the -.Dv shell +.Dq shell command instead. -.It close -Close the current connection (but don't quit). -.It delete[!] dest +.It clear modem|ipcp Op current|overall|peak... +Clear the specified throughput values at either the +.Dq modem +or +.Dq ipcp +level. If +.Dq modem +is specified, context must be given (see the +.Dq link +command below). If no second argument is given, all values are +cleared. +.It clone Ar name[,name]... +Clone the specified link, creating one or more new links according to the +.Ar name +argument(s). This command must be used from the +.Dq link +command below unless you've only got a single link (in which case that +link becomes the default). Links may be removed using the +.Dq remove +command below. +.Pp +The default link name is +.Dq deflink . +.It close Op lcp|ccp[!] +If no arguments are given, the relevant protocol layers will be brought +down and the link will be closed. If +.Dq lcp +is specified, the LCP layer is brought down, but +.Nm +will not bring the link offline. It is subsequently possible to use +.Dq term +.Pq see below +to talk to the peer machine if, for example, something like +.Dq slirp +is being used. If +.Dq ccp +is specified, only the relevant compression layer is closed. If the +.Dq \&! +is used, the compression layer will remain in the closed state, otherwise +it will re-enter the STOPPED state, waiting for the peer to initiate +further CCP negotiation. In any event, this command does not disconnect +the user from +.Nm +or exit +.Nm ppp . +See the +.Dq quit +command below. +.It delete[!] Ar dest This command deletes the route with the given .Ar dest IP address. If .Ar dest is specified as .Sq ALL , -all non-direct entries in the routing for the current interface that -.Nm -is using are deleted. This means all entries for tunN, except the entry -representing the actual link. If +all non-direct entries in the routing table for the current interface, +and all +.Sq sticky route +entries are deleted. If .Ar dest is specified as .Sq default , @@ -1843,41 +2448,100 @@ the default route is deleted. If the .Ar delete! command is used -.Pq note the following Dq \&! , +.Pq note the trailing Dq \&! , .Nm will not complain if the route does not already exist. -.It dial|call [remote] -If -.Dq remote -is specified, a connection is established using the -.Dq dial -and -.Dq login -scripts for the given -.Dq remote -system. Otherwise, the current settings are used to establish -the connection. -.It display -Displays the current status of the negotiable protocol -values as specified under -.Dq accept|deny|enable|disable option.... -above. -.It down -Bring the link down ungracefully, as if the physical layer had become -unavailable. It's not considered polite to use this command. -.It help|? [command] +.It dial|call Op Ar label +When used with no argument, this command is the same as the +.Dq open +command. When +.Ar label +is specified, a +.Dq load +will be done first. +.It down Op Ar lcp|ccp +Bring the relevant layer down ungracefully, as if the underlying layer +had become unavailable. It's not considered polite to use this command on +a Finite State Machine that's in the OPEN state. If no arguments are +supplied, the entire link is closed (or if no context is given, all links +are terminated). If +.Sq lcp +is specified, the +.Em LCP +layer is terminated but the modem is not brought offline and the link +is not closed. If +.Sq ccp +is specified, only the relevant compression layer(s) are terminated. +.It help|? Op Ar command Show a list of available commands. If -.Dq command +.Ar command is specified, show the usage string for that command. -.It load [remote] +.It [data]link Ar name[,name...] command Op Ar args +This command may prefix any other command if the user wishes to +specify which link the command should affect. This is only +applicable after multiple links have been created in Multi-link +mode using the +.Dq clone +command. +.Pp +.Ar Name +specifies the name of an existing link. If +.Ar name +is a comma separated list, +.Ar command +is executed on each link. If +.Ar name +is +.Dq * , +.Ar command +is executed on all links. +.It load Op Ar label Load the given -.Dq remote -label. If -.Dq remote +.Ar label +from the +.Pa ppp.conf +file. If +.Ar label is not given, the -.Dq default -label is assumed. -.It passwd pass +.Ar default +label is used. +.It open Op lcp|ccp|ipcp +This is the opposite of the +.Dq close +command. Using +.Dq open +with no arguments is the same as using +.Dq dial +with no arguments, where all closed links are brought up (some auto +links may not come up based on the +.Dq set autoload +command) using the current configuration. +.Pp +If the +.Dq lcp +while the LCP layer is already open, LCP will be renegotiated. This +allows various LCP options to be changed, after which +.Dq open lcp +can be used to put them into effect. After renegotiating LCP, +any agreed authentication will also take place. +.Pp +If the +.Dq ccp +argument is used, the relevant compression layer is opened. Again, +if it is already open, it will be renegotiated. +.Pp +If the +.Dq ipcp +argument is used, the link will be brought up as normal, but if +IPCP is already open, it will be renegotiated and the network +interface will be reconfigured. +.Pp +It is probably not good practice to re-open the PPP state machines +like this as it's possible that the peer will not behave correctly. +It +.Em is +however useful as a way of forcing the CCP or VJ dictionaries to be reset. +.It passwd Ar pass Specify the password required for access to the full .Nm command set. This password is required when connecting to the diagnostic @@ -1885,68 +2549,63 @@ port (see the .Dq set server command). .Ar Pass -may be specified either on the +is specified on the .Dq set server -command line or by putting an entry in -.Pa /var/log/ppp.secret -for the local host. The value of +command line. The value of .Ar pass is not logged when .Ar command logging is active, instead, the literal string -.Dq ******** +.Sq ******** is logged. .It quit|bye [all] -Exit -.Nm ppp . If -.Nm -is in interactive mode or if the -.Dq all -argument is given, -.Nm -will exit, closing the connection. A simple .Dq quit -issued from a -.Xr pppctl 8 +is executed from the controlling connection or from a command file, +ppp will exit after closing all connections. Otherwise, if the user +is connected to a diagnostic socket, the connection is simply dropped. +.Pp +If the +.Ar +all argument is given, +.Nm +will exit despite the source of the command after closing all existing +connections. +.It remove|rm +This command removes the given link. It is only really useful in +multi-link mode. A link must be +in the +.Dv CLOSED +state before it is removed. +.It rename|mv Ar name +This command renames the given link to +.Ar name . +It will fail if +.Ar name +is already used by another link. +.Pp +The default link name is +.Sq deflink . +Renaming it to +.Sq modem , +.Sq cuaa0 or -.Xr telnet 1 -session will not close the current connection. +.Sq USR +may make the log file more readable. .It save This option is not (yet) implemented. -.It set[up] var value +.It set[up] Ar var value This option allows the setting of any of the following variables: -.Bl -tag -width 20 -.It set accmap hex-value -ACCMap stands for Asyncronous Control Character Map. This is always -negotiated with the peer, and defaults to a value of 0x00000000. +.Bl -tag -width XX +.It set accmap Ar hex-value +ACCMap stands for Asynchronous Control Character Map. This is always +negotiated with the peer, and defaults to a value of 00000000 in hex. This protocol is required to defeat hardware that depends on passing certain characters from end to end (such as XON/XOFF etc). -.It set filter-name rule-no action [src_addr/src_width] -[dst_addr/dst_width] [proto [src [lt|eq|gt] port ]] -[dst [lt|eq|gt] port] [estab] .Pp -.Nm Ppp -supports four filter sets. The afilter specifies packets that keep -the connection alive - reseting the idle timer. The dfilter specifies -packets that cause -.Nm -to dial when in -.Fl auto -mode. The ifilter specifies packets that are allowed to travel -into the machine and the ofilter specifies packets that are allowed -out of the machine. By default all filter sets allow all packets -to pass. -Rules are processed in order according to -.Dq n . -Up to 20 rules may be given for each set. If a packet doesn't match -any of the rules in a given set, it is discarded. In the case of -ifilters and ofilters, this means that the packet is dropped. In -the case of afilters it means that the packet will not reset the -idle timer and in the case of dfilters it means that the packet will -not trigger a dial. -Refer to the section on PACKET FILTERING above for further details. -.It set authkey|key value +For the XON/XOFF scenario, use +.Dq set accmap 000a0000 . +.It set authkey|key Ar value This sets the authentication key (or password) used in client mode PAP or CHAP negotiation to the given value. It can also be used to specify the password to be used in the dial or login scripts in place @@ -1955,13 +2614,183 @@ of the '\\P' sequence, preventing the actual password from being logged. If logging is in effect, .Ar value is logged as -.Ar ******** +.Sq ******** for security reasons. -.It set authname id +.It set authname Ar id This sets the authentication id used in client mode PAP or CHAP negotiation. -.It set ctsrts -This sets hardware flow control and is the default. -.It set device|line value[,value...] +.Pp +If used in +.Fl direct +mode with PAP or CHAP enabled, +.Ar id +is used in the initial authentication request and is normally set to +the local machine name. +.It set autoload Ar max-duration max-load [min-duration min-load] +These settings apply only in multi-link mode and all default to zero. +When more than one +.Ar demand-dial +.Pq also known as Fl auto +mode link is available, only the first link is made active when +.Nm +first reads data from the tun device. The next +.Ar demand-dial +link will be opened only when at least +.Ar max-load +packets have been in the send queue for +.Ar max-duration +seconds. Because both values default to zero, +.Ar demand-dial +links will simply come up one at a time by default. +.Pp +If two or more links are open, at least one of which is a +.Ar demand-dial +link, a +.Ar demand-dial +link will be closed when there is less than +.Ar min-packets +in the queue for more than +.Ar min-duration . +If +.Ar min-duration +is zero, this timer is disabled. Because both values default to zero, +.Ar demand-dial +links will stay active until the bundle idle timer expires. +.It set callback [none|auth|cbcp|E.164 *|number[,number]...]... +If no arguments are given, callback is disabled, otherwise, +.Nm +will request (or in +.Ar direct +mode, will accept) one of the given protocols. If a request is NAK'd +.Nm +will request another, until no options remain at which point +.Nm +will terminate negotiations. +The options are as follows (in this order of preference): +.Pp +.Bl -tag +.It auth +The callee is expected to decide the callback number based on +authentication. If +.Nm +is the callee, the number should be specified as the fifth field of +the peers entry in +.Pa /etc/ppp/ppp.secret . +.It cbcp +Microsofts callback control protocol is used. See +.Dq set cbcp +below. +.It E.164 *|number[,number]... +The caller specifies the +.Ar number . +If +.Nm +is the callee, +.Ar number +should be either a comma seperated list of allowable numbers or a +.Dq \&* , +meaning any number is permitted. If +.Nm +is the caller, only a single number should be specified. +.Pp +Note, this option is very unsafe when used with a +.Dq \&* +as a malicious caller can tell +.Nm +to call any (possibly international) number without first authenticating +themselves. +.It none +If the peer does not wish to do callback at all, +.Nm +will accept the fact and continue without callback rather than terminating +the connection. +.El +.Pp +.It set cbcp Op *|number[,number]... Op delay Op retry +If no arguments are given, CBCP (Microsofts CallBack Control Protocol) +is disabled - ie, configuring CBCP in the +.Dq set callback +command will result in +.Nm +requesting no callback in the CBCP phase. +Otherwise, +.Nm +attempts to use the given phone +.Ar number Ns No (s). +.Pp +In server mode +.Pq Fl direct , +.Nm +will insist that the client uses one of these numbers, unless +.Dq \&* +is used in which case the client is expected to specify the number. +.Pp +In client mode, +.Nm +will attempt to use one of the given numbers (whichever it finds to +be agreeable with the peer), or if +.Dq \&* +is specified, +.Nm +will expect the peer to specify the number. +.It set choked Op Ar timeout +This sets the number of seconds that +.Nm +will keep a choked output queue before dropping all pending output packets. +If +.Ar timeout +is less than or equal to zero or if +.Ar timeout +isn't specified, it is set to the default value of +.Em 120 seconds . +.Pp +A choked output queue occurs when +.Nm +has read a certain number of packets from the local network for transmission, +but cannot send the data due to link failure (the peer is busy etc.). +.Nm Ppp +will not read packets indefinitely. Instead, it reads up to +.Em 20 +packets (or +.Em 20 No + +.Em nlinks No * +.Em 2 +packets in multi-link mode), then stops reading the network interface +until either +.Ar timeout +seconds have passed or at least one packet has been sent. +.Pp +If +.Ar timeout +seconds pass, all pending output packets are dropped. +.It set ctsrts|crtscts on|off +This sets hardware flow control. Hardware flow control is +.Ar on +by default. +.It set deflate Ar out-winsize Op Ar in-winsize +This sets the DEFLATE algorithms default outgoing and incoming window +sizes. Both +.Ar out-winsize +and +.Ar in-winsize +must be values between +.Em 8 +and +.Em 15 . +If +.Ar in-winsize +is specified, +.Nm +will insist that this window size is used and will not accept any other +values from the peer. +.It set dns Op Ar primary Op Ar secondary +This command specifies DNS overrides for the +.Dq accept dns +command. Refer to the +.Dq accept +command description above for details. This command does not affect the +IP numbers requested using +.Dq enable dns . +.It set device|line Ar value[,value...] This sets the device(s) to which .Nm will talk to the given @@ -1972,9 +2801,20 @@ If .Dq value does not begin with .Pa /dev/ , -it must be of the format +it must either begin with an exclamation mark +.Pq Dq \&! +or be of the format .Dq host:port . -If this is the case, +.Pp +If it begins with an exclamation mark, the rest of the device name is +treated as a program name, and that program is executed when the device +is opened. Standard input, output and error are fed back to +.Nm +and are read and written as if they were a regular device. +.Pp +If a +.Dq host:port +pair is given, .Nm will attempt to connect to the given .Dq host @@ -1982,13 +2822,15 @@ on the given .Dq port . Refer to the section on .Em PPP OVER TCP -above for further details. If multiple +above for further details. +.Pp +If multiple .Dq values are specified, .Nm will attempt to open each one in turn until it succeeds or runs out of devices. -.It set dial chat-script +.It set dial Ar chat-script This specifies the chat script that will be used to dial the other side. See also the .Dq set login @@ -1999,35 +2841,35 @@ format. It is possible to specify some special .Sq values in your chat script as follows: -.Bd -literal -offset indent -.It \\\\\\\\\\\\\\\\c +.Bd -unfilled -offset indent +.It Li \\\\\\\\\\\\\\\\c When used as the last character in a .Sq send string, this indicates that a newline should not be appended. -.It \\\\\\\\\\\\\\\\d +.It Li \\\\\\\\\\\\\\\\d When the chat script encounters this sequence, it delays two seconds. -.It \\\\\\\\\\\\\\\\p +.It Li \\\\\\\\\\\\\\\\p When the chat script encounters this sequence, it delays for one quarter of a second. -.It \\\\\\\\\\\\\\\\n +.It Li \\\\\\\\\\\\\\\\n This is replaced with a newline character. -.It \\\\\\\\\\\\\\\\r +.It Li \\\\\\\\\\\\\\\\r This is replaced with a carriage return character. -.It \\\\\\\\\\\\\\\\s +.It Li \\\\\\\\\\\\\\\\s This is replaced with a space character. -.It \\\\\\\\\\\\\\\\t +.It Li \\\\\\\\\\\\\\\\t This is replaced with a tab character. -.It \\\\\\\\\\\\\\\\T +.It Li \\\\\\\\\\\\\\\\T This is replaced by the current phone number (see .Dq set phone below). -.It \\\\\\\\\\\\\\\\P +.It Li \\\\\\\\\\\\\\\\P This is replaced by the current .Ar authkey value (see .Dq set authkey above). -.It \\\\\\\\\\\\\\\\U +.It Li \\\\\\\\\\\\\\\\U This is replaced by the current .Ar authname value (see @@ -2047,7 +2889,7 @@ set dial "... ATDT\\\\T CONNECT" .Pp It is also possible to execute external commands from the chat script. To do this, the first character of the expect or send string is an -exclaimation mark +exclamation mark .Pq Dq \&! . When the command is executed, standard input and standard output are directed to the modem device (see the @@ -2056,7 +2898,7 @@ command), and standard error is read by .Nm and substituted as the expect or send string. If .Nm -is running in interactive mode, file descriptor 4 is attached to +is running in interactive mode, file descriptor 3 is attached to .Pa /dev/tty . .Pp For example (wrapped for readability); @@ -2115,64 +2957,132 @@ This, of course means that it is possible to execute an entirely external command rather than using the internal one. See .Xr chat 8 for a good alternative. +.It set enddisc Op label|IP|MAC|magic|psn value +This command sets our local endpoint discriminator. If set prior to +LCP negotiation, +.Nm +will send the information to the peer using the LCP endpoint discriminator +option. The following discriminators may be set: +.Bd -unfilled -offset indent +.It Li label +The current label is used. +.It Li IP +Our local IP number is used. As LCP is negotiated prior to IPCP, it is +possible that the IPCP layer will subsequently change this value. If +it does, the endpoint discriminator stays at the old value unless manually +reset. +.It Li MAC +This is similar to the +.Ar IP +option above, except that the MAC address associated with the local IP +number is used. If the local IP number is not resident on any Ethernet +interface, the command will fail. +.Pp +As the local IP number defaults to whatever the machine host name is, +.Dq set enddisc mac +is usually done prior to any +.Dq set ifaddr +commands. +.It Li magic +A 20 digit random number is used. +.It Li psn Ar value +The given +.Ar value +is used. +.Ar Value +should be set to an absolute public switched network number with the +country code first. +.Ed .Pp -.It set hangup chat-script -This specifies the chat script that will be used to reset the modem -before it is closed. It should not normally be necessary, but can -be used for devices that fail to reset themselves properly on close. -.It set encrypt MSChap|MD5 -This specifies the encryption algorithm to request and use when issuing -the CHAP challenge, and defaults to MD5. If this is set to MSChap, -.Nm -will behave like a Microsoft RAS when sending the CHAP challenge (assuming -CHAP is enabled). When responding to a challenge, -.Nm -determines how to encrypt the response based on the challenge, so this -setting is ignored. -.Bl -tag -width NOTE: -.It NOTE: -Because the Microsoft encryption algorithm uses a combination of MD4 and DES, -if you have not installed DES encryption software on your machine -before building -.Nm ppp , -this option will not be available - only MD5 will be used. -.El -.Pp -.It set escape value... +If no arguments are given, the endpoint discriminator is reset. +.It set escape Ar value... This option is similar to the .Dq set accmap option above. It allows the user to specify a set of characters that will be `escaped' as they travel across the link. -.It set ifaddr [myaddr [hisaddr [netmask [triggeraddr]]]] +.It set filter dial|alive|in|out rule-no permit|deny Ar "[src_addr/width] [dst_addr/width] [proto [src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]" +.Nm Ppp +supports four filter sets. The +.Em alive +filter specifies packets that keep the connection alive - reseting the +idle timer. The +.Em dial +filter specifies packets that cause +.Nm +to dial when in +.Fl auto +mode. The +.Em in +filter specifies packets that are allowed to travel +into the machine and the +.Em out +filter specifies packets that are allowed out of the machine. +.Pp +Filtering is done prior to any IP alterations that might be done by the +alias engine. By default all filter sets allow all packets to pass. +Rules are processed in order according to +.Ar rule-no . +Up to 20 rules may be given for each set. If a packet doesn't match +any of the rules in a given set, it is discarded. In the case of +.Em in +and +.Em out +filters, this means that the packet is dropped. In the case of +.Em alive +filters it means that the packet will not reset the idle timer and in +the case of +.Em dial +filters it means that the packet will not trigger a dial. A packet failing +to trigger a dial will be dropped rather than queued. Refer to the +section on PACKET FILTERING above for further details. +.It set hangup Ar chat-script +This specifies the chat script that will be used to reset the modem +before it is closed. It should not normally be necessary, but can +be used for devices that fail to reset themselves properly on close. +.It set help|? Op Ar command +This command gives a summary of available set commands, or if +.Ar command +is specified, the command usage is shown. +.It set ifaddr Ar [myaddr [hisaddr [netmask [triggeraddr]]]] This command specifies the IP addresses that will be used during IPCP negotiation. Addresses are specified using the format +.Pp .Dl a.b.c.d/n -Where a.b.c.d is the preferred IP, but n specifies how many bits -of the address we will insist on. If the /n bit is omitted, it -defaults to /32 unless the IP address is 0.0.0.0 in which case -the mask defaults to /0. +.Pp +Where +.Ar a.b.c.d +is the preferred IP, but +.Ar n +specifies how many bits of the address we will insist on. If +.Ar /n +is omitted, it defaults to +.Ar /32 +unless the IP address is 0.0.0.0 in which case it defaults to +.Ar /0 . .Pp .Ar Hisaddr may also be specified as a range of IP numbers in the format +.Pp .Dl a.b.c.d[-d.e.f.g][,h.i.j.k[-l,m,n,o]]... +.Pp for example: +.Pp .Dl set ifaddr 10.0.0.1 10.0.1.2-10.0.1.10,10.0.1.20 +.Pp will only negotiate .Ar 10.0.0.1 -as the local IP number, but will assign any of the given 10 IP +as the local IP number, but may assign any of the given 10 IP numbers to the peer. If the peer requests one of these numbers, and that number is not already in use, .Nm will grant the peers request. This is useful if the peer wants to re-establish a link using the same IP number as was previously -allocated. If the peer requests an IP number that's either outside +allocated (thus maintaining any existing tcp connections). +.Pp +If the peer requests an IP number that's either outside of this range or is already in use, .Nm -will start by suggesting a random unused IP number from the range. -If the peer doesn't subsequently agree, -.Nm -will suggest each of the other numbers in succession until a number -is chosen or until too many IPCP Configure Requests have been sent. +will suggest a random unused IP number from the range. .Pp If .Ar triggeraddr @@ -2180,7 +3090,11 @@ is specified, it is used in place of .Ar myaddr in the initial IPCP negotiation. However, only an address in the .Ar myaddr -range will be accepted. +range will be accepted. This is useful when negotiating with some +.Dv PPP +implementations that will not assign an IP number unless their peer +requests +.Ar 0.0.0.0 . .Pp It should be noted that in .Fl auto @@ -2189,71 +3103,97 @@ mode, will configure the interface immediately upon reading the .Dq set ifaddr line in the config file. In any other mode, these values are just -used for the IPCP negotiations, and the interface isn't configured -until the IPCP layer is up. As a result, it is impossible -.Pq or at least unwise -to use the -.Dq add -command in -.Pa ppp.conf -unless using -.Fl auto -mode (the -.Pa ppp.linkup -file should be used instead). Use -.Dq allow mode auto -to restrict the current profile to -.Fl auto -mode only. +used for IPCP negotiations, and the interface isn't configured +until the IPCP layer is up. .Pp -Note also that the -.Ar hisaddr -argument may be overridden in the +Note that the +.Ar HISADDR +argument may be overridden by the third field in the .Pa ppp.secret -file once the client has authenticated themself. Refer to the +file once the client has authenticated itself +.Pq if PAP or CHAP are Dq enabled . +Refer to the .Em AUTHENTICATING INCOMING CONNECTIONS section for details. -.It set loopback on|off -When set to -.Ar on -(the default), -.Nm -will automatically loop back packets being sent -out with a destination address equal to that of the -.Em PPP -interface. If set to -.Ar off , -.Nm -will send the packet, probably resulting in an ICMP redirect from -the other end. -.It set log [local] [+|-]value... +.Pp +In all cases, if the interface is already configured, +.Nm +will try to maintain the interface IP numbers so that any existing +bound sockets will remain valid. +.It set ccpretry Ar period +.It set chapretry Ar period +.It set ipcpretry Ar period +.It set lcpretry Ar period +.It set papretry Ar period +These commands set the number of seconds that +.Nm +will wait before resending Finite State Machine (FSM) Request packets. +The default +.Ar period +for all FSMs is 3 seconds (which should suffice in most cases). +.It set log [local] [+|-] Ns Ar value... This command allows the adjustment of the current log level. Refer to the Logging Facility section for further details. -.It set login chat-script +.It set login Ar chat-script This .Ar chat-script compliments the dial-script. If both are specified, the login script will be executed after the dial script. Escape sequences available in the dial script are also available here. -.It set mru value -The default MRU is 1500. If it is increased, the other side *may* -increase its mtu. There is no use decreasing the MRU to below the -default as the +.It set lqrperiod Ar frequency +This command sets the +.Ar frequency +in seconds at which +.Em LQR +or +.Em ECHO LQR +packets are sent. The default is 30 seconds. You must also use the +.Dq enable lqr +command if you wish to send LQR requests to the peer. +.It set mode Ar interactive|auto|ddial|background +This command allows you to change the +.Sq mode +of the specified link. This is normally only useful in multi-link mode, +but may also be used in uni-link mode. +.Pp +It is not possible to change a link that is +.Sq direct +or +.Sq dedicated . +.It set mrru Op Ar value +Setting this option enables Multi-link PPP negotiations, also known as +Multi-link Protocol or MP. There is no default MRRU (Maximum +Reconstructed Receive Unit) value. If no argument is given, multi-link +mode is disabled. +.It set mru Op Ar value +The default MRU (Maximum Receive Unit) is 1500. If it is increased, the +other side *may* increase its mtu. There is no point in decreasing the +MRU to below the default as the .Em PPP -protocol *must* be able to accept packets of at -least 1500 octets. -.It set mtu value -The default MTU is 1500. This may be increased by the MRU specified -by the peer. It may only be subsequently decreased by this option. -Increasing it is not valid as the peer is not necessarily able to -receive the increased packet size. -.It set ns x.x.x.x y.y.y.y -This option allows the setting of the Microsoft DNS servers that -will be negotiated. -.It set nbns x.x.x.x y.y.y.y -This option allows the setting of the Microsoft NetBIOS DNS servers that -will be negotiated. -.It set openmode active|passive Op delay +protocol *must* be able to accept packets of at least 1500 octets. If +no argument is given, 1500 is assumed. +.It set mtu Op Ar value +The default MTU is 1500. At negotiation time, +.Nm +will accept whatever MRU or MRRU that the peer wants (assuming it's +not less than 296 bytes). If the MTU is set, +.Nm +will not accept MRU/MRRU values less than +.Ar value . +When negotiations are complete, the MTU is assigned to the interface, even +if the peer requested a higher value MRU/MRRU. This can be useful for +limiting your packet size (giving better bandwidth sharing at the expense +of more header data). +.Pp +If no +.Ar value +is given, 1500, or whatever the peer asks for is used. +.It set nbns Op Ar x.x.x.x Op Ar y.y.y.y +This option allows the setting of the Microsoft NetBIOS name server +values to be returned at the peers request. If no values are given, +.Nm +will reject any such requests. +.It set openmode active|passive Op Ar delay By default, .Ar openmode is always @@ -2273,7 +3213,7 @@ may be specified here in seconds. .It set parity odd|even|none|mark This allows the line parity to be set. The default value is .Ar none . -.It set phone telno[|telno]...[:telno[|telno]...]... +.It set phone Ar telno[|telno]...[:telno[|telno]...]... This allows the specification of the phone number to be used in place of the \\\\T string in the dial and login chat scripts. Multiple phone numbers may be given separated by a pipe (|) or @@ -2288,7 +3228,7 @@ the maximum number of times specified by below. In .Fl background mode, each number is attempted at most once. -.It set reconnect timeout ntries +.It set reconnect Ar timeout ntries Should the line drop unexpectedly (due to loss of CD or LQR failure), a connection will be re-established after the given .Ar timeout . @@ -2301,11 +3241,11 @@ defaults to zero. A value of for .Ar timeout will result in a variable pause, somewhere between 0 and 30 seconds. -.It set redial seconds[.nseconds] [attempts] +.It set redial Ar seconds[.nseconds] [attempts] .Nm Ppp can be instructed to attempt to redial .Ar attempts -times. If more than one number is specified (see +times. If more than one phone number is specified (see .Dq set phone above), a pause of .Ar nseconds @@ -2313,48 +3253,40 @@ is taken before dialing each number. A pause of .Ar seconds is taken before starting at the first number again. A value of .Ar random -may be used here too. -.It set stopped [LCPseconds [IPCPseconds [CCPseconds]]] -If this option is set, -.Nm -will time out after the given FSM (Finite State Machine) has been in -the stopped state for the given number of -.Dq seconds . -This option may be useful if you see -.Nm -failing to respond in the stopped state, or if you wish to -.Dq set openmode passive -and time out if the peer doesn't send a Configure Request within the -given time. Use -.Dq set log +lcp +ipcp +ccp -to make -.Nm -log all state transitions. -.Pp -The default value is zero, where -.Nm -doesn't time out in the stopped state. +may be used here in place of +.Ar seconds +and +.Ar nseconds , +causing a random delay of between 0 and 30 seconds. .Pp -This value should not be set to less than the openmode delay (see -.Dq set openmode -above). -.It set server|socket TcpPort|LocalName|none [password] [mask] +Note, this delay will be effective, even after +.Ar attempts +has been exceeded, so an immediate manual dial may appear to have +done nothing. If an immediate dial is required, a +.Dq \&! +should immediately follow the +.Dq open +keyword. See the +.Dq open +description above for further details. +.It set server|socket Ar TcpPort|LocalName|none password Op Ar mask This command tells .Nm to listen on the given socket or .Sq diagnostic port -for incoming command connections. This is not possible if -.Nm -is in interactive mode. The word +for incoming command connections. +.Pp +The word .Ar none instructs .Nm -to close any existing socket. If you wish to specify a unix domain -socket, +to close any existing socket. +.Pp +If you wish to specify a local domain socket, .Ar LocalName must be specified as an absolute file name, otherwise it is assumed to be the name or number of a TCP port. You may specify the octal umask that -should be used with unix domain sockets as a four character octal number +should be used with local domain sockets as a four character octal number beginning with .Sq 0 . Refer to @@ -2363,14 +3295,22 @@ for umask details. Refer to .Xr services 5 for details of how to translate TCP port names. .Pp -You may also specify the password that must be used by the client when -connecting to this socket. If the password is not specified here, -.Pa /etc/ppp/ppp.secret -is searched for a machine name that's the same as your local host name -without any domain suffix. Refer to -.Xr hostname 1 -for further details. If a password is specified as the empty string, -no password is required. +You must also specify the password that must be entered by the client +(using the +.Dq passwd +command above) when connecting to this socket. If the password is +specified as an empty string, no password is required for connecting clients. +.Pp +When specifying a local domain socket, the first +.Dq %d +sequence found in the socket name will be replaced with the current +interface unit number. This is useful when you wish to use the same +profile for more than one connection. +.Pp +In a similar manner TCP sockets may be prefixed with the +.Dq + +character, in which case the current interface unit number is added to +the port number. .Pp When using .Nm @@ -2381,17 +3321,45 @@ command is the preferred mechanism of communications. Currently, can also be used, but link encryption may be implemented in the future, so .Xr telnet 1 should not be relied upon. -.It set speed value +.It set speed Ar value This sets the speed of the serial device. -.It set timeout idle [LQR [FSM-resend]] -This command allows the setting of the idle timer, the LQR timer (if -enabled) and the finite state machine -.Pq FSM -retry timer. -.It set vj slots nslots -This command sets the initial number of -.Ar slots -that +.It set stopped Ar [LCPseconds [CCPseconds]] +If this option is set, +.Nm +will time out after the given FSM (Finite State Machine) has been in +the stopped state for the given number of +.Dq seconds . +This option may be useful if the peer sends a terminate request, +but never actually closes the connection despite our sending a terminate +acknowledgement. This is also useful if you wish to +.Dq set openmode passive +and time out if the peer doesn't send a Configure Request within the +given time. Use +.Dq set log +lcp +ccp +to make +.Nm +log the appropriate state transitions. +.Pp +The default value is zero, where +.Nm +doesn't time out in the stopped state. +.Pp +This value should not be set to less than the openmode delay (see +.Dq set openmode +above). +.It set timeout Ar idleseconds +This command allows the setting of the idle timer. Refer to the +section titled +.Dq SETTING THE IDLE TIMER +for further details. +.It set vj slotcomp on|off +This command tells +.Nm +whether it should attempt to negotiate VJ slot compression. By default, +slot compression is turned +.Ar on . +.It set vj slots Ar nslots +This command sets the initial number of slots that .Nm will try to negotiate with the peer when VJ compression is enabled (see the .Sq enable @@ -2402,88 +3370,70 @@ must be between and .Ar 16 inclusive. -.It set vj slotcomp on|off -This command tells -.Nm -whether it should attempt to negotiate VJ slot compression. By default, -slot compression is turned -.Ar on . -.It set help|? -This command gives a summary of available set commands. .El .Pp -.It shell|! [command] +.It shell|! Op Ar command If -.Dq command +.Ar command is not specified a shell is invoked according to the .Dv SHELL -environment variable. Otherwise, the given command is executed. -Any of the pseudo arguments -.Dv HISADDR , -.Dv INTERFACE -and -.Dv MYADDR -will be replaced with the appropriate values. Use of the ! character -requires a following space as with any other commands. You should note -that this command is executed in the foreground - +environment variable. Otherwise, the given +.Ar command +is executed. Word replacement is done in the same way as for the +.Dq !bg +commanad as described above. +.Pp +Use of the ! character +requires a following space as with any of the other commands. You should +note that this command is executed in the foreground - .Nm will not continue running until this process has exited. Use the .Dv bg command if you wish processing to happen in the background. -.It show var +.It show Ar var This command allows the user to examine the following: -.Bl -tag -width 20 -.It show [adio]filter -List the current rules for the given filter. -.It show auth -Show the current authname and encryption values. If you have built -.Nm -without DES support, the encryption value is not displayed as it will -always be -.Ar MD5 . +.Bl -tag -width XX +.It show bundle +Show the current bundle settings. .It show ccp -Show the current CCP statistics. +Show the current CCP compression statistics. .It show compress -Show the current compress statistics. +Show the current VJ compression statistics. .It show escape Show the current escape characters. +.It show filter Op Ar name +List the current rules for the given filter. If +.Ar name +is not specified, all filters are shown. .It show hdlc Show the current HDLC statistics. +.It show help|? +Give a summary of available show commands. .It show ipcp Show the current IPCP statistics. .It show lcp Show the current LCP statistics. -.It show loopback -Show the current loopback status. +.It show [data]link +Show high level link information. +.It show links +Show a list of available logical links. .It show log Show the current log values. .It show mem Show current memory statistics. .It show modem -Show current modem statistics. -.It show mru -Show the current MRU. -.It show mtu -Show the current MTU. +Show low level link information. .It show proto Show current protocol totals. -.It show reconnect -Show the current reconnect values. -.It show redial -Show the current redial values. -.It show stopped -Show the current stopped timeouts. .It show route Show the current routing tables. -.It show timeout -Show the current timeout values. -.It show msext -Show the current Microsoft extension values. +.It show stopped +Show the current stopped timeouts. +.It show timer +Show the active alarm timers. .It show version Show the current version number of .Nm ppp . -.It show help|? -Give a summary of available show commands. .El .Pp .It term @@ -2497,7 +3447,7 @@ automatically enables Packet Mode and goes back into command mode. .El .Pp .Sh MORE DETAILS -.Bl -bullet -compact +.Bl -bullet .It Read the example configuration files. They are a good source of information. .It @@ -2508,7 +3458,16 @@ Use .Dq set ? and .Dq set ? <var> -commands. +to get online information about what's available. +.It +The following urls contain useful information: +.Bl -bullet -compact +.It +http://www.FreeBSD.org/FAQ/userppp.html +.It +http://www.FreeBSD.org/handbook/userppp.html +.El +.Pp .El .Pp .Sh FILES @@ -2522,7 +3481,7 @@ and These files are placed in the .Pa /etc/ppp directory. -.Bl -tag -width flag +.Bl -tag -width XX .It Pa /etc/ppp/ppp.conf System default configuration file. .It Pa /etc/ppp/ppp.secret @@ -2550,12 +3509,7 @@ The process id (pid) of the .Nm program connected to the tunN device, where .Sq N -is the number of the device. This file is only created in -.Fl background , -.Fl auto -and -.Fl ddial -modes. +is the number of the device. .It Pa /var/run/ttyXX.if The tun interface used by this port. Again, this file is only created in .Fl background , @@ -2565,34 +3519,56 @@ and modes. .It Pa /etc/services Get port number if port number is using service name. +.It Pa /var/run/ppp-authname-class-value +In multi-link mode, local domain sockets are created using the peer +authentication name +.Pq Sq authname , +the peer endpoint discriminator class +.Pq Sq class +and the peer endpoint discriminator value +.Pq Sq value . +As the endpoint discriminator value may be a binary value, it is turned +to HEX to determine the actual file name. +.Pp +This socket is used to pass links between different instances of +.Nm ppp . .El .Pp .Sh SEE ALSO +.Xr adduser 8 , .Xr at 1 , .Xr chat 8 , .Xr crontab 5 , .Xr ftp 1 , .Xr getty 8 , +.Xr group 5 , .Xr gzip 1 , .Xr hostname 1 , .Xr inetd 8 , .Xr init 8 , .Xr login 1 , +.Xr named 8 , .Xr passwd 5 , .Xr ping 8 , .Xr pppctl 8 , .Xr pppd 8 , .Xr route 8 , +.Xr resolv.conf 5 , .Xr syslog 3 , .Xr syslog.conf 5 , .Xr syslogd 8 , .Xr tcpdump 1 , .Xr telnet 1 , .Xr traceroute 8 , -.Xr uucplock 3 +.Xr uucplock 3 , +.Xr vipw 8 .Sh HISTORY This program was originally written by Toshiharu OHNO (tony-o@iij.ad.jp), and was submitted to FreeBSD-2.0.5 by Atsushi Murai (amurai@spec.co.jp). .Pp -It has since been substantially modified by Brian Somers (brian@Awfulhak.org), -and was ported to OpenBSD in November '97 (just after the 2.2 release). +It was substantially modified during 1997 by Brian Somers +(brian@Awfulhak.org), and was ported to OpenBSD in November that year +(just after the 2.2 release). +.Pp +Most of the code was rewritten by Brian Somers in early 1998 when +multi-link ppp support was added. diff --git a/usr.sbin/ppp/pred.c b/usr.sbin/ppp/ppp/pred.c index 85b751d5fa0..0480e61cfb3 100644 --- a/usr.sbin/ppp/pred.c +++ b/usr.sbin/ppp/ppp/pred.c @@ -26,26 +26,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pred.c,v 1.4 1998/01/14 01:48:19 brian Exp $ + * $Id: pred.c,v 1.1 1998/08/31 00:22:26 brian Exp $ */ -#include <sys/param.h> -#include <netinet/in.h> +#include <sys/types.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> -#include "command.h" +#include "defs.h" #include "mbuf.h" #include "log.h" -#include "defs.h" -#include "loadalias.h" -#include "vars.h" #include "timer.h" #include "fsm.h" +#include "lqr.h" #include "hdlc.h" -#include "lcpproto.h" #include "lcp.h" #include "ccp.h" #include "pred.h" @@ -56,16 +51,16 @@ * A better hash function would result in additional compression, * at the expense of time. */ -#define IHASH(x) do {iHash = (iHash << 4) ^ (x);} while(0) -#define OHASH(x) do {oHash = (oHash << 4) ^ (x);} while(0) +#define HASH(state, x) state->hash = (state->hash << 4) ^ (x) #define GUESS_TABLE_SIZE 65536 -static unsigned short int iHash, oHash; -static unsigned char *InputGuessTable; -static unsigned char *OutputGuessTable; +struct pred1_state { + u_short hash; + u_char dict[GUESS_TABLE_SIZE]; +}; static int -compress(u_char * source, u_char * dest, int len) +compress(struct pred1_state *state, u_char *source, u_char *dest, int len) { int i, bitmask; unsigned char *flagdest, flags, *orgdest; @@ -75,13 +70,13 @@ compress(u_char * source, u_char * dest, int len) flagdest = dest++; flags = 0; /* All guess wrong initially */ for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { - if (OutputGuessTable[oHash] == *source) { + if (state->dict[state->hash] == *source) { flags |= bitmask; /* Guess was right - don't output */ } else { - OutputGuessTable[oHash] = *source; + state->dict[state->hash] = *source; *dest++ = *source; /* Guess wrong, output char */ } - OHASH(*source++); + HASH(state, *source++); len--; } *flagdest = flags; @@ -90,19 +85,17 @@ compress(u_char * source, u_char * dest, int len) } static void -SyncTable(u_char * source, u_char * dest, int len) +SyncTable(struct pred1_state *state, u_char * source, u_char * dest, int len) { - while (len--) { - if (InputGuessTable[iHash] != *source) { - InputGuessTable[iHash] = *source; - } - IHASH(*dest++ = *source++); + if (state->dict[state->hash] != *source) + state->dict[state->hash] = *source; + HASH(state, *dest++ = *source++); } } static int -decompress(u_char * source, u_char * dest, int len) +decompress(struct pred1_state *state, u_char * source, u_char * dest, int len) { int i, bitmask; unsigned char flags, *orgdest; @@ -113,157 +106,151 @@ decompress(u_char * source, u_char * dest, int len) len--; for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { if (flags & bitmask) { - *dest = InputGuessTable[iHash]; /* Guess correct */ + *dest = state->dict[state->hash]; /* Guess correct */ } else { if (!len) break; /* we seem to be really done -- cabo */ - InputGuessTable[iHash] = *source; /* Guess wrong */ + state->dict[state->hash] = *source; /* Guess wrong */ *dest = *source++; /* Read from source */ len--; } - IHASH(*dest++); + HASH(state, *dest++); } } return (dest - orgdest); } static void -Pred1TermInput(void) +Pred1Term(void *v) { - if (InputGuessTable != NULL) { - free(InputGuessTable); - InputGuessTable = NULL; - } + struct pred1_state *state = (struct pred1_state *)v; + free(state); } static void -Pred1TermOutput(void) +Pred1ResetInput(void *v) { - if (OutputGuessTable != NULL) { - free(OutputGuessTable); - OutputGuessTable = NULL; - } + struct pred1_state *state = (struct pred1_state *)v; + state->hash = 0; + memset(state->dict, '\0', sizeof state->dict); + log_Printf(LogCCP, "Predictor1: Input channel reset\n"); } static void -Pred1ResetInput(void) +Pred1ResetOutput(void *v) { - iHash = 0; - memset(InputGuessTable, '\0', GUESS_TABLE_SIZE); - LogPrintf(LogCCP, "Predictor1: Input channel reset\n"); + struct pred1_state *state = (struct pred1_state *)v; + state->hash = 0; + memset(state->dict, '\0', sizeof state->dict); + log_Printf(LogCCP, "Predictor1: Output channel reset\n"); } -static void -Pred1ResetOutput(void) +static void * +Pred1InitInput(struct lcp_opt *o) { - oHash = 0; - memset(OutputGuessTable, '\0', GUESS_TABLE_SIZE); - LogPrintf(LogCCP, "Predictor1: Output channel reset\n"); + struct pred1_state *state; + state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); + if (state != NULL) + Pred1ResetInput(state); + return state; } -static int -Pred1InitInput(void) +static void * +Pred1InitOutput(struct lcp_opt *o) { - if (InputGuessTable == NULL) - if ((InputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) - return 0; - Pred1ResetInput(); - return 1; + struct pred1_state *state; + state = (struct pred1_state *)malloc(sizeof(struct pred1_state)); + if (state != NULL) + Pred1ResetOutput(state); + return state; } static int -Pred1InitOutput(void) -{ - if (OutputGuessTable == NULL) - if ((OutputGuessTable = malloc(GUESS_TABLE_SIZE)) == NULL) - return 0; - Pred1ResetOutput(); - return 1; -} - -static int -Pred1Output(int pri, u_short proto, struct mbuf * bp) +Pred1Output(void *v, struct ccp *ccp, struct link *l, int pri, u_short proto, + struct mbuf *bp) { + struct pred1_state *state = (struct pred1_state *)v; struct mbuf *mwp; u_char *cp, *wp, *hp; int orglen, len; u_char bufp[MAX_MTU + 2]; u_short fcs; - orglen = plength(bp) + 2; /* add count of proto */ - mwp = mballoc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); + orglen = mbuf_Length(bp) + 2; /* add count of proto */ + mwp = mbuf_Alloc((orglen + 2) / 8 * 9 + 12, MB_HDLCOUT); hp = wp = MBUF_CTOP(mwp); cp = bufp; *wp++ = *cp++ = orglen >> 8; *wp++ = *cp++ = orglen & 0377; *cp++ = proto >> 8; *cp++ = proto & 0377; - mbread(bp, cp, orglen - 2); - fcs = HdlcFcs(INITFCS, bufp, 2 + orglen); + mbuf_Read(bp, cp, orglen - 2); + fcs = hdlc_Fcs(INITFCS, bufp, 2 + orglen); fcs = ~fcs; - len = compress(bufp + 2, wp, orglen); - LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); - CcpInfo.uncompout += orglen; + len = compress(state, bufp + 2, wp, orglen); + log_Printf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); + ccp->uncompout += orglen; if (len < orglen) { *hp |= 0x80; wp += len; - CcpInfo.compout += len; + ccp->compout += len; } else { memcpy(wp, bufp + 2, orglen); wp += orglen; - CcpInfo.compout += orglen; + ccp->compout += orglen; } *wp++ = fcs & 0377; *wp++ = fcs >> 8; mwp->cnt = wp - MBUF_CTOP(mwp); - HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp); + hdlc_Output(l, PRI_NORMAL, ccp_Proto(ccp), mwp); return 1; } static struct mbuf * -Pred1Input(u_short *proto, struct mbuf *bp) +Pred1Input(void *v, struct ccp *ccp, u_short *proto, struct mbuf *bp) { + struct pred1_state *state = (struct pred1_state *)v; u_char *cp, *pp; int len, olen, len1; struct mbuf *wp; u_char *bufp; u_short fcs; - wp = mballoc(MAX_MTU + 2, MB_IPIN); + wp = mbuf_Alloc(MAX_MTU + 2, MB_IPIN); cp = MBUF_CTOP(bp); - olen = plength(bp); + olen = mbuf_Length(bp); pp = bufp = MBUF_CTOP(wp); *pp++ = *cp & 0177; len = *cp++ << 8; *pp++ = *cp; len += *cp++; - CcpInfo.uncompin += len & 0x7fff; + ccp->uncompin += len & 0x7fff; if (len & 0x8000) { - len1 = decompress(cp, pp, olen - 4); - CcpInfo.compin += olen; + len1 = decompress(state, cp, pp, olen - 4); + ccp->compin += olen; len &= 0x7fff; if (len != len1) { /* Error is detected. Send reset request */ - LogPrintf(LogCCP, "Pred1: Length error\n"); - CcpSendResetReq(&CcpFsm); - pfree(bp); - pfree(wp); + log_Printf(LogCCP, "Pred1: Length error\n"); + ccp_SendResetReq(&ccp->fsm); + mbuf_Free(bp); + mbuf_Free(wp); return NULL; } cp += olen - 4; pp += len1; } else { - CcpInfo.compin += len; - SyncTable(cp, pp, len); + ccp->compin += len; + SyncTable(state, cp, pp, len); cp += len; pp += len; } *pp++ = *cp++; /* CRC */ *pp++ = *cp++; - fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp); + fcs = hdlc_Fcs(INITFCS, bufp, wp->cnt = pp - bufp); if (fcs != GOODFCS) - LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," + log_Printf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", len, olen); if (fcs == GOODFCS) { @@ -279,19 +266,19 @@ Pred1Input(u_short *proto, struct mbuf *bp) wp->cnt -= 2; *proto = (*proto << 8) | *pp++; } - pfree(bp); + mbuf_Free(bp); return wp; } else { - LogDumpBp(LogHDLC, "Bad FCS", wp); - CcpSendResetReq(&CcpFsm); - pfree(wp); + log_DumpBp(LogHDLC, "Bad FCS", wp); + ccp_SendResetReq(&ccp->fsm); + mbuf_Free(wp); } - pfree(bp); + mbuf_Free(bp); return NULL; } static void -Pred1DictSetup(u_short proto, struct mbuf * bp) +Pred1DictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf * bp) { } @@ -302,40 +289,44 @@ Pred1DispOpts(struct lcp_opt *o) } static void -Pred1GetOpts(struct lcp_opt *o) +Pred1InitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg) { - o->id = TY_PRED1; o->len = 2; } static int -Pred1SetOpts(struct lcp_opt *o) +Pred1SetOptsOutput(struct lcp_opt *o) { - if (o->id != TY_PRED1 || o->len != 2) { - Pred1GetOpts(o); + if (o->len != 2) { + o->len = 2; return MODE_NAK; } return MODE_ACK; } +static int +Pred1SetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg) +{ + return Pred1SetOptsOutput(o); +} + const struct ccp_algorithm Pred1Algorithm = { TY_PRED1, - ConfPred1, + CCP_NEG_PRED1, Pred1DispOpts, { - Pred1GetOpts, - Pred1SetOpts, + Pred1SetOptsInput, Pred1InitInput, - Pred1TermInput, + Pred1Term, Pred1ResetInput, Pred1Input, Pred1DictSetup }, { - Pred1GetOpts, - Pred1SetOpts, + Pred1InitOptsOutput, + Pred1SetOptsOutput, Pred1InitOutput, - Pred1TermOutput, + Pred1Term, Pred1ResetOutput, Pred1Output }, diff --git a/usr.sbin/ppp/pred.h b/usr.sbin/ppp/ppp/pred.h index f9a5715bba3..d2fb046a298 100644 --- a/usr.sbin/ppp/pred.h +++ b/usr.sbin/ppp/ppp/pred.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pred.h,v 1.2 1997/12/06 12:09:03 brian Exp $ + * $Id: pred.h,v 1.1 1998/08/31 00:22:26 brian Exp $ * * TODO: */ diff --git a/usr.sbin/ppp/ppp/probe.c b/usr.sbin/ppp/ppp/probe.c new file mode 100644 index 00000000000..fd6c5e5c8e0 --- /dev/null +++ b/usr.sbin/ppp/ppp/probe.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: probe.c,v 1.1 1998/08/31 00:22:26 brian Exp $ + */ + +#include <sys/time.h> +#include <unistd.h> + +#include "probe.h" +#include "log.h" + +/* Does select() alter the passed time value ? */ +static int +select_changes_time(void) +{ + struct timeval t; + + t.tv_sec = 0; + t.tv_usec = 100000; + select(0, NULL, NULL, NULL, &t); + return t.tv_usec != 100000; +} + +void +probe_Init(struct probe *p) +{ + p->select_changes_time = select_changes_time() ? 1 : 0; + log_Printf(LogDEBUG, "Select changes time: %s\n", + p->select_changes_time ? "yes" : "no"); +} diff --git a/usr.sbin/ppp/server.h b/usr.sbin/ppp/ppp/probe.h index c30da6bd136..e8d68facfce 100644 --- a/usr.sbin/ppp/server.h +++ b/usr.sbin/ppp/ppp/probe.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,11 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: server.h,v 1.2 1997/12/21 14:27:13 brian Exp $ + * $Id: probe.h,v 1.1 1998/08/31 00:22:27 brian Exp $ */ -extern int server; +struct probe { + unsigned select_changes_time : 1; +}; -extern int ServerLocalOpen(const char *, mode_t); -extern int ServerTcpOpen(int); -extern void ServerClose(void); +extern void probe_Init(struct probe *); diff --git a/usr.sbin/ppp/ppp/prompt.c b/usr.sbin/ppp/ppp/prompt.c new file mode 100644 index 00000000000..81034155678 --- /dev/null +++ b/usr.sbin/ppp/ppp/prompt.c @@ -0,0 +1,551 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: prompt.c,v 1.1 1998/08/31 00:22:27 brian Exp $ + */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/fcntl.h> +#include <termios.h> +#include <unistd.h> + +#include "defs.h" +#include "timer.h" +#include "command.h" +#include "log.h" +#include "descriptor.h" +#include "prompt.h" +#include "fsm.h" +#include "lcp.h" +#include "auth.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" +#include "mbuf.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "filter.h" +#include "async.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "chat.h" +#include "chap.h" +#include "cbcp.h" +#include "datalink.h" +#include "server.h" +#include "main.h" + +static void +prompt_Display(struct prompt *p) +{ + /* XXX: See Index2Nam() - should we only figure this out once ? */ + static char shostname[MAXHOSTNAMELEN]; + const char *pconnect, *pauth; + + if (p->TermMode || !p->needprompt) + return; + + p->needprompt = 0; + + if (p->nonewline) + p->nonewline = 0; + else + fprintf(p->Term, "\n"); + + if (p->auth == LOCAL_AUTH) + pauth = " ON "; + else + pauth = " on "; + + if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) + pconnect = "PPP"; + else if (bundle_Phase(p->bundle) == PHASE_NETWORK) + pconnect = "PPp"; + else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) + pconnect = "Ppp"; + else + pconnect = "ppp"; + + if (*shostname == '\0') { + char *dot; + + if (gethostname(shostname, sizeof shostname)) + strcpy(shostname, "localhost"); + else if ((dot = strchr(shostname, '.'))) + *dot = '\0'; + } + + fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); + fflush(p->Term); +} + +static int +prompt_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + struct prompt *p = descriptor2prompt(d); + int sets; + + sets = 0; + + if (!p->active) + return sets; + + if (p->fd_in >= 0) { + if (r) { + FD_SET(p->fd_in, r); + log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); + sets++; + } + if (e) { + FD_SET(p->fd_in, e); + log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); + sets++; + } + if (sets && *n < p->fd_in + 1) + *n = p->fd_in + 1; + } + + prompt_Display(p); + + return sets; +} + +static int +prompt_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct prompt *p = descriptor2prompt(d); + return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); +} + + +static void +prompt_ShowHelp(struct prompt *p) +{ + prompt_Printf(p, "The following commands are available:\n"); + prompt_Printf(p, " ~p\tEnter Packet mode\n"); + prompt_Printf(p, " ~t\tShow timers\n"); + prompt_Printf(p, " ~m\tShow memory map\n"); + prompt_Printf(p, " ~.\tTerminate program\n"); + prompt_Printf(p, " ~?\tThis help\n"); +} + +static void +prompt_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct prompt *p = descriptor2prompt(d); + int n; + char ch; + char linebuff[LINE_LEN]; + + if (p->TermMode == NULL) { + n = read(p->fd_in, linebuff, sizeof linebuff - 1); + if (n > 0) { + if (linebuff[n-1] == '\n') + linebuff[--n] = '\0'; + else + linebuff[n] = '\0'; + p->nonewline = 1; /* Maybe command_Decode does a prompt */ + prompt_Required(p); + if (n) + command_Decode(bundle, linebuff, n, p, p->src.from); + } else if (n <= 0) { + log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); + if (!p->owner) + Cleanup(EX_NORMAL); + prompt_Destroy(p, 0); + } + return; + } + + switch (p->TermMode->state) { + case DATALINK_CLOSED: + prompt_Printf(p, "Link lost, terminal mode.\n"); + prompt_TtyCommandMode(p); + p->nonewline = 0; + prompt_Required(p); + return; + + case DATALINK_READY: + break; + + case DATALINK_OPEN: + prompt_Printf(p, "\nPacket mode detected.\n"); + prompt_TtyCommandMode(p); + p->nonewline = 0; + /* We'll get a prompt because of our status change */ + /* Fall through */ + + default: + /* Wait 'till we're in a state we care about */ + return; + } + + /* + * We are in terminal mode, decode special sequences + */ + n = read(p->fd_in, &ch, 1); + log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); + + if (n > 0) { + switch (p->readtilde) { + case 0: + if (ch == '~') + p->readtilde = 1; + else + if (physical_Write(p->TermMode->physical, &ch, n) < 0) { + log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); + prompt_TtyCommandMode(p); + } + break; + case 1: + switch (ch) { + case '?': + prompt_ShowHelp(p); + break; + case 'p': + datalink_Up(p->TermMode, 0, 1); + prompt_Printf(p, "\nPacket mode.\n"); + prompt_TtyCommandMode(p); + break; + case '.': + prompt_TtyCommandMode(p); + p->nonewline = 0; + prompt_Required(p); + break; + case 't': + timer_Show(0, p); + break; + case 'm': + { + struct cmdargs arg; + + arg.cmdtab = NULL; + arg.cmd = NULL; + arg.argc = 0; + arg.argn = 0; + arg.argv = NULL; + arg.bundle = bundle; + arg.cx = p->TermMode; + arg.prompt = p; + + mbuf_Show(&arg); + } + break; + default: + if (physical_Write(p->TermMode->physical, &ch, n) < 0) { + log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); + prompt_TtyCommandMode(p); + } + break; + } + p->readtilde = 0; + break; + } + } +} + +static int +prompt_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + /* We never want to write here ! */ + log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); + return 0; +} + +struct prompt * +prompt_Create(struct server *s, struct bundle *bundle, int fd) +{ + struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); + + if (p != NULL) { + p->desc.type = PROMPT_DESCRIPTOR; + p->desc.UpdateSet = prompt_UpdateSet; + p->desc.IsSet = prompt_IsSet; + p->desc.Read = prompt_Read; + p->desc.Write = prompt_Write; + + if (fd == PROMPT_STD) { + char *tty = ttyname(STDIN_FILENO); + + if (!tty) { + free(p); + return NULL; + } + p->fd_in = STDIN_FILENO; + p->fd_out = STDOUT_FILENO; + p->Term = stdout; + p->owner = NULL; + p->auth = LOCAL_AUTH; + p->src.type = "Controller"; + strncpy(p->src.from, tty, sizeof p->src.from - 1); + p->src.from[sizeof p->src.from - 1] = '\0'; + tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ + } else { + p->fd_in = p->fd_out = fd; + p->Term = fdopen(fd, "a+"); + p->owner = s; + p->auth = *s->passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; + p->src.type = "unknown"; + *p->src.from = '\0'; + } + p->TermMode = NULL; + p->nonewline = 1; + p->needprompt = 1; + p->readtilde = 0; + p->bundle = bundle; + log_RegisterPrompt(p); + } + + return p; +} + +void +prompt_Destroy(struct prompt *p, int verbose) +{ + if (p) { + if (p->Term != stdout) { + fclose(p->Term); + close(p->fd_in); + if (p->fd_out != p->fd_in) + close(p->fd_out); + if (verbose) + log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); + } else + prompt_TtyOldMode(p); + + log_UnRegisterPrompt(p); + free(p); + } +} + +void +prompt_Printf(struct prompt *p, const char *fmt,...) +{ + if (p && p->active) { + va_list ap; + + va_start(ap, fmt); + prompt_vPrintf(p, fmt, ap); + va_end(ap); + } +} + +void +prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) +{ + if (p && p->active) { + char nfmt[LINE_LEN]; + const char *pfmt; + + if (p->TermMode) { + /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ + int len = strlen(fmt); + + if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n') { + strcpy(nfmt, fmt); + strcpy(nfmt + len - 1, "\r\n"); + pfmt = nfmt; + } else + pfmt = fmt; + } else + pfmt = fmt; + vfprintf(p->Term, pfmt, ap); + fflush(p->Term); + p->nonewline = 1; + } +} + +void +prompt_TtyInit(struct prompt *p) +{ + int stat, fd = p ? p->fd_in : STDIN_FILENO; + struct termios newtio; + + stat = fcntl(fd, F_GETFL, 0); + if (stat > 0) { + stat |= O_NONBLOCK; + fcntl(fd, F_SETFL, stat); + } + + if (p) + newtio = p->oldtio; + else + tcgetattr(fd, &newtio); + + newtio.c_lflag &= ~(ECHO | ISIG | ICANON); + newtio.c_iflag = 0; + newtio.c_oflag &= ~OPOST; + if (!p) + newtio.c_cc[VINTR] = _POSIX_VDISABLE; + newtio.c_cc[VMIN] = 1; + newtio.c_cc[VTIME] = 0; + newtio.c_cflag |= CS8; + tcsetattr(fd, TCSANOW, &newtio); + if (p) + p->comtio = newtio; +} + +/* + * Set tty into command mode. We allow canonical input and echo processing. + */ +void +prompt_TtyCommandMode(struct prompt *p) +{ + struct termios newtio; + int stat; + + tcgetattr(p->fd_in, &newtio); + newtio.c_lflag |= (ECHO | ISIG | ICANON); + newtio.c_iflag = p->oldtio.c_iflag; + newtio.c_oflag |= OPOST; + tcsetattr(p->fd_in, TCSADRAIN, &newtio); + + stat = fcntl(p->fd_in, F_GETFL, 0); + if (stat > 0) { + stat |= O_NONBLOCK; + fcntl(p->fd_in, F_SETFL, stat); + } + + p->TermMode = NULL; +} + +/* + * Set tty into terminal mode which is used while we invoke term command. + */ +void +prompt_TtyTermMode(struct prompt *p, struct datalink *dl) +{ + int stat; + + if (p->Term == stdout) + tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); + + stat = fcntl(p->fd_in, F_GETFL, 0); + if (stat > 0) { + stat &= ~O_NONBLOCK; + fcntl(p->fd_in, F_SETFL, stat); + } + p->TermMode = dl; +} + +void +prompt_TtyOldMode(struct prompt *p) +{ + int stat; + + stat = fcntl(p->fd_in, F_GETFL, 0); + if (stat > 0) { + stat &= ~O_NONBLOCK; + fcntl(p->fd_in, F_SETFL, stat); + } + + if (p->Term == stdout) + tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); +} + +pid_t +prompt_pgrp(struct prompt *p) +{ + return tcgetpgrp(p->fd_in); +} + +int +PasswdCommand(struct cmdargs const *arg) +{ + const char *pass; + + if (!arg->prompt) { + log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); + return 0; + } + + if (arg->prompt->owner == NULL) { + log_Printf(LogWARN, "passwd: Not required\n"); + return 0; + } + + if (arg->argc == arg->argn) + pass = ""; + else if (arg->argc > arg->argn+1) + return -1; + else + pass = arg->argv[arg->argn]; + + if (!strcmp(arg->prompt->owner->passwd, pass)) + arg->prompt->auth = LOCAL_AUTH; + else + arg->prompt->auth = LOCAL_NO_AUTH; + + return 0; +} + +static struct pppTimer bgtimer; + +static void +prompt_TimedContinue(void *v) +{ + prompt_Continue((struct prompt *)v); +} + +void +prompt_Continue(struct prompt *p) +{ + timer_Stop(&bgtimer); + if (getpgrp() == prompt_pgrp(p)) { + prompt_TtyCommandMode(p); + p->nonewline = 1; + prompt_Required(p); + log_ActivatePrompt(p); + } else if (!p->owner) { + bgtimer.func = prompt_TimedContinue; + bgtimer.name = "prompt bg"; + bgtimer.load = SECTICKS; + bgtimer.arg = p; + timer_Start(&bgtimer); + } +} + +void +prompt_Suspend(struct prompt *p) +{ + if (getpgrp() == prompt_pgrp(p)) { + prompt_TtyOldMode(p); + log_DeactivatePrompt(p); + } +} diff --git a/usr.sbin/ppp/ppp/prompt.h b/usr.sbin/ppp/ppp/prompt.h new file mode 100644 index 00000000000..6f58cb6588a --- /dev/null +++ b/usr.sbin/ppp/ppp/prompt.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: prompt.h,v 1.1 1998/08/31 00:22:27 brian Exp $ + */ + +#define LOCAL_AUTH 0x01 +#define LOCAL_NO_AUTH 0x02 +#define LOCAL_DENY 0x03 +#define LOCAL_CX 0x04 /* OR'd value - require a context */ +#define LOCAL_CX_OPT 0x08 /* OR'd value - optional context */ + +struct server; +struct datalink; +struct bundle; +struct cmdargs; + +struct prompt { + struct descriptor desc; + int fd_in, fd_out; + struct datalink *TermMode; /* The modem we're talking directly to */ + FILE *Term; /* sits on top of fd_out */ + u_char auth; /* Local Authorized status */ + struct server *owner; /* who created me */ + struct bundle *bundle; /* who I'm controlling */ + unsigned nonewline : 1; /* need a newline before our prompt ? */ + unsigned needprompt : 1; /* Show a prompt at the next UpdateSet() */ + unsigned active : 1; /* Is the prompt active (^Z) */ + unsigned readtilde : 1; /* We've read a ``~'' from fd_in */ + + struct { + const char *type; /* Type of connection */ + char from[40]; /* Source of connection */ + } src; + + struct prompt *next; /* Maintained in log.c */ + u_long logmask; /* Maintained in log.c */ + + struct termios oldtio; /* Original tty mode */ + struct termios comtio; /* Command level tty mode */ +}; + +#define descriptor2prompt(d) \ + ((d)->type == PROMPT_DESCRIPTOR ? (struct prompt *)(d) : NULL) + +#define PROMPT_STD (-1) +extern struct prompt *prompt_Create(struct server *, struct bundle *, int); +extern void prompt_Destroy(struct prompt *, int); +extern void prompt_Required(struct prompt *); +#ifdef __GNUC__ +extern void prompt_Printf(struct prompt *, const char *, ...) + __attribute__ ((format (printf, 2, 3))); +#else +extern void prompt_Printf(struct prompt *, const char *, ...); +#endif +extern void prompt_vPrintf(struct prompt *, const char *, _BSD_VA_LIST_); +#define PROMPT_DONT_WANT_INT 1 +#define PROMPT_WANT_INT 0 +extern void prompt_TtyInit(struct prompt *); +extern void prompt_TtyCommandMode(struct prompt *); +extern void prompt_TtyTermMode(struct prompt *, struct datalink *); +extern void prompt_TtyOldMode(struct prompt *); +extern pid_t prompt_pgrp(struct prompt *); +extern int PasswdCommand(struct cmdargs const *); +extern void prompt_Suspend(struct prompt *); +extern void prompt_Continue(struct prompt *); +#define prompt_IsTermMode(p, dl) ((p)->TermMode == (dl) ? 1 : 0) +#define prompt_IsController(p) (!(p) || (p)->owner ? 0 : 1) +#define prompt_Required(p) ((p)->needprompt = 1) diff --git a/usr.sbin/ppp/route.c b/usr.sbin/ppp/ppp/route.c index e7e16487307..5328f3a4ab8 100644 --- a/usr.sbin/ppp/route.c +++ b/usr.sbin/ppp/ppp/route.c @@ -17,12 +17,11 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: route.c,v 1.19 1998/08/17 06:45:38 brian Exp $ + * $Id: route.c,v 1.1 1998/08/31 00:22:27 brian Exp $ * */ -#include <sys/param.h> -#include <sys/time.h> +#include <sys/types.h> #include <sys/socket.h> #include <net/if_types.h> #include <net/route.h> @@ -30,155 +29,42 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <net/if_dl.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> #include <errno.h> -#include <machine/endian.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/ioctl.h> #include <sys/sysctl.h> -#include <unistd.h> +#include <termios.h> +#include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" -#include "loadalias.h" -#include "defs.h" -#include "vars.h" -#include "id.h" -#include "os.h" -#include "ipcp.h" #include "iplist.h" +#include "timer.h" +#include "throughput.h" +#include "lqr.h" +#include "hdlc.h" +#include "fsm.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "mp.h" +#include "bundle.h" #include "route.h" - -static int IfIndex; - -struct rtmsg { - struct rt_msghdr m_rtm; - char m_space[64]; -}; - -static int seqno; - -void -OsSetRoute(int cmd, - struct in_addr dst, - struct in_addr gateway, - struct in_addr mask, - int bang) -{ - struct rtmsg rtmes; - int s, nb, wb; - char *cp; - const char *cmdstr; - struct sockaddr_in rtdata; - - if (bang) - cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); - else - cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); - s = ID0socket(PF_ROUTE, SOCK_RAW, 0); - if (s < 0) { - LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); - return; - } - memset(&rtmes, '\0', sizeof rtmes); - rtmes.m_rtm.rtm_version = RTM_VERSION; - rtmes.m_rtm.rtm_type = cmd; - rtmes.m_rtm.rtm_addrs = RTA_DST; - rtmes.m_rtm.rtm_seq = ++seqno; - rtmes.m_rtm.rtm_pid = getpid(); - rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; - - memset(&rtdata, '\0', sizeof rtdata); - rtdata.sin_len = 16; - rtdata.sin_family = AF_INET; - rtdata.sin_port = 0; - rtdata.sin_addr = dst; - - cp = rtmes.m_space; - memcpy(cp, &rtdata, 16); - cp += 16; - if (cmd == RTM_ADD) { - if (gateway.s_addr == INADDR_ANY) { - /* Add a route through the interface */ - struct sockaddr_dl dl; - const char *iname; - int ilen; - - iname = Index2Nam(IfIndex); - ilen = strlen(iname); - dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; - dl.sdl_family = AF_LINK; - dl.sdl_index = IfIndex; - dl.sdl_type = 0; - dl.sdl_nlen = ilen; - dl.sdl_alen = 0; - dl.sdl_slen = 0; - strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); - - memcpy(cp, &dl, dl.sdl_len); - cp += dl.sdl_len; - rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; - } else { - rtdata.sin_addr = gateway; - memcpy(cp, &rtdata, 16); - cp += 16; - rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; - } - } - - if (dst.s_addr == INADDR_ANY) - mask.s_addr = INADDR_ANY; - - if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { - rtdata.sin_addr = mask; - memcpy(cp, &rtdata, 16); - cp += 16; - rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; - } - - nb = cp - (char *) &rtmes; - rtmes.m_rtm.rtm_msglen = nb; - wb = ID0write(s, &rtmes, nb); - if (wb < 0) { - LogPrintf(LogTCPIP, "OsSetRoute failure:\n"); - LogPrintf(LogTCPIP, "OsSetRoute: Cmd = %s\n", cmdstr); - LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); - LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); - LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); -failed: - if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || - (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { - if (!bang) - LogPrintf(LogWARN, "Add route failed: %s already exists\n", - inet_ntoa(dst)); - else { - rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; - if ((wb = ID0write(s, &rtmes, nb)) < 0) - goto failed; - } - } else if (cmd == RTM_DELETE && - (rtmes.m_rtm.rtm_errno == ESRCH || - (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { - if (!bang) - LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", - inet_ntoa(dst)); - } else if (rtmes.m_rtm.rtm_errno == 0) - LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, - inet_ntoa(dst), strerror(errno)); - else - LogPrintf(LogWARN, "%s route failed: %s: %s\n", - cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); - } - LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", - wb, cmdstr, dst.s_addr, gateway.s_addr); - close(s); -} +#include "prompt.h" static void -p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) +p_sockaddr(struct prompt *prompt, struct sockaddr *phost, + struct sockaddr *pmask, int width) { char buf[29]; struct sockaddr_in *ihost = (struct sockaddr_in *)phost; @@ -194,8 +80,8 @@ p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) else if (!mask) strcpy(buf, inet_ntoa(ihost->sin_addr)); else { - u_int msk = ntohl(mask->sin_addr.s_addr); - u_int tst; + u_int32_t msk = ntohl(mask->sin_addr.s_addr); + u_int32_t tst; int bits; int len; struct sockaddr_in net; @@ -204,20 +90,20 @@ p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) if (msk & tst) break; - for (tst <<=1; tst; tst <<= 1) + for (tst <<= 1; tst; tst <<= 1) if (!(msk & tst)) break; net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; strcpy(buf, inet_ntoa(net.sin_addr)); - for (len = strlen(buf); len > 3; buf[len-=2] = '\0') - if (strcmp(buf+len-2, ".0")) + for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') + if (strcmp(buf + len - 2, ".0")) break; if (tst) /* non-contiguous :-( */ - sprintf(buf+strlen(buf),"&0x%08x", msk); + sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); else - sprintf(buf+strlen(buf), "/%d", bits); + sprintf(buf + strlen(buf), "/%d", bits); } break; @@ -238,7 +124,7 @@ p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) strcpy(buf, "??:??:??:??:??:??"); } else sprintf(buf, "<IFT type %d>", dl->sdl_type); - } else if (dl->sdl_slen) + } else if (dl->sdl_slen) sprintf(buf, "<slen %d?>", dl->sdl_slen); else sprintf(buf, "link#%d", dl->sdl_index); @@ -249,7 +135,7 @@ p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) break; } - fprintf(VarTerm, "%-*s ", width-1, buf); + prompt_Printf(prompt, "%-*s ", width-1, buf); } static struct bits { @@ -290,28 +176,32 @@ static struct bits { #endif static void -p_flags(u_int32_t f, int max) +p_flags(struct prompt *prompt, u_int32_t f, int max) { - if (VarTerm) { - char name[33], *flags; - register struct bits *p = bits; - - if (max > sizeof name - 1) - max = sizeof name - 1; - - for (flags = name; p->b_mask && flags - name < max; p++) - if (p->b_mask & f) - *flags++ = p->b_val; - *flags = '\0'; - fprintf(VarTerm, "%-*.*s", max, max, name); - } + char name[33], *flags; + register struct bits *p = bits; + + if (max > sizeof name - 1) + max = sizeof name - 1; + + for (flags = name; p->b_mask && flags - name < max; p++) + if (p->b_mask & f) + *flags++ = p->b_val; + *flags = '\0'; + prompt_Printf(prompt, "%-*.*s", max, max, name); } const char * Index2Nam(int idx) { - static char **ifs; - static int nifs, debug_done; + /* + * XXX: Maybe we should select() on the routing socket so that we can + * notice interfaces that come & go (PCCARD support). + * Or we could even support a signal that resets these so that + * the PCCARD insert/remove events can signal ppp. + */ + static char **ifs; /* Figure these out once */ + static int nifs, debug_done; /* Figure out how many once, and debug once */ if (!nifs) { int mib[6], have, had; @@ -328,7 +218,8 @@ Index2Nam(int idx) mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); + log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", + strerror(errno)); return "???"; } if ((buf = malloc(needed)) == NULL) @@ -354,7 +245,7 @@ Index2Nam(int idx) else newifs = (char **)malloc(sizeof(char *) * have); if (!newifs) { - LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); + log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); nifs = 0; if (ifs) free(ifs); @@ -370,20 +261,20 @@ Index2Nam(int idx) if (nifs < ifm->ifm_index) nifs = ifm->ifm_index; } - } else if (LogIsKept(LogDEBUG)) - LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n", + } else if (log_IsKept(LogDEBUG)) + log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", ifm->ifm_index); } free(buf); } - if (LogIsKept(LogDEBUG) && !debug_done) { + if (log_IsKept(LogDEBUG) && !debug_done) { int f; - LogPrintf(LogDEBUG, "Found the following interfaces:\n"); + log_Printf(LogDEBUG, "Found the following interfaces:\n"); for (f = 0; f < nifs; f++) if (ifs[f] != NULL) - LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); + log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); debug_done = 1; } @@ -394,7 +285,7 @@ Index2Nam(int idx) } int -ShowRoute(struct cmdargs const *arg) +route_Show(struct cmdargs const *arg) { struct rt_msghdr *rtm; struct sockaddr *sa_dst, *sa_gw, *sa_mask; @@ -402,9 +293,6 @@ ShowRoute(struct cmdargs const *arg) size_t needed; int mib[6]; - if (!VarTerm) - return 1; - mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; @@ -412,22 +300,21 @@ ShowRoute(struct cmdargs const *arg) mib[4] = NET_RT_DUMP; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); + log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); return (1); } - if (needed < 0) - return (1); sp = malloc(needed); if (sp == NULL) return (1); if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); + log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); free(sp); return (1); } ep = sp + needed; - fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); + prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", + "Destination", "Gateway"); for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { rtm = (struct rt_msghdr *) cp; wp = (char *)(rtm+1); @@ -450,11 +337,11 @@ ShowRoute(struct cmdargs const *arg) } else sa_mask = NULL; - p_sockaddr(sa_dst, sa_mask, 20); - p_sockaddr(sa_gw, NULL, 20); + p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); + p_sockaddr(arg->prompt, sa_gw, NULL, 20); - p_flags(rtm->rtm_flags, 6); - fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index)); + p_flags(arg->prompt, rtm->rtm_flags, 6); + prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); } free(sp); return 0; @@ -464,7 +351,7 @@ ShowRoute(struct cmdargs const *arg) * Delete routes associated with our interface */ void -DeleteIfRoutes(int all) +route_IfDelete(struct bundle *bundle, int all) { struct rt_msghdr *rtm; struct sockaddr *sa; @@ -474,7 +361,7 @@ DeleteIfRoutes(int all) char *sp, *cp, *ep; int mib[6]; - LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); + log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->ifp.Index); sa_none.s_addr = INADDR_ANY; mib[0] = CTL_NET; @@ -484,19 +371,17 @@ DeleteIfRoutes(int all) mib[4] = NET_RT_DUMP; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", + log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", strerror(errno)); return; } - if (needed < 0) - return; sp = malloc(needed); if (sp == NULL) return; if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { - LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", + log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", strerror(errno)); free(sp); return; @@ -508,7 +393,8 @@ DeleteIfRoutes(int all) * We do 2 passes. The first deletes all cloned routes. The second * deletes all non-cloned routes. This is necessary to avoid * potential errors from trying to delete route X after route Y where - * route X was cloned from route Y (which is no longer there). + * route X was cloned from route Y (and is no longer there 'cos it + * may have gone with route Y). */ if (RTF_WASCLONED == 0 && pass == 0) /* So we can't tell ! */ @@ -516,25 +402,25 @@ DeleteIfRoutes(int all) for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { rtm = (struct rt_msghdr *) cp; sa = (struct sockaddr *) (rtm + 1); - LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s)," + log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, Index2Nam(rtm->rtm_index), rtm->rtm_flags, inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && - rtm->rtm_index == IfIndex && + rtm->rtm_index == bundle->ifp.Index && (all || (rtm->rtm_flags & RTF_GATEWAY))) { sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; sa = (struct sockaddr *)((char *)sa + sa->sa_len); if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { - LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass); - OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0); + log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); + bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0, 0); } else - LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass); + log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); } else - LogPrintf(LogDEBUG, - "DeleteIfRoutes: Can't remove routes of %d family !\n", + log_Printf(LogDEBUG, + "route_IfDelete: Can't remove routes of %d family !\n", sa->sa_family); } } @@ -551,33 +437,133 @@ GetIfIndex(char *name) idx = 1; while (strcmp(got = Index2Nam(idx), "???")) if (!strcmp(got, name)) - return IfIndex = idx; + return idx; else idx++; return -1; } -struct in_addr -ChooseHisAddr(const struct in_addr gw) +void +route_Change(struct bundle *bundle, struct sticky_route *r, + struct in_addr me, struct in_addr peer) +{ + struct in_addr none, del; + + none.s_addr = INADDR_ANY; + for (; r; r = r->next) { + if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { + del.s_addr = r->dst.s_addr & r->mask.s_addr; + bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); + r->dst = me; + if (r->type & ROUTE_GWHISADDR) + r->gw = peer; + } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { + del.s_addr = r->dst.s_addr & r->mask.s_addr; + bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); + r->dst = peer; + if (r->type & ROUTE_GWHISADDR) + r->gw = peer; + } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) + r->gw = peer; + bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); + } +} + +void +route_Clean(struct bundle *bundle, struct sticky_route *r) +{ + struct in_addr none, del; + + none.s_addr = INADDR_ANY; + for (; r; r = r->next) { + del.s_addr = r->dst.s_addr & r->mask.s_addr; + bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); + } +} + +void +route_Add(struct sticky_route **rp, int type, struct in_addr dst, + struct in_addr mask, struct in_addr gw) +{ + if (type != ROUTE_STATIC) { + struct sticky_route *r; + int dsttype = type & ROUTE_DSTANY; + + r = NULL; + while (*rp) { + if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || + (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { + r = *rp; + *rp = r->next; + } else + rp = &(*rp)->next; + } + + if (!r) + r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); + r->type = type; + r->next = NULL; + r->dst = dst; + r->mask = mask; + r->gw = gw; + *rp = r; + } +} + +void +route_Delete(struct sticky_route **rp, int type, struct in_addr dst) { - struct in_addr try; - int f; - - for (f = 0; f < DefHisChoice.nItems; f++) { - try = iplist_next(&DefHisChoice); - LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", - f, inet_ntoa(try)); - if (OsTrySetIpaddress(gw, try) == 0) { - LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n", - inet_ntoa(try)); + struct sticky_route *r; + int dsttype = type & ROUTE_DSTANY; + + for (; *rp; rp = &(*rp)->next) { + if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || + (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { + r = *rp; + *rp = r->next; + free(r); break; } } +} + +void +route_DeleteAll(struct sticky_route **rp) +{ + struct sticky_route *r, *rn; - if (f == DefHisChoice.nItems) { - LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); - try.s_addr = INADDR_ANY; + for (r = *rp; r; r = rn) { + rn = r->next; + free(r); } + *rp = NULL; +} - return try; +void +route_ShowSticky(struct prompt *p, struct sticky_route *r) +{ + int def; + + prompt_Printf(p, "Sticky routes:\n"); + for (; r; r = r->next) { + def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; + + prompt_Printf(p, " add "); + if (r->type & ROUTE_DSTMYADDR) + prompt_Printf(p, "MYADDR"); + else if (r->type & ROUTE_DSTHISADDR) + prompt_Printf(p, "HISADDR"); + else if (!def) + prompt_Printf(p, "%s", inet_ntoa(r->dst)); + + if (def) + prompt_Printf(p, "default "); + else + prompt_Printf(p, " %s ", inet_ntoa(r->mask)); + + if (r->type & ROUTE_GWHISADDR) + prompt_Printf(p, "HISADDR\n"); + else + prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); + } } diff --git a/usr.sbin/ppp/ppp/route.h b/usr.sbin/ppp/ppp/route.h new file mode 100644 index 00000000000..7b230b6e106 --- /dev/null +++ b/usr.sbin/ppp/ppp/route.h @@ -0,0 +1,53 @@ +/* + * User Process PPP + * + * Written by Toshiharu OHNO (tony-o@iij.ad.jp) + * + * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Internet Initiative Japan, Inc. The name of the + * IIJ may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: route.h,v 1.1 1998/08/31 00:22:27 brian Exp $ + * + */ + +struct bundle; +struct cmdargs; + +#define ROUTE_STATIC 0 +#define ROUTE_DSTMYADDR 1 +#define ROUTE_DSTHISADDR 2 +#define ROUTE_DSTANY 3 +#define ROUTE_GWHISADDR 4 /* May be ORd with DST_MYADDR */ + +struct sticky_route { + int type; /* ROUTE_* value (not _STATIC) */ + struct sticky_route *next; /* next in list */ + + struct in_addr dst; + struct in_addr mask; + struct in_addr gw; +}; + +extern int GetIfIndex(char *); +extern int route_Show(struct cmdargs const *); +extern void route_IfDelete(struct bundle *, int); +extern const char *Index2Nam(int); +extern void route_Change(struct bundle *, struct sticky_route *, + struct in_addr, struct in_addr); +extern void route_Add(struct sticky_route **, int, struct in_addr, + struct in_addr, struct in_addr); +extern void route_Delete(struct sticky_route **, int, struct in_addr); +extern void route_DeleteAll(struct sticky_route **); +extern void route_Clean(struct bundle *, struct sticky_route *); +extern void route_ShowSticky(struct prompt *, struct sticky_route *); diff --git a/usr.sbin/ppp/ppp/server.c b/usr.sbin/ppp/ppp/server.c new file mode 100644 index 00000000000..317d858f0d7 --- /dev/null +++ b/usr.sbin/ppp/ppp/server.c @@ -0,0 +1,285 @@ +/*- + * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: server.c,v 1.1 1998/08/31 00:22:27 brian Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/un.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <termios.h> +#include <unistd.h> + +#include "log.h" +#include "descriptor.h" +#include "server.h" +#include "id.h" +#include "prompt.h" + +static int +server_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + struct server *s = descriptor2server(d); + struct prompt *p; + int sets; + + sets = 0; + if (r && s->fd >= 0) { + if (*n < s->fd + 1) + *n = s->fd + 1; + FD_SET(s->fd, r); + log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd); + sets++; + } + + for (p = log_PromptList(); p; p = p->next) + sets += descriptor_UpdateSet(&p->desc, r, w, e, n); + + return sets; +} + +static int +server_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct server *s = descriptor2server(d); + struct prompt *p; + + if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) + return 1; + + for (p = log_PromptList(); p; p = p->next) + if (descriptor_IsSet(&p->desc, fdset)) + return 1; + + return 0; +} + +#define IN_SIZE sizeof(struct sockaddr_in) +#define UN_SIZE sizeof(struct sockaddr_in) +#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE) + +static void +server_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + struct server *s = descriptor2server(d); + char hisaddr[ADDRSZ]; + struct sockaddr *sa = (struct sockaddr *)hisaddr; + struct sockaddr_in *in = (struct sockaddr_in *)hisaddr; + int ssize = ADDRSZ, wfd; + struct prompt *p; + + if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) { + wfd = accept(s->fd, sa, &ssize); + if (wfd < 0) + log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno)); + } else + wfd = -1; + + if (wfd >= 0) + switch (sa->sa_family) { + case AF_LOCAL: + log_Printf(LogPHASE, "Connected to local client.\n"); + break; + + case AF_INET: + if (ntohs(in->sin_port) < 1024) { + log_Printf(LogALERT, "Rejected client connection from %s:%u" + "(invalid port number) !\n", + inet_ntoa(in->sin_addr), ntohs(in->sin_port)); + close(wfd); + wfd = -1; + break; + } + log_Printf(LogPHASE, "Connected to client from %s:%u\n", + inet_ntoa(in->sin_addr), in->sin_port); + break; + + default: + write(wfd, "Unrecognised access !\n", 22); + close(wfd); + wfd = -1; + break; + } + + if (wfd >= 0) { + if ((p = prompt_Create(s, bundle, wfd)) == NULL) { + write(wfd, "Connection refused.\n", 20); + close(wfd); + } else { + switch (sa->sa_family) { + case AF_LOCAL: + p->src.type = "local"; + strncpy(p->src.from, s->rm, sizeof p->src.from - 1); + p->src.from[sizeof p->src.from - 1] = '\0'; + break; + case AF_INET: + p->src.type = "tcp"; + snprintf(p->src.from, sizeof p->src.from, "%s:%u", + inet_ntoa(in->sin_addr), in->sin_port); + break; + } + prompt_TtyCommandMode(p); + prompt_Required(p); + } + } + + log_PromptListChanged = 0; + for (p = log_PromptList(); p; p = p->next) + if (descriptor_IsSet(&p->desc, fdset)) { + descriptor_Read(&p->desc, bundle, fdset); + if (log_PromptListChanged) + break; + } +} + +static int +server_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + /* We never want to write here ! */ + log_Printf(LogALERT, "server_Write: Internal error: Bad call !\n"); + return 0; +} + +struct server server = { + { + SERVER_DESCRIPTOR, + server_UpdateSet, + server_IsSet, + server_Read, + server_Write + }, + -1 +}; + +int +server_LocalOpen(struct bundle *bundle, const char *name, mode_t mask) +{ + int s; + + if (server.rm && !strcmp(server.rm, name)) { + if (chmod(server.rm, mask)) + log_Printf(LogERROR, "Local: chmod: %s\n", strerror(errno)); + return 0; + } + + memset(&server.ifsun, '\0', sizeof server.ifsun); + server.ifsun.sun_len = strlen(name); + if (server.ifsun.sun_len > sizeof server.ifsun.sun_path - 1) { + log_Printf(LogERROR, "Local: %s: Path too long\n", name); + return 2; + } + server.ifsun.sun_family = AF_LOCAL; + strcpy(server.ifsun.sun_path, name); + + s = ID0socket(PF_LOCAL, SOCK_STREAM, 0); + if (s < 0) { + log_Printf(LogERROR, "Local: socket: %s\n", strerror(errno)); + return 3; + } + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); + if (mask != (mode_t)-1) + mask = umask(mask); + if (bind(s, (struct sockaddr *)&server.ifsun, sizeof server.ifsun) < 0) { + if (mask != (mode_t)-1) + umask(mask); + log_Printf(LogWARN, "Local: bind: %s\n", strerror(errno)); + close(s); + return 4; + } + if (mask != (mode_t)-1) + umask(mask); + if (listen(s, 5) != 0) { + log_Printf(LogERROR, "Local: Unable to listen to socket - BUNDLE overload?\n"); + close(s); + ID0unlink(name); + return 5; + } + server_Close(bundle); + server.fd = s; + server.rm = server.ifsun.sun_path; + log_Printf(LogPHASE, "Listening at local socket %s.\n", name); + return 0; +} + +int +server_TcpOpen(struct bundle *bundle, int port) +{ + struct sockaddr_in ifsin; + int s; + + if (server.port == port) + return 0; + + s = ID0socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) { + log_Printf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); + return 7; + } + memset(&ifsin, '\0', sizeof ifsin); + ifsin.sin_family = AF_INET; + ifsin.sin_addr.s_addr = INADDR_ANY; + ifsin.sin_port = htons(port); + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); + if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) { + log_Printf(LogWARN, "Tcp: bind: %s\n", strerror(errno)); + close(s); + return 8; + } + if (listen(s, 5) != 0) { + log_Printf(LogERROR, "Tcp: Unable to listen to socket - BUNDLE overload?\n"); + close(s); + return 9; + } + server_Close(bundle); + server.fd = s; + server.port = port; + log_Printf(LogPHASE, "Listening at port %d.\n", port); + return 0; +} + +int +server_Close(struct bundle *bundle) +{ + if (server.fd >= 0) { + close(server.fd); + if (server.rm) { + ID0unlink(server.rm); + server.rm = NULL; + } + server.fd = -1; + server.port = 0; + /* Drop associated prompts */ + log_DestroyPrompts(&server); + return 1; + } + return 0; +} diff --git a/usr.sbin/ppp/ppp/server.h b/usr.sbin/ppp/ppp/server.h new file mode 100644 index 00000000000..a1a8eb15c91 --- /dev/null +++ b/usr.sbin/ppp/ppp/server.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: server.h,v 1.1 1998/08/31 00:22:28 brian Exp $ + */ + +struct bundle; + +struct server { + struct descriptor desc; + int fd; + char passwd[50]; + + struct sockaddr_un ifsun; /* local socket */ + char *rm; /* Points to local socket path */ + + u_short port; /* tcp socket */ +}; + +#define descriptor2server(d) \ + ((d)->type == SERVER_DESCRIPTOR ? (struct server *)(d) : NULL) + +extern struct server server; + +extern int server_LocalOpen(struct bundle *, const char *, mode_t); +extern int server_TcpOpen(struct bundle *, int); +extern int server_Close(struct bundle *); diff --git a/usr.sbin/ppp/sig.c b/usr.sbin/ppp/ppp/sig.c index 3061c39538a..40c4f8733b9 100644 --- a/usr.sbin/ppp/sig.c +++ b/usr.sbin/ppp/ppp/sig.c @@ -23,15 +23,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sig.c,v 1.3 1998/03/08 23:32:14 brian Exp $ + * $Id: sig.c,v 1.1 1998/08/31 00:22:28 brian Exp $ */ #include <sys/types.h> #include <signal.h> -#include "command.h" -#include "mbuf.h" #include "log.h" #include "sig.h" @@ -54,13 +52,13 @@ signal_recorder(int sig) */ sig_type -pending_signal(int sig, sig_type fn) +sig_signal(int sig, sig_type fn) { sig_type Result; if (sig <= 0 || sig > NSIG) { /* Oops - we must be a bit out of date (too many sigs ?) */ - LogPrintf(LogALERT, "Eeek! %s:%s: I must be out of date!\n", + log_Printf(LogALERT, "Eeek! %s:%d: I must be out of date!\n", __FILE__, __LINE__); return signal(sig, fn); } @@ -80,7 +78,7 @@ pending_signal(int sig, sig_type fn) /* Call the handlers for any pending signals */ void -handle_signals() +sig_Handle() { int sig; int got; diff --git a/usr.sbin/ppp/sig.h b/usr.sbin/ppp/ppp/sig.h index 2653627168c..6db3c6133b7 100644 --- a/usr.sbin/ppp/sig.h +++ b/usr.sbin/ppp/ppp/sig.h @@ -23,13 +23,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sig.h,v 1.2 1997/12/21 14:27:15 brian Exp $ + * $Id: sig.h,v 1.1 1998/08/31 00:22:28 brian Exp $ */ typedef void (*sig_type)(int); /* Call this instead of signal() */ -extern sig_type pending_signal(int, sig_type); +extern sig_type sig_signal(int, sig_type); /* Call this when you want things to *actually* happen */ -extern void handle_signals(void); +extern void sig_Handle(void); diff --git a/usr.sbin/ppp/slcompress.c b/usr.sbin/ppp/ppp/slcompress.c index 1715d8bde64..37b585f7590 100644 --- a/usr.sbin/ppp/slcompress.c +++ b/usr.sbin/ppp/ppp/slcompress.c @@ -17,41 +17,43 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: slcompress.c,v 1.3 1998/06/27 12:06:49 brian Exp $ + * $Id: slcompress.c,v 1.1 1998/08/31 00:22:28 brian Exp $ * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. */ -#include <sys/param.h> +#include <sys/types.h> #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netinet/ip.h> +#include <sys/un.h> #include <stdio.h> #include <string.h> +#include <termios.h> +#include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" -#include "defs.h" #include "slcompress.h" -#include "loadalias.h" -#include "vars.h" - -static struct slstat { - int sls_packets; /* outbound packets */ - int sls_compressed; /* outbound compressed packets */ - int sls_searches; /* searches for connection state */ - int sls_misses; /* times couldn't find conn. state */ - int sls_uncompressedin; /* inbound uncompressed packets */ - int sls_compressedin; /* inbound compressed packets */ - int sls_errorin; /* inbound unknown type packets */ - int sls_tossed; /* inbound packets tossed because of error */ -} slstat; - -#define INCR(counter) slstat.counter++; +#include "descriptor.h" +#include "prompt.h" +#include "timer.h" +#include "fsm.h" +#include "throughput.h" +#include "iplist.h" +#include "lqr.h" +#include "hdlc.h" +#include "ipcp.h" +#include "filter.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" void sl_compress_init(struct slcompress * comp, int max_state) @@ -129,7 +131,8 @@ sl_compress_init(struct slcompress * comp, int max_state) u_char sl_compress_tcp(struct mbuf * m, struct ip * ip, - struct slcompress * comp, + struct slcompress *comp, + struct slstat *slstat, int compress_cid) { register struct cstate *cs = comp->last_cs->cs_next; @@ -147,15 +150,15 @@ sl_compress_tcp(struct mbuf * m, * the caller has already made sure the packet is IP proto TCP). */ if ((ip->ip_off & htons(0x3fff)) || m->cnt < 40) { - LogPrintf(LogDEBUG, "??? 1 ip_off = %x, cnt = %d\n", + log_Printf(LogDEBUG, "??? 1 ip_off = %x, cnt = %d\n", ip->ip_off, m->cnt); - LogDumpBp(LogDEBUG, "", m); + log_DumpBp(LogDEBUG, "", m); return (TYPE_IP); } th = (struct tcphdr *) & ((int *) ip)[hlen]; if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) { - LogPrintf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags); - LogDumpBp(LogDEBUG, "", m); + log_Printf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags); + log_DumpBp(LogDEBUG, "", m); return (TYPE_IP); } @@ -166,10 +169,10 @@ sl_compress_tcp(struct mbuf * m, * it's most likely to be used again & we don't have to do any reordering * if it's used. */ - INCR(sls_packets) - if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || - ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || - *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) { + slstat->sls_packets++; + if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || + ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || + *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) { /* * Wasn't the first -- search for it. @@ -187,10 +190,10 @@ sl_compress_tcp(struct mbuf * m, do { lcs = cs; cs = cs->cs_next; - INCR(sls_searches) - if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr - && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr - && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) + slstat->sls_searches++; + if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr + && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr + && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) goto found; } while (cs != lastcs); @@ -201,7 +204,7 @@ sl_compress_tcp(struct mbuf * m, * state points to the newest and we only need to set last_cs to update * the lru linkage. */ - INCR(sls_misses) + slstat->sls_misses++; comp->last_cs = lcs; #define THOFFSET(th) (th->th_off) hlen += th->th_off; @@ -382,8 +385,8 @@ found: *cp++ = deltaA >> 8; *cp++ = deltaA; memcpy(cp, new_seq, deltaS); - INCR(sls_compressed) - return (TYPE_COMPRESSED_TCP); + slstat->sls_compressed++; + return (TYPE_COMPRESSED_TCP); /* * Update connection state cs & send uncompressed packet ('uncompressed' @@ -399,10 +402,8 @@ uncompressed: int -sl_uncompress_tcp(u_char ** bufp, - int len, - u_int type, - struct slcompress * comp) +sl_uncompress_tcp(u_char ** bufp, int len, u_int type, struct slcompress *comp, + struct slstat *slstat, int max_state) { register u_char *cp; register u_int hlen, changes; @@ -414,7 +415,7 @@ sl_uncompress_tcp(u_char ** bufp, case TYPE_UNCOMPRESSED_TCP: ip = (struct ip *) * bufp; - if (ip->ip_p >= MAX_STATES) + if (ip->ip_p > max_state) goto bad; cs = &comp->rstate[comp->last_recv = ip->ip_p]; comp->flags &= ~SLF_TOSS; @@ -434,8 +435,8 @@ sl_uncompress_tcp(u_char ** bufp, memcpy(&cs->cs_ip, ip, hlen); cs->cs_ip.ip_sum = 0; cs->cs_hlen = hlen; - INCR(sls_uncompressedin) - return (len); + slstat->sls_uncompressedin++; + return (len); default: goto bad; @@ -444,18 +445,19 @@ sl_uncompress_tcp(u_char ** bufp, break; } /* We've got a compressed packet. */ - INCR(sls_compressedin) - cp = *bufp; + slstat->sls_compressedin++; + cp = *bufp; changes = *cp++; - LogPrintf(LogDEBUG, "compressed: changes = %02x\n", changes); + log_Printf(LogDEBUG, "compressed: changes = %02x\n", changes); if (changes & NEW_C) { /* * Make sure the state index is in range, then grab the state. If we have * a good state index, clear the 'discard' flag. */ - if (*cp >= MAX_STATES || comp->last_recv == 255) + if (*cp > max_state || comp->last_recv == 255) { goto bad; + } comp->flags &= ~SLF_TOSS; comp->last_recv = *cp++; @@ -467,12 +469,14 @@ sl_uncompress_tcp(u_char ** bufp, * the packet. */ if (comp->flags & SLF_TOSS) { - INCR(sls_tossed) - return (0); + slstat->sls_tossed++; + return (0); } } cs = &comp->rstate[comp->last_recv]; hlen = cs->cs_ip.ip_hl << 2; + if (hlen == 0) + goto bad; /* We've been pointed at a not-yet-used slot ! */ th = (struct tcphdr *) & ((u_char *) & cs->cs_ip)[hlen]; th->th_sum = htons((*cp << 8) | cp[1]); cp += 2; @@ -507,7 +511,7 @@ sl_uncompress_tcp(u_char ** bufp, if (changes & NEW_A) DECODEL(th->th_ack) if (changes & NEW_S) { - LogPrintf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n", + log_Printf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n", *cp, cp[1], cp[2]); DECODEL(th->th_seq) } @@ -518,8 +522,8 @@ sl_uncompress_tcp(u_char ** bufp, } else cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); - LogPrintf(LogDEBUG, "Uncompress: id = %04x, seq = %08x\n", - cs->cs_ip.ip_id, ntohl(th->th_seq)); + log_Printf(LogDEBUG, "Uncompress: id = %04x, seq = %08lx\n", + cs->cs_ip.ip_id, (u_long)ntohl(th->th_seq)); /* * At this point, cp points to the first byte of data in the packet. If @@ -565,23 +569,25 @@ sl_uncompress_tcp(u_char ** bufp, return (len); bad: comp->flags |= SLF_TOSS; - INCR(sls_errorin) - return (0); + slstat->sls_errorin++; + return (0); } int -ReportCompress(struct cmdargs const *arg) +sl_Show(struct cmdargs const *arg) { - if (!VarTerm) - return 1; - - fprintf(VarTerm, "Out: %d (compress) / %d (total)", - slstat.sls_compressed, slstat.sls_packets); - fprintf(VarTerm, " %d (miss) / %d (search)\n", - slstat.sls_misses, slstat.sls_searches); - fprintf(VarTerm, "In: %d (compress), %d (uncompress)", - slstat.sls_compressedin, slstat.sls_uncompressedin); - fprintf(VarTerm, " %d (error), %d (tossed)\n", - slstat.sls_errorin, slstat.sls_tossed); + prompt_Printf(arg->prompt, "VJ compression statistics:\n"); + prompt_Printf(arg->prompt, " Out: %d (compress) / %d (total)", + arg->bundle->ncp.ipcp.vj.slstat.sls_compressed, + arg->bundle->ncp.ipcp.vj.slstat.sls_packets); + prompt_Printf(arg->prompt, " %d (miss) / %d (search)\n", + arg->bundle->ncp.ipcp.vj.slstat.sls_misses, + arg->bundle->ncp.ipcp.vj.slstat.sls_searches); + prompt_Printf(arg->prompt, " In: %d (compress), %d (uncompress)", + arg->bundle->ncp.ipcp.vj.slstat.sls_compressedin, + arg->bundle->ncp.ipcp.vj.slstat.sls_uncompressedin); + prompt_Printf(arg->prompt, " %d (error), %d (tossed)\n", + arg->bundle->ncp.ipcp.vj.slstat.sls_errorin, + arg->bundle->ncp.ipcp.vj.slstat.sls_tossed); return 0; } diff --git a/usr.sbin/ppp/slcompress.h b/usr.sbin/ppp/ppp/slcompress.h index 17658efca26..06479d90563 100644 --- a/usr.sbin/ppp/slcompress.h +++ b/usr.sbin/ppp/ppp/slcompress.h @@ -1,8 +1,6 @@ /* * Definitions for tcp compression routines. * - * $Header: /cvs/OpenBSD/src/usr.sbin/ppp/Attic/slcompress.h,v 1.1 1997/11/23 20:27:36 brian Exp $ - * * Copyright (c) 1989 Regents of the University of California. * All rights reserved. * @@ -18,14 +16,16 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: slcompress.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + * $Id: slcompress.h,v 1.1 1998/08/31 00:22:28 brian Exp $ * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. */ -#define MAX_STATES 16 /* must be > 2 and < 256 */ -#define MAX_HDR 128 /* XXX 4bsd-ism: should really be 128 */ +#define MIN_VJ_STATES 3 +#define MAX_VJ_STATES 255 +#define DEF_VJ_STATES 16 /* must be > 2 and < 256 */ +#define MAX_HDR 128 /* * Compressed packet format: @@ -120,15 +120,30 @@ struct slcompress { u_char last_recv; /* last rcvd conn. id */ u_char last_xmit; /* last sent conn. id */ u_short flags; - struct cstate tstate[MAX_STATES]; /* xmit connection states */ - struct cstate rstate[MAX_STATES]; /* receive connection states */ + struct cstate tstate[MAX_VJ_STATES]; /* xmit connection states */ + struct cstate rstate[MAX_VJ_STATES]; /* receive connection states */ +}; + +struct slstat { + int sls_packets; /* outbound packets */ + int sls_compressed; /* outbound compressed packets */ + int sls_searches; /* searches for connection state */ + int sls_misses; /* times couldn't find conn. state */ + int sls_uncompressedin; /* inbound uncompressed packets */ + int sls_compressedin; /* inbound compressed packets */ + int sls_errorin; /* inbound unknown type packets */ + int sls_tossed; /* inbound packets tossed because of error */ }; /* flag values */ #define SLF_TOSS 1 /* tossing rcvd frames because of input err */ +struct mbuf; +struct cmdargs; + extern void sl_compress_init(struct slcompress *, int); -extern u_char sl_compress_tcp - (struct mbuf *, struct ip *, struct slcompress *, int); -extern int sl_uncompress_tcp(u_char **, int, u_int, struct slcompress *); -extern int ReportCompress(struct cmdargs const *); +extern u_char sl_compress_tcp(struct mbuf *, struct ip *, struct slcompress *, + struct slstat *, int); +extern int sl_uncompress_tcp(u_char **, int, u_int, struct slcompress *, + struct slstat *, int); +extern int sl_Show(struct cmdargs const *); diff --git a/usr.sbin/ppp/systems.c b/usr.sbin/ppp/ppp/systems.c index 1d7c65ac3a4..22dd1546da7 100644 --- a/usr.sbin/ppp/systems.c +++ b/usr.sbin/ppp/ppp/systems.c @@ -17,12 +17,11 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: systems.c,v 1.8 1998/01/21 02:13:41 brian Exp $ + * $Id: systems.c,v 1.1 1998/08/31 00:22:28 brian Exp $ * * TODO: */ #include <sys/param.h> -#include <netinet/in.h> #include <ctype.h> #include <pwd.h> @@ -31,17 +30,10 @@ #include <string.h> #include <unistd.h> +#include "defs.h" #include "command.h" -#include "mbuf.h" #include "log.h" #include "id.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "loadalias.h" -#include "pathnames.h" -#include "vars.h" -#include "server.h" #include "systems.h" #define issep(ch) ((ch) == ' ' || (ch) == '\t') @@ -55,7 +47,7 @@ OpenSecret(const char *file) snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file); fp = ID0fopen(line, "r"); if (fp == NULL) - LogPrintf(LogWARN, "OpenSecret: Can't open %s.\n", line); + log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line); return (fp); } @@ -164,18 +156,22 @@ DecodeCtrlCommand(char *line, char *arg) return CTRL_UNKNOWN; } +/* Initialised in system_IsValid(), set in ReadSystem(), used by system_IsValid() */ +static int modeok; static int userok; +static int modereq; int AllowUsers(struct cmdargs const *arg) { + /* arg->bundle may be NULL (see system_IsValid()) ! */ int f; char *user; userok = 0; user = getlogin(); if (user && *user) - for (f = 0; f < arg->argc; f++) + for (f = arg->argn; f < arg->argc; f++) if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) { userok = 1; break; @@ -184,57 +180,82 @@ AllowUsers(struct cmdargs const *arg) return 0; } -static struct { - int mode; - const char *name; -} modes[] = { - { MODE_INTER, "interactive" }, - { MODE_AUTO, "auto" }, - { MODE_DIRECT, "direct" }, - { MODE_DEDICATED, "dedicated" }, - { MODE_DDIAL, "ddial" }, - { MODE_BACKGROUND, "background" }, - { ~0, "*" }, - { 0, 0 } -}; - -static int modeok; - int AllowModes(struct cmdargs const *arg) { - int f; - int m; - int allowed; + /* arg->bundle may be NULL (see system_IsValid()) ! */ + int f, mode, allowed; allowed = 0; - for (f = 0; f < arg->argc; f++) { - for (m = 0; modes[m].mode; m++) - if (!strcasecmp(modes[m].name, arg->argv[f])) { - allowed |= modes[m].mode; - break; - } - if (modes[m].mode == 0) - LogPrintf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); + for (f = arg->argn; f < arg->argc; f++) { + mode = Nam2mode(arg->argv[f]); + if (mode == PHYS_NONE || mode == PHYS_ALL) + log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); + else + allowed |= mode; } - modeok = (mode | allowed) == allowed ? 1 : 0; + modeok = modereq & allowed ? 1 : 0; return 0; } +static char * +strip(char *line) +{ + int len; + + len = strlen(line); + while (len && (line[len-1] == '\n' || line[len-1] == '\r' || + issep(line[len-1]))) + line[--len] = '\0'; + + while (issep(*line)) + line++; + + if (*line == '#') + *line = '\0'; + + return line; +} + +static int +xgets(char *buf, int buflen, FILE *fp) +{ + int len, n; + + n = 0; + while (fgets(buf, buflen-1, fp)) { + n++; + buf[buflen-1] = '\0'; + len = strlen(buf); + while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) + buf[--len] = '\0'; + if (len && buf[len-1] == '\\') { + buf += len - 1; + buflen -= len - 1; + if (!buflen) /* No buffer space */ + break; + } else + break; + } + return n; +} + static int -ReadSystem(const char *name, const char *file, int doexec) +ReadSystem(struct bundle *bundle, const char *name, const char *file, + int doexec, struct prompt *prompt, struct datalink *cx) { FILE *fp; char *cp, *wp; int n, len; - u_char olauth; char line[LINE_LEN]; char filename[MAXPATHLEN]; int linenum; int argc; - char **argv; + char *argv[MAXARGS]; int allowcmd; + int indent; + char arg[LINE_LEN]; if (*file == '/') snprintf(filename, sizeof filename, "%s", file); @@ -242,73 +263,71 @@ ReadSystem(const char *name, const char *file, int doexec) snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); fp = ID0fopen(filename, "r"); if (fp == NULL) { - LogPrintf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); + log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); return (-1); } - LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); + log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); linenum = 0; - while (fgets(line, sizeof line, fp)) { - linenum++; - cp = line; + while ((n = xgets(line, sizeof line, fp))) { + linenum += n; + if (issep(*line)) + continue; + + cp = strip(line); + switch (*cp) { - case '#': /* comment */ + case '\0': /* empty/comment */ break; - case ' ': - case '\t': + + case '!': + switch (DecodeCtrlCommand(cp+1, arg)) { + case CTRL_INCLUDE: + log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); + n = ReadSystem(bundle, name, arg, doexec, prompt, cx); + log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); + if (!n) + return 0; /* got it */ + break; + default: + log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); + break; + } break; + default: - wp = strpbrk(cp, ":\n"); - if (wp == NULL) { - LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", + wp = strchr(cp, ':'); + if (wp == NULL || wp[1] != '\0') { + log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", filename, linenum); - ServerClose(); - exit(1); + continue; } *wp = '\0'; - if (*cp == '!') { - char arg[LINE_LEN]; - switch (DecodeCtrlCommand(cp+1, arg)) { - case CTRL_INCLUDE: - LogPrintf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); - n = ReadSystem(name, arg, doexec); - LogPrintf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); - if (!n) - return 0; /* got it */ - break; - default: - LogPrintf(LogWARN, "%s: %s: Invalid command\n", filename, cp); - break; + cp = strip(cp); /* lose any spaces between the label and the ':' */ + + if (strcmp(cp, name) == 0) { + /* We're in business */ + while ((n = xgets(line, sizeof line, fp))) { + linenum += n; + indent = issep(*line); + cp = strip(line); + + if (*cp == '\0') /* empty / comment */ + continue; + + if (!indent) /* start of next section */ + break; + + len = strlen(cp); + argc = command_Interpret(cp, len, argv); + allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); + if ((!doexec && allowcmd) || (doexec && !allowcmd)) + command_Run(bundle, argc, (char const *const *)argv, prompt, + name, cx); } - } else if (strcmp(cp, name) == 0) { - while (fgets(line, sizeof line, fp)) { - cp = line; - if (issep(*cp)) { - n = strspn(cp, " \t"); - cp += n; - len = strlen(cp); - if (!len || *cp == '#') - continue; - if (cp[len-1] == '\n') - cp[--len] = '\0'; - if (!len) - continue; - InterpretCommand(cp, len, &argc, &argv); - allowcmd = argc > 0 && !strcasecmp(*argv, "allow"); - if ((!doexec && allowcmd) || (doexec && !allowcmd)) { - olauth = VarLocalAuth; - if (VarLocalAuth == LOCAL_NO_AUTH) - VarLocalAuth = LOCAL_AUTH; - RunCommand(argc, (char const *const *)argv, name); - VarLocalAuth = olauth; - } - } else if (*cp == '#' || *cp == '\n' || *cp == '\0') { - continue; - } else - break; - } - fclose(fp); - return (0); + + fclose(fp); /* everything read - get out */ + return 0; } break; } @@ -318,49 +337,28 @@ ReadSystem(const char *name, const char *file, int doexec) } int -ValidSystem(const char *name) +system_IsValid(const char *name, struct prompt *prompt, int mode) { + /* + * Note: The ReadSystem() calls only result in calls to the Allow* + * functions. arg->bundle will be set to NULL for these commands ! + */ if (ID0realuid() == 0) return userok = modeok = 1; userok = 0; modeok = 1; - ReadSystem("default", CONFFILE, 0); + modereq = mode; + ReadSystem(NULL, "default", CONFFILE, 0, prompt, NULL); if (name != NULL) - ReadSystem(name, CONFFILE, 0); + ReadSystem(NULL, name, CONFFILE, 0, prompt, NULL); return userok && modeok; } int -SelectSystem(const char *name, const char *file) +system_Select(struct bundle *bundle, const char *name, const char *file, + struct prompt *prompt, struct datalink *cx) { userok = modeok = 1; - return ReadSystem(name, file, 1); -} - -int -LoadCommand(struct cmdargs const *arg) -{ - const char *name; - - if (arg->argc > 0) - name = *arg->argv; - else - name = "default"; - - if (!ValidSystem(name)) { - LogPrintf(LogERROR, "%s: Label not allowed\n", name); - return 1; - } else if (SelectSystem(name, CONFFILE) < 0) { - LogPrintf(LogWARN, "%s: label not found.\n", name); - return -1; - } else - SetLabel(arg->argc ? name : NULL); - return 0; -} - -int -SaveCommand(struct cmdargs const *arg) -{ - LogPrintf(LogWARN, "save command is not implemented (yet).\n"); - return 1; + modereq = PHYS_ALL; + return ReadSystem(bundle, name, file, 1, prompt, cx); } diff --git a/usr.sbin/ppp/systems.h b/usr.sbin/ppp/ppp/systems.h index cf75015f987..59254a0afbf 100644 --- a/usr.sbin/ppp/systems.h +++ b/usr.sbin/ppp/ppp/systems.h @@ -17,12 +17,18 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: systems.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + * $Id: systems.h,v 1.1 1998/08/31 00:22:29 brian Exp $ * */ -extern int SelectSystem(const char *, const char *); -extern int ValidSystem(const char *); +struct prompt; +struct datalink; +struct bundle; +struct cmdargs; + +extern int system_Select(struct bundle *bundle, const char *, const char *, + struct prompt *, struct datalink *); +extern int system_IsValid(const char *, struct prompt *, int); extern FILE *OpenSecret(const char *); extern void CloseSecret(FILE *); extern int AllowUsers(struct cmdargs const *); diff --git a/usr.sbin/ppp/throughput.c b/usr.sbin/ppp/ppp/throughput.c index 49af5a42def..90d27eb34d0 100644 --- a/usr.sbin/ppp/throughput.c +++ b/usr.sbin/ppp/ppp/throughput.c @@ -23,23 +23,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: throughput.c,v 1.3 1997/12/21 14:27:16 brian Exp $ + * $Id: throughput.c,v 1.1 1998/08/31 00:22:29 brian Exp $ */ -#include <sys/param.h> +#include <sys/types.h> #include <stdio.h> +#include <string.h> +#include <termios.h> #include <time.h> -#include <netinet/in.h> -#include "command.h" -#include "mbuf.h" #include "log.h" #include "timer.h" #include "throughput.h" -#include "defs.h" -#include "loadalias.h" -#include "vars.h" +#include "descriptor.h" +#include "prompt.h" void throughput_init(struct pppThroughput *t) @@ -50,26 +48,34 @@ throughput_init(struct pppThroughput *t) for (f = 0; f < SAMPLE_PERIOD; f++) t->SampleOctets[f] = 0; t->OctetsPerSecond = t->BestOctetsPerSecond = t->nSample = 0; + t->BestOctetsPerSecondTime = time(NULL); + memset(&t->Timer, '\0', sizeof t->Timer); + t->Timer.name = "throughput"; + t->uptime = 0; + t->rolling = 0; throughput_stop(t); } void -throughput_disp(struct pppThroughput *t, FILE *f) +throughput_disp(struct pppThroughput *t, struct prompt *prompt) { int secs_up; secs_up = t->uptime ? time(NULL) - t->uptime : 0; - fprintf(f, "Connect time: %d secs\n", secs_up); + prompt_Printf(prompt, "Connect time: %d secs\n", secs_up); if (secs_up == 0) secs_up = 1; - fprintf(f, "%ld octets in, %ld octets out\n", t->OctetsIn, t->OctetsOut); - if (Enabled(ConfThroughput)) { - fprintf(f, " overall %5ld bytes/sec\n", - (t->OctetsIn+t->OctetsOut)/secs_up); - fprintf(f, " currently %5d bytes/sec\n", t->OctetsPerSecond); - fprintf(f, " peak %5d bytes/sec\n", t->BestOctetsPerSecond); + prompt_Printf(prompt, "%ld octets in, %ld octets out\n", + t->OctetsIn, t->OctetsOut); + if (t->rolling) { + prompt_Printf(prompt, " overall %5ld bytes/sec\n", + (t->OctetsIn+t->OctetsOut)/secs_up); + prompt_Printf(prompt, " currently %5d bytes/sec\n", t->OctetsPerSecond); + prompt_Printf(prompt, " peak %5d bytes/sec on %s", + t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); } else - fprintf(f, "Overall %ld bytes/sec\n", (t->OctetsIn+t->OctetsOut)/secs_up); + prompt_Printf(prompt, "Overall %ld bytes/sec\n", + (t->OctetsIn+t->OctetsOut)/secs_up); } @@ -81,18 +87,19 @@ throughput_log(struct pppThroughput *t, int level, const char *title) secs_up = t->uptime ? time(NULL) - t->uptime : 0; if (title) - LogPrintf(level, "%s: Connect time: %d secs: %ld octets in, %ld octets" + log_Printf(level, "%s: Connect time: %d secs: %ld octets in, %ld octets" " out\n", title, secs_up, t->OctetsIn, t->OctetsOut); else - LogPrintf(level, "Connect time: %d secs: %ld octets in, %ld octets out\n", + log_Printf(level, "Connect time: %d secs: %ld octets in, %ld octets out\n", secs_up, t->OctetsIn, t->OctetsOut); if (secs_up == 0) secs_up = 1; - if (Enabled(ConfThroughput)) - LogPrintf(level, " total %ld bytes/sec, peak %d bytes/sec\n", - (t->OctetsIn+t->OctetsOut)/secs_up, t->BestOctetsPerSecond); + if (t->rolling) + log_Printf(level, " total %ld bytes/sec, peak %d bytes/sec on %s", + (t->OctetsIn+t->OctetsOut)/secs_up, t->BestOctetsPerSecond, + ctime(&t->BestOctetsPerSecondTime)); else - LogPrintf(level, " total %ld bytes/sec\n", + log_Printf(level, " total %ld bytes/sec\n", (t->OctetsIn+t->OctetsOut)/secs_up); } } @@ -103,39 +110,41 @@ throughput_sampler(void *v) struct pppThroughput *t = (struct pppThroughput *)v; u_long old; - StopTimer(&t->Timer); - t->Timer.state = TIMER_STOPPED; + timer_Stop(&t->Timer); old = t->SampleOctets[t->nSample]; t->SampleOctets[t->nSample] = t->OctetsIn + t->OctetsOut; t->OctetsPerSecond = (t->SampleOctets[t->nSample] - old) / SAMPLE_PERIOD; - if (t->BestOctetsPerSecond < t->OctetsPerSecond) + if (t->BestOctetsPerSecond < t->OctetsPerSecond) { t->BestOctetsPerSecond = t->OctetsPerSecond; + t->BestOctetsPerSecondTime = time(NULL); + } if (++t->nSample == SAMPLE_PERIOD) t->nSample = 0; - StartTimer(&t->Timer); + timer_Start(&t->Timer); } void -throughput_start(struct pppThroughput *t) +throughput_start(struct pppThroughput *t, const char *name, int rolling) { + timer_Stop(&t->Timer); throughput_init(t); + t->rolling = rolling ? 1 : 0; time(&t->uptime); - if (Enabled(ConfThroughput)) { - t->Timer.state = TIMER_STOPPED; + if (t->rolling) { t->Timer.load = SECTICKS; t->Timer.func = throughput_sampler; + t->Timer.name = name; t->Timer.arg = t; - StartTimer(&t->Timer); + timer_Start(&t->Timer); } } void throughput_stop(struct pppThroughput *t) { - if (Enabled(ConfThroughput)) - StopTimer(&t->Timer); + timer_Stop(&t->Timer); } void @@ -149,3 +158,44 @@ throughput_addout(struct pppThroughput *t, int n) { t->OctetsOut += n; } + +void +throughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) +{ + if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { + int i; + + for (i = 0; i < SAMPLE_PERIOD; i++) + t->SampleOctets[i] = 0; + t->nSample = 0; + } + + if (clear_type & THROUGHPUT_OVERALL) { + int secs_up; + + secs_up = t->uptime ? time(NULL) - t->uptime : 1; + prompt_Printf(prompt, "overall cleared (was %5ld bytes/sec)\n", + (t->OctetsIn + t->OctetsOut)/secs_up); + t->OctetsIn = t->OctetsOut = 0; + t->uptime = time(NULL); + } + + if (clear_type & THROUGHPUT_CURRENT) { + prompt_Printf(prompt, "current cleared (was %5d bytes/sec)\n", + t->OctetsPerSecond); + t->OctetsPerSecond = 0; + } + + if (clear_type & THROUGHPUT_PEAK) { + char *time_buf, *last; + + time_buf = ctime(&t->BestOctetsPerSecondTime); + last = time_buf + strlen(time_buf); + if (last > time_buf && *--last == '\n') + *last = '\0'; + prompt_Printf(prompt, "peak cleared (was %5d bytes/sec on %s)\n", + t->BestOctetsPerSecond, time_buf); + t->BestOctetsPerSecond = 0; + t->BestOctetsPerSecondTime = time(NULL); + } +} diff --git a/usr.sbin/ppp/throughput.h b/usr.sbin/ppp/ppp/throughput.h index 7e6e8ca1b48..e33954e445a 100644 --- a/usr.sbin/ppp/throughput.h +++ b/usr.sbin/ppp/ppp/throughput.h @@ -23,11 +23,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: throughput.h,v 1.2 1997/12/21 14:27:17 brian Exp $ + * $Id: throughput.h,v 1.1 1998/08/31 00:22:29 brian Exp $ */ #define SAMPLE_PERIOD 5 +#define THROUGHPUT_OVERALL 0x0001 +#define THROUGHPUT_CURRENT 0x0002 +#define THROUGHPUT_PEAK 0x0004 +#define THROUGHPUT_ALL THROUGHPUT_OVERALL | THROUGHPUT_CURRENT \ + | THROUGHPUT_PEAK + struct pppThroughput { time_t uptime; u_long OctetsIn; @@ -35,14 +41,17 @@ struct pppThroughput { u_long SampleOctets[SAMPLE_PERIOD]; int OctetsPerSecond; int BestOctetsPerSecond; + time_t BestOctetsPerSecondTime; int nSample; + unsigned rolling : 1; struct pppTimer Timer; }; extern void throughput_init(struct pppThroughput *); -extern void throughput_disp(struct pppThroughput *, FILE *); +extern void throughput_disp(struct pppThroughput *, struct prompt *); extern void throughput_log(struct pppThroughput *, int, const char *); -extern void throughput_start(struct pppThroughput *); +extern void throughput_start(struct pppThroughput *, const char *, int); extern void throughput_stop(struct pppThroughput *); extern void throughput_addin(struct pppThroughput *, int); extern void throughput_addout(struct pppThroughput *, int); +extern void throughput_clear(struct pppThroughput *, int, struct prompt *); diff --git a/usr.sbin/ppp/timer.c b/usr.sbin/ppp/ppp/timer.c index fcaa240b39c..b3028aea232 100644 --- a/usr.sbin/ppp/timer.c +++ b/usr.sbin/ppp/ppp/timer.c @@ -17,67 +17,65 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: timer.c,v 1.5 1998/06/28 09:41:45 brian Exp $ + * $Id: timer.c,v 1.1 1998/08/31 00:22:29 brian Exp $ * * TODO: */ #include <signal.h> -#ifdef SIGALRM -#include <errno.h> -#endif +#include <stdio.h> #include <sys/time.h> -#include <unistd.h> +#include <termios.h> -#include "command.h" -#include "mbuf.h" #include "log.h" #include "sig.h" #include "timer.h" +#include "descriptor.h" +#include "prompt.h" static struct pppTimer *TimerList = NULL; static void StopTimerNoBlock(struct pppTimer *); -static void InitTimerService(void); + +static const char * +tState2Nam(u_int state) +{ + static const char *StateNames[] = { "stopped", "running", "expired" }; + + if (state >= sizeof StateNames / sizeof StateNames[0]) + return "unknown"; + return StateNames[state]; +} void -StopTimer(struct pppTimer * tp) +timer_Stop(struct pppTimer * tp) { -#ifdef SIGALRM int omask; omask = sigblock(sigmask(SIGALRM)); -#endif StopTimerNoBlock(tp); -#ifdef SIGALRM sigsetmask(omask); -#endif } void -StartTimer(struct pppTimer * tp) +timer_Start(struct pppTimer * tp) { struct pppTimer *t, *pt; u_long ticks = 0; - -#ifdef SIGALRM int omask; omask = sigblock(sigmask(SIGALRM)); -#endif - if (tp->state != TIMER_STOPPED) { + if (tp->state != TIMER_STOPPED) StopTimerNoBlock(tp); - } + if (tp->load == 0) { - LogPrintf(LogDEBUG, "timer %x has 0 load!\n", tp); + log_Printf(LogTIMER, "%s timer[%p] has 0 load!\n", tp->name, tp); sigsetmask(omask); return; } pt = NULL; for (t = TimerList; t; t = t->next) { - LogPrintf(LogDEBUG, "StartTimer: %x(%d): ticks: %d, rest: %d\n", - t, t->state, ticks, t->rest); if (ticks + t->rest >= tp->load) break; ticks += t->rest; @@ -86,22 +84,25 @@ StartTimer(struct pppTimer * tp) tp->state = TIMER_RUNNING; tp->rest = tp->load - ticks; - LogPrintf(LogDEBUG, "StartTimer: Inserting %x before %x, rest = %d\n", - tp, t, tp->rest); + + if (t) + log_Printf(LogTIMER, "timer_Start: Inserting %s timer[%p] before %s " + "timer[%p], delta = %ld\n", tp->name, tp, t->name, t, tp->rest); + else + log_Printf(LogTIMER, "timer_Start: Inserting %s timer[%p]\n", tp->name, tp); + /* Insert given *tp just before *t */ tp->next = t; if (pt) { pt->next = tp; } else { - InitTimerService(); + timer_InitService(); TimerList = tp; } if (t) t->rest -= tp->rest; -#ifdef SIGALRM sigsetmask(omask); -#endif } static void @@ -110,12 +111,10 @@ StopTimerNoBlock(struct pppTimer * tp) struct pppTimer *t, *pt; /* - * A Running Timer should be removing TimerList, But STOPPED/EXPIRED is - * already removing TimerList. So just marked as TIMER_STOPPED. Do not - * change tp->enext!! (Might be Called by expired proc) + * A RUNNING timer must be removed from TimerList (->next list). + * A STOPPED timer isn't in any list, but may have a bogus [e]next field. + * An EXPIRED timer is in the ->enext list. */ - LogPrintf(LogDEBUG, "StopTimer: %x, next = %x state=%x\n", - tp, tp->next, tp->state); if (tp->state != TIMER_RUNNING) { tp->next = NULL; tp->state = TIMER_STOPPED; @@ -130,12 +129,12 @@ StopTimerNoBlock(struct pppTimer * tp) } else { TimerList = t->next; if (TimerList == NULL) /* Last one ? */ - TermTimerService(); /* Terminate Timer Service */ + timer_TermService(); /* Terminate Timer Service */ } if (t->next) t->next->rest += tp->rest; } else - LogPrintf(LogERROR, "Oops, timer not found!!\n"); + log_Printf(LogERROR, "Oops, %s timer not found!!\n", tp->name); tp->next = NULL; tp->state = TIMER_STOPPED; @@ -146,8 +145,14 @@ TimerService(void) { struct pppTimer *tp, *exp, *wt; - if (LogIsKept(LogDEBUG)) - ShowTimers(); + if (log_IsKept(LogTIMER)) { + static time_t t; /* Only show timers globally every second */ + time_t n = time(NULL); + + if (n > t) + timer_Show(LogTIMER, NULL); + t = n; + } tp = TimerList; if (tp) { tp->rest--; @@ -162,22 +167,19 @@ TimerService(void) wt = tp->next; tp->enext = exp; exp = tp; - LogPrintf(LogDEBUG, "TimerService: Add %x to exp\n", tp); tp = wt; } while (tp && (tp->rest == 0)); TimerList = tp; if (TimerList == NULL) /* No timers ? */ - TermTimerService(); /* Terminate Timer Service */ - LogPrintf(LogDEBUG, "TimerService: next is %x(%d)\n", - TimerList, TimerList ? TimerList->rest : 0); + timer_TermService(); /* Terminate Timer Service */ /* * Process all expired timers. */ while (exp) { #ifdef notdef - StopTimer(exp); + timer_Stop(exp); #endif if (exp->func) (*exp->func) (exp->arg); @@ -193,97 +195,53 @@ TimerService(void) } void -ShowTimers() +timer_Show(int LogLevel, struct prompt *prompt) { struct pppTimer *pt; - - LogPrintf(LogDEBUG, "---- Begin of Timer Service List---\n"); - for (pt = TimerList; pt; pt = pt->next) - LogPrintf(LogDEBUG, "%x: load = %d, rest = %d, state =%x\n", - pt, pt->load, pt->rest, pt->state); - LogPrintf(LogDEBUG, "---- End of Timer Service List ---\n"); -} - -#ifdef SIGALRM - -static void -nointr_dosleep(u_int sec, u_int usec) -{ - struct timeval to, st, et; - - gettimeofday(&st, NULL); - et.tv_sec = st.tv_sec + sec; - et.tv_usec = st.tv_usec + usec; - to.tv_sec = sec; - to.tv_usec = usec; - for (;;) { - if (select(0, NULL, NULL, NULL, &to) == 0 || - errno != EINTR) { - break; - } else { - gettimeofday(&to, NULL); - if (to.tv_sec > et.tv_sec + 1 || - (to.tv_sec == et.tv_sec + 1 && to.tv_usec > et.tv_usec) || - to.tv_sec < st.tv_sec || - (to.tv_sec == st.tv_sec && to.tv_usec < st.tv_usec)) { - LogPrintf(LogWARN, "Clock adjusted between %d and %d seconds " - "during sleep !\n", - to.tv_sec - st.tv_sec, sec + to.tv_sec - st.tv_sec); - st.tv_sec = to.tv_sec; - st.tv_usec = to.tv_usec; - et.tv_sec = st.tv_sec + sec; - et.tv_usec = st.tv_usec + usec; - to.tv_sec = sec; - to.tv_usec = usec; - } else if (to.tv_sec > et.tv_sec || - (to.tv_sec == et.tv_sec && to.tv_usec >= et.tv_usec)) { - break; - } else { - to.tv_sec = et.tv_sec - to.tv_sec; - if (et.tv_usec < to.tv_usec) { - to.tv_sec--; - to.tv_usec = 1000000 + et.tv_usec - to.tv_usec; - } else - to.tv_usec = et.tv_usec - to.tv_usec; - } - } + int rest = 0; + +#define SECS(val) ((val) / SECTICKS) +#define HSECS(val) (((val) % SECTICKS) * 100 / SECTICKS) +#define DISP \ + "%s timer[%p]: freq = %ld.%02lds, next = %d.%02ds, state = %s\n", \ + pt->name, pt, SECS(pt->load), HSECS(pt->load), SECS(rest), \ + HSECS(rest), tState2Nam(pt->state) + + if (!prompt) + log_Printf(LogLevel, "---- Begin of Timer Service List---\n"); + + for (pt = TimerList; pt; pt = pt->next) { + rest += pt->rest; + if (prompt) + prompt_Printf(prompt, DISP); + else + log_Printf(LogLevel, DISP); } -} -void -nointr_sleep(u_int sec) -{ - nointr_dosleep(sec, 0); + if (!prompt) + log_Printf(LogLevel, "---- End of Timer Service List ---\n"); } -void -nointr_usleep(u_int usec) -{ - nointr_dosleep(0, usec); -} - -static void -InitTimerService() +void +timer_InitService() { struct itimerval itimer; - pending_signal(SIGALRM, (void (*) (int)) TimerService); + sig_signal(SIGALRM, (void (*) (int)) TimerService); itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; if (setitimer(ITIMER_REAL, &itimer, NULL) == -1) - LogPrintf(LogERROR, "Unable to set itimer.\n"); + log_Printf(LogERROR, "Unable to set itimer.\n"); } void -TermTimerService(void) +timer_TermService(void) { struct itimerval itimer; itimer.it_interval.tv_usec = itimer.it_interval.tv_sec = 0; itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; if (setitimer(ITIMER_REAL, &itimer, NULL) == -1) - LogPrintf(LogERROR, "Unable to set itimer.\n"); - pending_signal(SIGALRM, SIG_IGN); + log_Printf(LogERROR, "Unable to set itimer.\n"); + sig_signal(SIGALRM, SIG_IGN); } - -#endif diff --git a/usr.sbin/ppp/timer.h b/usr.sbin/ppp/ppp/timer.h index ba18da519bd..d64e388136a 100644 --- a/usr.sbin/ppp/timer.h +++ b/usr.sbin/ppp/ppp/timer.h @@ -15,16 +15,17 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: timer.h,v 1.3 1998/01/21 02:13:42 brian Exp $ + * $Id: timer.h,v 1.1 1998/08/31 00:22:29 brian Exp $ * * TODO: */ -#define TICKUNIT 100000 /* Unit in usec */ -#define SECTICKS (1000000/TICKUNIT) +#define TICKUNIT 100000 /* usec's per Unit */ +#define SECTICKS (1000000/TICKUNIT) /* Units per second */ struct pppTimer { int state; + const char *name; u_long rest; /* Ticks to expire */ u_long load; /* Initial load value */ void (*func)(void *); /* Function called when timer is expired */ @@ -37,12 +38,10 @@ struct pppTimer { #define TIMER_RUNNING 1 #define TIMER_EXPIRED 2 -extern void StartTimer(struct pppTimer *); -extern void StopTimer(struct pppTimer *); -extern void TermTimerService(void); -extern void ShowTimers(void); +struct prompt; -#ifdef SIGALRM -extern void nointr_sleep(u_int); -extern void nointr_usleep(u_int); -#endif +extern void timer_Start(struct pppTimer *); +extern void timer_Stop(struct pppTimer *); +extern void timer_InitService(void); +extern void timer_TermService(void); +extern void timer_Show(int LogLevel, struct prompt *); diff --git a/usr.sbin/ppp/tun.c b/usr.sbin/ppp/ppp/tun.c index 17b472942e8..2043f61925c 100644 --- a/usr.sbin/ppp/tun.c +++ b/usr.sbin/ppp/ppp/tun.c @@ -23,44 +23,55 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: tun.c,v 1.4 1998/01/21 02:13:42 brian Exp $ + * $Id: tun.c,v 1.1 1998/08/31 00:22:30 brian Exp $ */ -#include <sys/param.h> -#include <sys/time.h> -#include <sys/socket.h> +#include <sys/types.h> +#include <sys/socket.h> /* For IFF_ defines */ +#include <net/if.h> /* For IFF_ defines */ #include <netinet/in.h> -#include <net/if.h> +#include <net/if_types.h> #include <net/if_tun.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> -#include <stdio.h> #include <string.h> #include <sys/ioctl.h> #include <sys/errno.h> -#include "command.h" #include "mbuf.h" #include "log.h" +#include "timer.h" +#include "lqr.h" #include "hdlc.h" #include "defs.h" -#include "loadalias.h" -#include "vars.h" +#include "fsm.h" +#include "throughput.h" +#include "iplist.h" +#include "slcompress.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "mp.h" +#include "bundle.h" #include "tun.h" void -tun_configure(int mtu, int speed) +tun_configure(struct bundle *bundle, int mtu) { struct tuninfo info; - info.type = 23; + info.type = IFT_PPP; info.mtu = mtu; - if (VarPrefMTU != 0 && VarPrefMTU < mtu) - info.mtu = VarPrefMTU; - info.baudrate = speed; + info.baudrate = bundle->ifp.Speed; #ifdef __OpenBSD__ info.flags = IFF_UP|IFF_POINTOPOINT; #endif - if (ioctl(tun_out, TUNSIFINFO, &info) < 0) - LogPrintf(LogERROR, "tun_configure: ioctl(TUNSIFINFO): %s\n", + if (ioctl(bundle->dev.fd, TUNSIFINFO, &info) < 0) + log_Printf(LogERROR, "tun_configure: ioctl(TUNSIFINFO): %s\n", strerror(errno)); } diff --git a/usr.sbin/ppp/tun.h b/usr.sbin/ppp/ppp/tun.h index 6a9bcab1ceb..705a8b731b6 100644 --- a/usr.sbin/ppp/tun.h +++ b/usr.sbin/ppp/ppp/tun.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: tun.h,v 1.3 1998/06/26 09:14:46 deraadt Exp $ + * $Id: tun.h,v 1.1 1998/08/31 00:22:30 brian Exp $ */ struct tun_data { @@ -41,4 +41,6 @@ struct tun_data { #define tun_check_header(f,proto) (1) #endif -extern void tun_configure(int, int); +struct bundle; + +extern void tun_configure(struct bundle *, int); diff --git a/usr.sbin/ppp/vjcomp.c b/usr.sbin/ppp/ppp/vjcomp.c index 7036980cb82..d2e2e1fdfeb 100644 --- a/usr.sbin/ppp/vjcomp.c +++ b/usr.sbin/ppp/ppp/vjcomp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: vjcomp.c,v 1.4 1998/01/21 02:13:44 brian Exp $ + * $Id: vjcomp.c,v 1.1 1998/08/31 00:22:30 brian Exp $ * * TODO: */ @@ -25,44 +25,50 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <sys/un.h> #include <stdio.h> #include <string.h> -#include "command.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "lcpproto.h" #include "slcompress.h" +#include "lqr.h" #include "hdlc.h" +#include "defs.h" +#include "iplist.h" +#include "throughput.h" #include "ipcp.h" +#include "lcp.h" +#include "ccp.h" +#include "link.h" +#include "filter.h" +#include "descriptor.h" +#include "mp.h" +#include "bundle.h" #include "vjcomp.h" #define MAX_VJHEADER 16 /* Maximum size of compressed header */ -static struct slcompress cslc; - -void -VjInit(int max_state) -{ - sl_compress_init(&cslc, max_state); -} - void -SendPppFrame(struct mbuf * bp) +vj_SendFrame(struct link *l, struct mbuf * bp, struct bundle *bundle) { int type; u_short proto; - u_short cproto = IpcpInfo.his_compproto >> 16; + u_short cproto = bundle->ncp.ipcp.peer_compproto >> 16; - LogPrintf(LogDEBUG, "SendPppFrame: proto = %x\n", IpcpInfo.his_compproto); + log_Printf(LogDEBUG, "vj_SendFrame: COMPPROTO = %x\n", + bundle->ncp.ipcp.peer_compproto); if (((struct ip *) MBUF_CTOP(bp))->ip_p == IPPROTO_TCP && cproto == PROTO_VJCOMP) { - type = sl_compress_tcp(bp, (struct ip *)MBUF_CTOP(bp), &cslc, - IpcpInfo.his_compproto & 0xff); - LogPrintf(LogDEBUG, "SendPppFrame: type = %x\n", type); + type = sl_compress_tcp(bp, (struct ip *)MBUF_CTOP(bp), + &bundle->ncp.ipcp.vj.cslc, + &bundle->ncp.ipcp.vj.slstat, + bundle->ncp.ipcp.peer_compproto & 0xff); + log_Printf(LogDEBUG, "vj_SendFrame: type = %x\n", type); switch (type) { case TYPE_IP: proto = PROTO_IP; @@ -74,24 +80,26 @@ SendPppFrame(struct mbuf * bp) proto = PROTO_VJCOMP; break; default: - LogPrintf(LogERROR, "Unknown frame type %x\n", type); - pfree(bp); + log_Printf(LogALERT, "Unknown frame type %x\n", type); + mbuf_Free(bp); return; } } else proto = PROTO_IP; - HdlcOutput(PRI_NORMAL, proto, bp); + + if (!ccp_Compress(&l->ccp, l, PRI_NORMAL, proto, bp)) + hdlc_Output(l, PRI_NORMAL, proto, bp); } static struct mbuf * -VjUncompressTcp(struct mbuf * bp, u_char type) +VjUncompressTcp(struct ipcp *ipcp, struct mbuf * bp, u_char type) { u_char *bufp; int len, olen, rlen; struct mbuf *nbp; u_char work[MAX_HDR + MAX_VJHEADER]; /* enough to hold TCP/IP header */ - olen = len = plength(bp); + olen = len = mbuf_Length(bp); if (type == TYPE_UNCOMPRESSED_TCP) { /* @@ -99,9 +107,10 @@ VjUncompressTcp(struct mbuf * bp, u_char type) * space for uncompression job. */ bufp = MBUF_CTOP(bp); - len = sl_uncompress_tcp(&bufp, len, type, &cslc); + len = sl_uncompress_tcp(&bufp, len, type, &ipcp->vj.cslc, &ipcp->vj.slstat, + (ipcp->my_compproto >> 8) & 255); if (len <= 0) { - pfree(bp); + mbuf_Free(bp); bp = NULL; } return (bp); @@ -116,27 +125,28 @@ VjUncompressTcp(struct mbuf * bp, u_char type) len = MAX_VJHEADER; rlen = len; bufp = work + MAX_HDR; - bp = mbread(bp, bufp, rlen); - len = sl_uncompress_tcp(&bufp, olen, type, &cslc); + bp = mbuf_Read(bp, bufp, rlen); + len = sl_uncompress_tcp(&bufp, olen, type, &ipcp->vj.cslc, &ipcp->vj.slstat, + (ipcp->my_compproto >> 8) & 255); if (len <= 0) { - pfree(bp); + mbuf_Free(bp); return NULL; } len -= olen; len += rlen; - nbp = mballoc(len, MB_VJCOMP); + nbp = mbuf_Alloc(len, MB_VJCOMP); memcpy(MBUF_CTOP(nbp), bufp, len); nbp->next = bp; return (nbp); } struct mbuf * -VjCompInput(struct mbuf * bp, int proto) +vj_Input(struct ipcp *ipcp, struct mbuf *bp, int proto) { u_char type; - LogPrintf(LogDEBUG, "VjCompInput: proto %02x\n", proto); - LogDumpBp(LogDEBUG, "Raw packet info:", bp); + log_Printf(LogDEBUG, "vj_Input: proto %02x\n", proto); + log_DumpBp(LogDEBUG, "Raw packet info:", bp); switch (proto) { case PROTO_VJCOMP: @@ -146,19 +156,22 @@ VjCompInput(struct mbuf * bp, int proto) type = TYPE_UNCOMPRESSED_TCP; break; default: - LogPrintf(LogERROR, "VjCompInput...???\n"); + log_Printf(LogWARN, "vj_Input...???\n"); return (bp); } - bp = VjUncompressTcp(bp, type); + bp = VjUncompressTcp(ipcp, bp, type); return (bp); } const char * vj2asc(u_int32_t val) { - static char asc[50]; + static char asc[50]; /* The return value is used immediately */ - sprintf(asc, "%d VJ slots %s slot compression", - (int)((val>>8)&15)+1, val & 1 ? "with" : "without"); + if (val) + snprintf(asc, sizeof asc, "%d VJ slots %s slot compression", + (int)((val>>8)&15)+1, val & 1 ? "with" : "without"); + else + strcpy(asc, "VJ disabled"); return asc; } diff --git a/usr.sbin/ppp/vjcomp.h b/usr.sbin/ppp/ppp/vjcomp.h index 7400739b9b4..734ebc011f7 100644 --- a/usr.sbin/ppp/vjcomp.h +++ b/usr.sbin/ppp/ppp/vjcomp.h @@ -23,10 +23,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: vjcomp.h,v 1.4 1998/01/11 17:54:49 brian Exp $ + * $Id: vjcomp.h,v 1.1 1998/08/31 00:22:30 brian Exp $ */ -extern void VjInit(int); -extern void SendPppFrame(struct mbuf *); -extern struct mbuf *VjCompInput(struct mbuf *, int); +struct mbuf; +struct link; +struct ipcp; +struct bundle; + +extern void vj_SendFrame(struct link *, struct mbuf *, struct bundle *); +extern struct mbuf *vj_Input(struct ipcp *, struct mbuf *, int); extern const char *vj2asc(u_int32_t); diff --git a/usr.sbin/ppp/pppctl/Makefile b/usr.sbin/ppp/pppctl/Makefile new file mode 100644 index 00000000000..0fd2e002f50 --- /dev/null +++ b/usr.sbin/ppp/pppctl/Makefile @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.1 1998/08/31 00:22:30 brian Exp $ + +PROG= pppctl +SRCS= pppctl.c +CFLAGS+=-Wall +LDADD+= -ledit -ltermcap +DPADD+= ${LIBEDIT} ${LIBTERMCAP} + +OPSYS!= uname -s +.if (${OPSYS} == "OpenBSD") +MAN= pppctl.8 +.else +MAN8= pppctl.8 +.endif + +.include <bsd.prog.mk> diff --git a/usr.sbin/pppctl/pppctl.8 b/usr.sbin/ppp/pppctl/pppctl.8 index cf54c2b57bc..1b5e6ae65e3 100644 --- a/usr.sbin/pppctl/pppctl.8 +++ b/usr.sbin/ppp/pppctl/pppctl.8 @@ -1,6 +1,6 @@ -.\" $Id: pppctl.8,v 1.4 1998/05/13 10:33:29 deraadt Exp $ +.\" $Id: pppctl.8,v 1.1 1998/08/31 00:22:31 brian Exp $ .Dd 26 June 1997 -.Os OpenBSD +.Os FreeBSD .Dt PPPCTL 8 .Sh NAME .Nm pppctl diff --git a/usr.sbin/pppctl/pppctl.c b/usr.sbin/ppp/pppctl/pppctl.c index 15ae7dcdc62..e59374c591b 100644 --- a/usr.sbin/pppctl/pppctl.c +++ b/usr.sbin/ppp/pppctl/pppctl.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pppctl.c,v 1.7 1998/03/21 16:39:24 todd Exp $ + * $Id: pppctl.c,v 1.1 1998/08/31 00:22:31 brian Exp $ */ #include <sys/types.h> diff --git a/usr.sbin/ppp/route.h b/usr.sbin/ppp/route.h deleted file mode 100644 index 835d048c6ef..00000000000 --- a/usr.sbin/ppp/route.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * User Process PPP - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: route.h,v 1.4 1998/01/19 02:57:34 brian Exp $ - * - */ - -extern int GetIfIndex(char *); -extern int ShowRoute(struct cmdargs const *); -extern void OsSetRoute(int, struct in_addr, struct in_addr, struct in_addr,int); -extern void DeleteIfRoutes(int); -extern struct in_addr ChooseHisAddr(const struct in_addr); -extern const char *Index2Nam(int); diff --git a/usr.sbin/ppp/server.c b/usr.sbin/ppp/server.c deleted file mode 100644 index a0245e704ef..00000000000 --- a/usr.sbin/ppp/server.c +++ /dev/null @@ -1,169 +0,0 @@ -/*- - * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: server.c,v 1.7 1998/02/18 20:33:30 brian Exp $ - */ - -#include <sys/param.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netinet/in_systm.h> - -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <unistd.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "loadalias.h" -#include "defs.h" -#include "vars.h" -#include "server.h" -#include "id.h" - -int server = -1; - -static struct sockaddr_un ifsun; -static char *rm; - -int -ServerLocalOpen(const char *name, mode_t mask) -{ - int s; - - if (VarLocalAuth == LOCAL_DENY) { - LogPrintf(LogWARN, "Local: Can't open socket %s: No password " - "in ppp.secret\n", name); - return 1; - } - - if (mode & MODE_INTER) { - LogPrintf(LogWARN, "Local: Can't open socket in interactive mode\n"); - return 1; - } - - memset(&ifsun, '\0', sizeof ifsun); - ifsun.sun_len = strlen(name); - if (ifsun.sun_len > sizeof ifsun.sun_path - 1) { - LogPrintf(LogERROR, "Local: %s: Path too long\n", name); - return 2; - } - ifsun.sun_family = AF_LOCAL; - strcpy(ifsun.sun_path, name); - - s = ID0socket(PF_LOCAL, SOCK_STREAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "Local: socket: %s\n", strerror(errno)); - return 3; - } - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); - if (mask != (mode_t)-1) - mask = umask(mask); - if (bind(s, (struct sockaddr *)&ifsun, sizeof ifsun) < 0) { - if (mask != (mode_t)-1) - umask(mask); - LogPrintf(LogERROR, "Local: bind: %s\n", strerror(errno)); - if (errno == EADDRINUSE && VarTerm) - fprintf(VarTerm, "Wait for a while, then try again.\n"); - close(s); - return 4; - } - if (mask != (mode_t)-1) - umask(mask); - if (listen(s, 5) != 0) { - LogPrintf(LogERROR, "Local: Unable to listen to socket - OS overload?\n"); - close(s); - ID0unlink(name); - return 5; - } - ServerClose(); - server = s; - rm = ifsun.sun_path; - LogPrintf(LogPHASE, "Listening at local socket %s.\n", name); - return 0; -} - -int -ServerTcpOpen(int port) -{ - struct sockaddr_in ifsin; - int s; - - if (VarLocalAuth == LOCAL_DENY) { - LogPrintf(LogWARN, "Tcp: Can't open socket %d: No password " - "in ppp.secret\n", port); - return 6; - } - - if (mode & MODE_INTER) { - LogPrintf(LogWARN, "Tcp: Can't open socket in interactive mode\n"); - return 6; - } - - s = ID0socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) { - LogPrintf(LogERROR, "Tcp: socket: %s\n", strerror(errno)); - return 7; - } - memset(&ifsin, '\0', sizeof ifsin); - ifsin.sin_family = AF_INET; - ifsin.sin_addr.s_addr = INADDR_ANY; - ifsin.sin_port = htons(port); - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &s, sizeof s); - if (bind(s, (struct sockaddr *)&ifsin, sizeof ifsin) < 0) { - LogPrintf(LogERROR, "Tcp: bind: %s\n", strerror(errno)); - if (errno == EADDRINUSE && VarTerm) - fprintf(VarTerm, "Wait for a while, then try again.\n"); - close(s); - return 8; - } - if (listen(s, 5) != 0) { - LogPrintf(LogERROR, "Tcp: Unable to listen to socket - OS overload?\n"); - close(s); - return 9; - } - ServerClose(); - server = s; - LogPrintf(LogPHASE, "Listening at port %d.\n", port); - return 0; -} - -void -ServerClose() -{ - if (server >= 0) { - close(server); - if (rm) { - ID0unlink(rm); - rm = 0; - } - } - server = -1; -} diff --git a/usr.sbin/ppp/vars.c b/usr.sbin/ppp/vars.c deleted file mode 100644 index 08b69ccdb11..00000000000 --- a/usr.sbin/ppp/vars.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * PPP configuration variables - * - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan, Inc. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: vars.c,v 1.7 1998/01/21 02:13:43 brian Exp $ - * - */ -#include <sys/param.h> -#include <netinet/in.h> - -#include <stdio.h> -#include <string.h> - -#include "command.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "hdlc.h" -#include "termios.h" -#include "loadalias.h" -#include "vars.h" -#include "auth.h" - -char VarVersion[] = "PPP Version 1.65"; -char VarLocalVersion[] = "$Date: 1998/01/21 02:13:43 $"; -int Utmp = 0; -int ipKeepAlive = 0; -int reconnectState = RECON_UNKNOWN; -int reconnectCount = 0; - -/* - * Order of conf option is important. See vars.h. - */ -struct confdesc pppConfs[] = { - {"acfcomp", CONF_ENABLE, CONF_ACCEPT}, - {"chap", CONF_DISABLE, CONF_ACCEPT}, - {"deflate", CONF_ENABLE, CONF_ACCEPT}, - {"lqr", CONF_DISABLE, CONF_ACCEPT}, - {"pap", CONF_DISABLE, CONF_ACCEPT}, - {"pppd-deflate", CONF_DISABLE, CONF_DENY}, - {"pred1", CONF_ENABLE, CONF_ACCEPT}, - {"protocomp", CONF_ENABLE, CONF_ACCEPT}, - {"vjcomp", CONF_ENABLE, CONF_ACCEPT}, - {"msext", CONF_DISABLE, CONF_NONE}, - {"passwdauth", CONF_DISABLE, CONF_NONE}, - {"proxy", CONF_DISABLE, CONF_NONE}, - {"throughput", CONF_DISABLE, CONF_NONE}, - {"utmp", CONF_ENABLE, CONF_NONE}, - {NULL}, -}; - -struct pppvars pppVars = { - DEF_MRU, DEF_MTU, 0, MODEM_SPEED, CS8, MODEM_CTSRTS, 180, 30, 3, - RECONNECT_TIMER, RECONNECT_TRIES, REDIAL_PERIOD, - NEXT_REDIAL_PERIOD, 1, 1, MODEM_DEV, "", BASE_MODEM_DEV, - 1, LOCAL_NO_AUTH, 0 -}; - -int -DisplayCommand(struct cmdargs const *arg) -{ - struct confdesc *vp; - - if (!VarTerm) - return 1; - - fprintf(VarTerm, "Current configuration option settings..\n\n"); - fprintf(VarTerm, "Name\t\tMy Side\t\tHis Side\n"); - fprintf(VarTerm, "----------------------------------------\n"); - for (vp = pppConfs; vp->name; vp++) - fprintf(VarTerm, "%-10s\t%s\t\t%s\n", vp->name, - (vp->myside == CONF_ENABLE) ? "enable" : - (vp->myside == CONF_DISABLE ? "disable" : "N/A"), - (vp->hisside == CONF_ACCEPT) ? "accept" : - (vp->hisside == CONF_DENY ? "deny" : "N/A")); - - return 0; -} - -static int -ConfigCommand(struct cmdargs const *arg, int mine, int val) -{ - struct confdesc *vp; - int err; - int narg = 0; - - if (arg->argc < 1) - return -1; - - err = 0; - do { - for (vp = pppConfs; vp->name; vp++) - if (strcasecmp(vp->name, arg->argv[narg]) == 0) { - if (mine) { - if (vp->myside == CONF_NONE) { - LogPrintf(LogWARN, "Config: %s cannot be enabled or disabled\n", - vp->name); - err++; - } else - vp->myside = val; - } else { - if (vp->hisside == CONF_NONE) { - LogPrintf(LogWARN, "Config: %s cannot be accepted or denied\n", - vp->name); - err++; - } else - vp->hisside = val; - } - break; - } - if (!vp->name) { - LogPrintf(LogWARN, "Config: %s: No such key word\n", arg->argv[narg]); - err++; - } - } while (++narg < arg->argc); - - return err; -} - -int -EnableCommand(struct cmdargs const *arg) -{ - return ConfigCommand(arg, 1, CONF_ENABLE); -} - -int -DisableCommand(struct cmdargs const *arg) -{ - return ConfigCommand(arg, 1, CONF_DISABLE); -} - -int -AcceptCommand(struct cmdargs const *arg) -{ - return ConfigCommand(arg, 0, CONF_ACCEPT); -} - -int -DenyCommand(struct cmdargs const *arg) -{ - return ConfigCommand(arg, 0, CONF_DENY); -} - -int -LocalAuthCommand(struct cmdargs const *arg) -{ - const char *pass; - if (arg->argc == 0) - pass = ""; - else if (arg->argc > 1) - return -1; - else - pass = *arg->argv; - - if (VarHaveLocalAuthKey) - VarLocalAuth = strcmp(VarLocalAuthKey, pass) ? LOCAL_NO_AUTH : LOCAL_AUTH; - else - switch (LocalAuthValidate(SECRETFILE, VarShortHost, pass)) { - case INVALID: - VarLocalAuth = LOCAL_NO_AUTH; - break; - case VALID: - VarLocalAuth = LOCAL_AUTH; - break; - case NOT_FOUND: - VarLocalAuth = LOCAL_AUTH; - LogPrintf(LogWARN, "WARNING: No Entry for this system\n"); - break; - default: - VarLocalAuth = LOCAL_NO_AUTH; - LogPrintf(LogERROR, "LocalAuthCommand: Ooops?\n"); - return 1; - } - return 0; -} diff --git a/usr.sbin/ppp/vars.h b/usr.sbin/ppp/vars.h deleted file mode 100644 index 5921ab80c89..00000000000 --- a/usr.sbin/ppp/vars.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Written by Toshiharu OHNO (tony-o@iij.ad.jp) - * - * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Internet Initiative Japan. The name of the - * IIJ may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: vars.h,v 1.7 1998/01/21 02:13:44 brian Exp $ - * - * TODO: - */ - -struct confdesc { - const char *name; - int myside, hisside; -}; - -#define CONF_NONE -1 -#define CONF_DISABLE 0 -#define CONF_ENABLE 1 - -#define CONF_DENY 0 -#define CONF_ACCEPT 1 - -#define ConfAcfcomp 0 -#define ConfChap 1 -#define ConfDeflate 2 -#define ConfLqr 3 -#define ConfPap 4 -#define ConfPppdDeflate 5 -#define ConfPred1 6 -#define ConfProtocomp 7 -#define ConfVjcomp 8 - -#define ConfMSExt 9 -#define ConfPasswdAuth 10 -#define ConfProxy 11 -#define ConfThroughput 12 -#define ConfUtmp 13 -#define MAXCONFS 14 - -#define Enabled(x) (pppConfs[x].myside & CONF_ENABLE) -#define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT) - -extern struct confdesc pppConfs[MAXCONFS + 1]; - -struct pppvars { - u_short var_mru; /* Initial MRU value */ - u_short pref_mtu; /* Preferred MTU value */ - int var_accmap; /* Initial ACCMAP value */ - int modem_speed; /* Current modem speed */ - int modem_parity; /* Parity setting */ - int modem_ctsrts; /* Use CTS/RTS on modem port? (boolean) */ - int idle_timeout; /* Idle timeout value */ - int lqr_timeout; /* LQR timeout value */ - int retry_timeout; /* Retry timeout value */ - int reconnect_timer; /* Timeout before reconnect on carrier loss */ - int reconnect_tries; /* Attempt reconnect on carrier loss */ - int redial_timeout; /* Redial timeout value */ - int redial_next_timeout; /* Redial next timeout value */ - int dial_tries; /* Dial attempts before giving up, 0 == inf */ - int loopback; /* Turn around packets addressed to me */ - char modem_devlist[LINE_LEN]; /* Comma-separated list of devices */ - char modem_dev[40]; /* Name of device / host:port */ - const char *base_modem_dev; /* Pointer to base of modem_dev */ - int open_mode; /* Delay before first LCP REQ (-1 = passive) */ -#define LOCAL_AUTH 0x01 -#define LOCAL_NO_AUTH 0x02 -#define LOCAL_DENY 0x03 - u_char lauth; /* Local Authorized status */ - FILE *termfp; /* The terminal */ -#define DIALUP_REQ 0x01 -#define DIALUP_DONE 0x02 - char dial_script[SCRIPT_LEN]; /* Dial script */ - char login_script[SCRIPT_LEN]; /* Login script */ - char auth_key[50]; /* PAP/CHAP key */ - char auth_name[50]; /* PAP/CHAP system name */ - char local_auth_key[50]; /* Local auth passwd */ - int have_local_auth_key; /* Local auth passwd specified ? */ -#ifdef HAVE_DES - int use_MSChap; /* Use MSCHAP encryption */ -#endif - char phone_numbers[200]; /* Telephone Numbers */ - char phone_copy[200]; /* copy for strsep() */ - char *next_phone; /* Next phone from the list */ - char *alt_phone; /* Next phone from the list */ - char shostname[MAXHOSTNAMELEN]; /* Local short Host Name */ - char hangup_script[SCRIPT_LEN]; /* Hangup script before modem is closed */ - struct aliasHandlers handler; /* Alias function pointers */ -}; - -#define VarAccmap pppVars.var_accmap -#define VarMRU pppVars.var_mru -#define VarPrefMTU pppVars.pref_mtu -#define VarDevice pppVars.modem_dev -#define VarDeviceList pppVars.modem_devlist -#define VarBaseDevice pppVars.base_modem_dev -#define VarSpeed pppVars.modem_speed -#define VarParity pppVars.modem_parity -#define VarCtsRts pppVars.modem_ctsrts -#define VarOpenMode pppVars.open_mode -#define VarLocalAuth pppVars.lauth -#define VarDialScript pppVars.dial_script -#define VarHangupScript pppVars.hangup_script -#define VarLoginScript pppVars.login_script -#define VarIdleTimeout pppVars.idle_timeout -#define VarLqrTimeout pppVars.lqr_timeout -#define VarRetryTimeout pppVars.retry_timeout -#define VarAuthKey pppVars.auth_key -#define VarAuthName pppVars.auth_name -#define VarLocalAuthKey pppVars.local_auth_key -#define VarHaveLocalAuthKey pppVars.have_local_auth_key -#ifdef HAVE_DES -#define VarMSChap pppVars.use_MSChap -#endif -#define VarPhoneList pppVars.phone_numbers -#define VarPhoneCopy pppVars.phone_copy -#define VarNextPhone pppVars.next_phone -#define VarAltPhone pppVars.alt_phone -#define VarShortHost pppVars.shostname -#define VarReconnectTimer pppVars.reconnect_timer -#define VarReconnectTries pppVars.reconnect_tries -#define VarRedialTimeout pppVars.redial_timeout -#define VarRedialNextTimeout pppVars.redial_next_timeout -#define VarDialTries pppVars.dial_tries -#define VarLoopback pppVars.loopback -#define VarTerm pppVars.termfp - -#define VarAliasHandlers pppVars.handler -#define VarPacketAliasGetFragment (*pppVars.handler.PacketAliasGetFragment) -#define VarPacketAliasGetFragment (*pppVars.handler.PacketAliasGetFragment) -#define VarPacketAliasInit (*pppVars.handler.PacketAliasInit) -#define VarPacketAliasIn (*pppVars.handler.PacketAliasIn) -#define VarPacketAliasOut (*pppVars.handler.PacketAliasOut) -#define VarPacketAliasRedirectAddr (*pppVars.handler.PacketAliasRedirectAddr) -#define VarPacketAliasRedirectPort (*pppVars.handler.PacketAliasRedirectPort) -#define VarPacketAliasSaveFragment (*pppVars.handler.PacketAliasSaveFragment) -#define VarPacketAliasSetAddress (*pppVars.handler.PacketAliasSetAddress) -#define VarPacketAliasSetMode (*pppVars.handler.PacketAliasSetMode) -#define VarPacketAliasFragmentIn (*pppVars.handler.PacketAliasFragmentIn) - -#define DEV_IS_SYNC (VarSpeed == 0) - -extern struct pppvars pppVars; -extern char VarVersion[]; -extern char VarLocalVersion[]; - -extern int Utmp; /* Are we in /etc/utmp ? */ -extern int ipKeepAlive; -extern int reconnectState; -extern int reconnectCount; - -#define RECON_TRUE (1) -#define RECON_FALSE (2) -#define RECON_UNKNOWN (3) -#define RECON_ENVOKED (4) -#define reconnect(x) \ - do \ - if (reconnectState == RECON_UNKNOWN) { \ - reconnectState = x; \ - if (x == RECON_FALSE) \ - reconnectCount = 0; \ - } \ - while(0) - - -/* - * This is the logic behind the reconnect variables: - * We have four reconnect "states". We start off not requiring anything - * from the reconnect code (reconnectState == RECON_UNKNOWN). If the - * line is brought down (via LcpClose() or LcpDown()), we have to decide - * whether to set to RECON_TRUE or RECON_FALSE. It's only here that we - * know the correct action. Once we've decided, we don't want that - * decision to be overridden (hence the above reconnect() macro) - If we - * call LcpClose, the ModemTimeout() still gets to "notice" that the line - * is down. When it "notice"s, it should only set RECON_TRUE if a decision - * hasn't already been made. - * - * In main.c, when we notice we have RECON_TRUE, we must only action - * it once. The fourth "state" is where we're bringing the line up, - * but if we call LcpClose for any reason (failed PAP/CHAP etc) we - * don't want to set to RECON_{TRUE,FALSE}. - * - * If we get a connection or give up dialing, we go back to RECON_UNKNOWN. - * If we get give up dialing or reconnecting or if we chose to down the - * connection, we set reconnectCount back to zero. - * - */ - -extern int EnableCommand(struct cmdargs const *); -extern int DisableCommand(struct cmdargs const *); -extern int AcceptCommand(struct cmdargs const *); -extern int DenyCommand(struct cmdargs const *); -extern int LocalAuthCommand(struct cmdargs const *); -extern int DisplayCommand(struct cmdargs const *); diff --git a/usr.sbin/pppctl/Makefile b/usr.sbin/pppctl/Makefile deleted file mode 100644 index feb62d2019a..00000000000 --- a/usr.sbin/pppctl/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $Id: Makefile,v 1.2 1998/07/24 00:11:11 millert Exp $ - -PROG= pppctl -SRCS= pppctl.c -CFLAGS+=-Wall -Wmissing-prototypes -LDADD+= -ledit -lcurses -DPADD+= ${LIBEDIT} ${LIBCURSES} -MAN= pppctl.8 - -.include <bsd.prog.mk> |