diff options
Diffstat (limited to 'usr.sbin/ppp')
85 files changed, 19544 insertions, 0 deletions
diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile new file mode 100644 index 00000000000..f9dbc19e38e --- /dev/null +++ b/usr.sbin/ppp/Makefile @@ -0,0 +1,23 @@ +# $Id: Makefile,v 1.1 1997/11/23 20:27:32 brian Exp $ + +PROG= ppp +SRCS= arp.c async.c auth.c ccp.c chap.c chap_ms.c chat.c \ + command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.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 +LDADD+= -lutil -ldes +DPADD+= ${LIBUTIL} ${LIBDES} +MAN= ppp.8 +BINMODE=4550 +BINOWN= root +BINGRP= network + +.if exists(/usr/include/alias.h) +SRCS+= alias_cmd.c loadalias.c +.else +CFLAGS+=-DNOALIAS +.endif + +.include <bsd.prog.mk> diff --git a/usr.sbin/ppp/README.alias b/usr.sbin/ppp/README.alias new file mode 100644 index 00000000000..de5b3c90af7 --- /dev/null +++ b/usr.sbin/ppp/README.alias @@ -0,0 +1,352 @@ +User PPP Packet Aliasing + + + +0. Contents + 1. Background + 2. Setup + 3. New commands in ppp + 4. Future Work + 5. Authors / Acknowledgments + 6. Revision History for Aliasing Code + + + +1. Background + +User mode ppp has embedded packet aliasing (IP masquerading) code. +Enabling this, either by the "-alias" command line option or the +"alias enable yes" command in a ppp.conf file, makes the ppp host +automatically alias IP packets forwarded from a local network, making +them appear to come from the ppp host machine. Incoming packets +from the outside world are then appropriately de-aliased. + +The process of aliasing involves both the IP address and the TCP or UDP +port numbers. ICMP echo and timestamp packets are aliased by their id +numbers. ICMP error messages can be properly directed by examining the +fragment of the offending packet which is contained in the body of the +message. + +This software was specifically meant to support users who have +unregistered, private address IP networks (e.g. 192.168.0.x or 10.0.0.x +addresses). The ppp host can act as a gateway for these networks, and +computers on the local area net will have some degree of Internet access +without the need for a registered IP address. Additionally, there will +be no need for an Internet service provider to maintain routing tables +for the local area network. + +A disadvantage of packet aliasing is that machines on the local network, +behind the ppp host, are not visible from the outside world. They can +establish TCP connections and make UDP inquiries (such as domain name +service requests) but the connections seem to come from the ppp host +itself. There is, in effect, a partial firewall. Of course, if this is +what you want, the disadvantage becomes an advantage. + +A second disadvantage is that "IP encoding" protocols, which send IP +address or port information within the data stream, are not supported +for the cases where exception code exists. This implementation has +workarounds for FTP and IRC DCC, the most well known of the IP encoding +protocols. This frees users from depending on using the ftp passive +mode and avoiding IRC DCC sends, as is sometimes the case with other +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 +correctly. + +The packet aliasing code also handle many ICMP messages. In particular, +ping and traceroute are supported. + + + +2. Packet Aliasing Setup + +It is recommended that users first verify correct ppp operation without +packet aliasing enabled. This will confirm that the ppp.conf file is +properly set up and that there are no ppp problems. Then start ppp with +the "-alias" option on the command line. The user should verify that +the ppp host can correctly connect to the Internet in packet aliasing +mode. Finally, check that machines on the private network can access +the Internet. + +The masquerading software aliases all packets, whether they come from +the host or another computer on the local area network. Thus, a correctly +operating ppp host indicates that the software should work properly for +other computers on the private network. + +If the ppp host can access the Internet, but other computers on the local +network cannot, check that IP forwarding is enabled on the ppp host. Also, +verify that the other computers use this machine as a gateway. Of course, +you should also verify that machines within the local area network +communicate properly. A common error is inconsistent subnet addresses +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 +is in addition to the -alias command line option. System managers and +more experienced users may prefer to use the iij-ppp command syntax +within the ppp.conf file. The alias command also allows packet aliasing +behavior 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. + +The syntax for 'alias' is + + ppp> alias option [yes|no] + +where option is given by one of the following templates. + + + - alias enable [yes|no] (default no) + +Enable packet aliasing functionality. If disabled, no other alias +options will have any effect. You should usually enable aliasing +before routing any packets over the link; good points are in the +initial script or right before adding a route. If you do not always +want aliasing, consider using the -alias option to ppp instead of this +command. + + + - alias deny_incoming [yes|no] (default yes) + +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 +all incoming connections to telnetd, ftpd, etc. + + + - alias log [yes|no] + +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. + + + - alias same_ports [yes|no] (default yes) + +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 +_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 +per machine. + + + - alias use_sockets [yes|no] (default yes) + +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 +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 +until the TCP connection has been acknowledged on both sides. The safe +option is yes, though fewer system resources are consumed by specifying +no. + + + - alias unregistered_only [yes|no] (default no) + +Packet aliasing normally remaps all packets coming from the local area +network to the ppp host machine address. Set this option to only map +addresses from the following standard ranges for private, unregistered +addresses: + + 10.0.0.0 -> 10.255.255.255 + 172.16.0.0 -> 172.31.255.255 + 192.168.0.0 -> 192.168.255.255 */ + +In the instance that there is a subnet of public addresses and another +subnet of private addresses being routed by the ppp host, then only the +packets on the private subnet will be aliased. + + +- alias port <proto> <local addr>:<port> <alias port> + +This command allows incoming traffic to <alias port> on the host +machine to be redirected to a specific machine and port on the +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 +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 +in dotted quad notation or in /etc/hosts. + + +- alias addr <local addr> <public addr> + +This command allows traffic for a public IP address to be +redirected to a machine on the local network. This function +is known as "static NAT". An address assignment of 0 refers +to the default address of the ppp host. Normally static +NAT is useful if your ISP has allocated a small block of +IP addresses to the user, but it can even be used in the +case of a single, dynamically allocated IP address: + + alias addr 10.0.0.8 0 + +The above command would redirect all incoming traffic to +machine 10.0.0.8. + +If several address aliases specifiy the same public addres +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 +translated local address (192.168.0.4), but outgoing +traffic to the first two addresses will still be aliased +to the specified public address. + + + +4. Future Work + +What is called packet aliasing here has been variously called masquerading, +network address translation (NAT) and transparent proxying by others. It +is an extremely useful function to many users, but it is also necessarily +imperfect. The occasional IP-encoding protocols always need workarounds +(hacks). Users who are interested in supporting new IP-encoding protocols +can follow the examples of alias_ftp.c and alias_irc.c. + +ICMP error messages are currently handled only in the incoming direction. +A handler needs to be added to correctly alias outgoing error messages. + +IRC and FTP exception handling make reasonable, though not strictly correct +assumptions, about how IP encoded messages will appear in the control +stream. Programmers may wish to consider how to make this process more +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 +host address, outgoing aliasing and incoming de-aliasing). + + + +5. Authors / Acknowledgments + +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> + +Listed below, in chronological order, are individuals who have provided +valuable comments and/or debugging assistance. + + Gary Roberts + Tom Torrance + Reto Burkhalter + Martin Renters + Brian Somers + Paul Traina + Ari Suutari + J. Fortes + Andrzej Bialeki + + + +6. Revision History for Aliasing Code + +Version 1.0: August 11, 1996 (cjm) + +Version 1.1: August 20, 1996 (cjm) + PPP 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 + Can't remember (this version only lasted a day -- 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 as well as FreeBSD traceroute. + +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. + +Verstion 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 + 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. + (Update done with the permission of cjm) + +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 - + minor API changes for integration with other programs than PPP (ee) + - Changed the build process, making all options switchable + from the Makefile (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) + - Incoming packets which are not recognized 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). + - 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. + - Now supports outgoing as well as incoming ICMP error messges/ + - PPP commands to support address and port redirection. + diff --git a/usr.sbin/ppp/alias_cmd.c b/usr.sbin/ppp/alias_cmd.c new file mode 100644 index 00000000000..240772833e2 --- /dev/null +++ b/usr.sbin/ppp/alias_cmd.c @@ -0,0 +1,191 @@ +/* + * $Id: alias_cmd.c,v 1.1 1997/11/23 20:27:32 brian Exp $ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "defs.h" +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "loadalias.h" +#include "vars.h" +#include "alias_cmd.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 +AliasRedirectPort(struct cmdargs const *arg) +{ + if (!(mode & MODE_ALIAS)) { + if (VarTerm) + fprintf(VarTerm, "Alias not enabled\n"); + } else if (arg->argc == 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[0]; + if (strcmp(proto, "tcp") == 0) { + proto_constant = IPPROTO_TCP; + } else if (strcmp(proto, "udp") == 0) { + proto_constant = IPPROTO_UDP; + } else { + if (VarTerm) { + fprintf(VarTerm, "port redirect: protocol must be tcp or udp\n"); + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, + arg->cmd->syntax); + } + return 1; + } + + error = StrToAddrAndPort(arg->argv[1], &local_addr, &local_port, proto); + if (error) { + if (VarTerm) { + fprintf(VarTerm, "port redirect: error reading local addr:port\n"); + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + } + return 1; + } + error = StrToPort(arg->argv[2], &alias_port, proto); + if (error) { + if (VarTerm) { + fprintf(VarTerm, "port redirect: error reading alias port\n"); + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + } + return 1; + } + null_addr.s_addr = 0; + + link = VarPacketAliasRedirectPort(local_addr, local_port, + null_addr, 0, + null_addr, alias_port, + proto_constant); + + if (link == NULL && VarTerm) + fprintf(VarTerm, "port redirect: error returned by packed" + " aliasing engine (code=%d)\n", error); + } else if (VarTerm) + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + + return 1; +} + + +int +AliasRedirectAddr(struct cmdargs const *arg) +{ + if (!(mode & MODE_ALIAS)) { + if (VarTerm) + fprintf(VarTerm, "alias not enabled\n"); + } else if (arg->argc == 2) { + int error; + struct in_addr local_addr; + struct in_addr alias_addr; + struct alias_link *link; + + error = StrToAddr(arg->argv[0], &local_addr); + if (error) { + if (VarTerm) + fprintf(VarTerm, "address redirect: invalid local address\n"); + return 1; + } + error = StrToAddr(arg->argv[1], &alias_addr); + if (error) { + if (VarTerm) { + fprintf(VarTerm, "address redirect: invalid alias address\n"); + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + } + return 1; + } + link = VarPacketAliasRedirectAddr(local_addr, alias_addr); + if (link == NULL && VarTerm) { + fprintf(VarTerm, "address redirect: packet aliasing engine error\n"); + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + } + } else if (VarTerm) + fprintf(VarTerm, "Usage: alias %s %s\n", arg->cmd->name, arg->cmd->syntax); + + return 1; +} + + +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) { + LogPrintf(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) { + LogPrintf(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) { + LogPrintf(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/alias_cmd.h b/usr.sbin/ppp/alias_cmd.h new file mode 100644 index 00000000000..6b5e37eeee5 --- /dev/null +++ b/usr.sbin/ppp/alias_cmd.h @@ -0,0 +1,6 @@ +/* + * $Id: alias_cmd.h,v 1.1 1997/11/23 20:27:32 brian Exp $ + */ + +extern int AliasRedirectPort(struct cmdargs const *); +extern int AliasRedirectAddr(struct cmdargs const *); diff --git a/usr.sbin/ppp/arp.c b/usr.sbin/ppp/arp.c new file mode 100644 index 00000000000..bed1cd879aa --- /dev/null +++ b/usr.sbin/ppp/arp.c @@ -0,0 +1,314 @@ +/* + * sys-bsd.c - System-dependent procedures for setting up + * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * 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 Carnegie Mellon University. The name of the + * University 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: arp.c,v 1.1 1997/11/23 20:27:32 brian Exp $ + * + */ + +/* + * TODO: + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/route.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <net/if_types.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <unistd.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "id.h" +#include "arp.h" + +static int rtm_seq; + +static int get_ether_addr(int, u_long, struct sockaddr_dl *); + +/* + * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, + * if it exists. + */ +#define SET_SA_FAMILY(addr, family) \ + memset((char *) &(addr), '\0', sizeof(addr)); \ + addr.sa_family = (family); \ + addr.sa_len = sizeof(addr); + + +#if RTM_VERSION >= 3 + +/* + * sifproxyarp - Make a proxy ARP entry for the peer. + */ +static struct { + struct rt_msghdr hdr; + struct sockaddr_inarp dst; + struct sockaddr_dl hwa; + char extra[128]; +} arpmsg; + +static int arpmsg_valid; + +int +sifproxyarp(int unit, u_long hisaddr) +{ + int routes; + + /* + * Get the hardware address of an interface on the same subnet as our local + * address. + */ + memset(&arpmsg, 0, sizeof(arpmsg)); + if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { + LogPrintf(LogERROR, "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", + 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_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; + 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)); + close(routes); + return 0; + } + close(routes); + arpmsg_valid = 1; + return 1; +} + +/* + * cifproxyarp - Delete the proxy ARP entry for the peer. + */ +int +cifproxyarp(int unit, u_long hisaddr) +{ + int routes; + + if (!arpmsg_valid) + return 0; + arpmsg_valid = 0; + + arpmsg.hdr.rtm_type = RTM_DELETE; + arpmsg.hdr.rtm_seq = ++rtm_seq; + + routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); + if (routes < 0) { + LogPrintf(LogERROR, "sifproxyarp: 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)); + close(routes); + return 0; + } + close(routes); + return 1; +} + +#else /* RTM_VERSION */ + +/* + * sifproxyarp - Make a proxy ARP entry for the peer. + */ +int +sifproxyarp(int unit, u_long hisaddr) +{ + struct arpreq arpreq; + struct { + struct sockaddr_dl sdl; + char space[128]; + } dls; + + memset(&arpreq, '\0', sizeof(arpreq)); + + /* + * 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"); + 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; + arpreq.arp_flags = ATF_PERM | ATF_PUBL; + if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { + LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno)); + return 0; + } + return 1; +} + +/* + * cifproxyarp - Delete the proxy ARP entry for the peer. + */ +int +cifproxyarp(int unit, u_long hisaddr) +{ + 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; + if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { + LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno)); + return 0; + } + return 1; +} + +#endif /* RTM_VERSION */ + + +/* + * get_ether_addr - get the hardware address of an interface on the + * the same subnet as ipaddr. + */ +#define MAX_IFS 32 + +static int +get_ether_addr(int s, u_long ipaddr, struct sockaddr_dl *hwaddr) +{ + struct ifreq *ifr, *ifend, *ifp; + u_long ina, mask; + struct sockaddr_dl *dla; + struct ifreq ifreq; + struct ifconf ifc; + struct ifreq ifs[MAX_IFS]; + + ifc.ifc_len = sizeof(ifs); + ifc.ifc_req = ifs; + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): %s\n", + strerror(errno)); + return 0; + } + + /* + * Scan through looking for an interface with an Internet address on the + * same subnet as `ipaddr'. + */ + ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + for (ifr = ifc.ifc_req; ifr < ifend;) { + if (ifr->ifr_addr.sa_family == AF_INET) { + ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr; + strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0'; + + /* + * Check that the interface is up, and not point-to-point or loopback. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) + continue; + if ((ifreq.ifr_flags & + (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)) + != (IFF_UP | IFF_BROADCAST)) + goto nextif; + + /* + * Get its netmask and check that it's on the right subnet. + */ + if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) + continue; + mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr; + if ((ipaddr & mask) != (ina & mask)) + goto nextif; + + break; + } +nextif: + ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); + } + + if (ifr >= ifend) + return 0; + LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name); + + /* + * Now scan through again looking for a link-level address for this + * interface. + */ + ifp = ifr; + for (ifr = ifc.ifc_req; ifr < ifend;) { + if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 + && ifr->ifr_addr.sa_family == AF_LINK) { + + /* + * Found the link-level address - copy it out + */ + dla = (struct sockaddr_dl *) & ifr->ifr_addr; + memcpy(hwaddr, dla, dla->sdl_len); + return 1; + } + ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); + } + + return 0; +} + + +#ifdef DEBUG +int +main() +{ + u_long ipaddr; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + ipaddr = inet_addr("192.168.1.32"); + sifproxyarp(s, ipaddr); + close(s); +} +#endif diff --git a/usr.sbin/ppp/arp.h b/usr.sbin/ppp/arp.h new file mode 100644 index 00000000000..53b6b934b04 --- /dev/null +++ b/usr.sbin/ppp/arp.h @@ -0,0 +1,25 @@ +/* + * 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: arp.h,v 1.1 1997/11/23 20:27:32 brian Exp $ + * + */ + +extern int cifproxyarp(int, u_long); +extern int sifproxyarp(int, u_long); diff --git a/usr.sbin/ppp/async.c b/usr.sbin/ppp/async.c new file mode 100644 index 00000000000..1f04ace6507 --- /dev/null +++ b/usr.sbin/ppp/async.c @@ -0,0 +1,198 @@ +/* + * PPP Async HDLC 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: async.c,v 1.1 1997/11/23 20:27:32 brian Exp $ + * + */ +#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 "lcp.h" +#include "lcpproto.h" +#include "modem.h" +#include "loadalias.h" +#include "vars.h" +#include "os.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_long my_accmap; + u_long his_accmap; +} AsyncState; + +#define MODE_HUNT 0x01 +#define MODE_ESC 0x02 + +void +AsyncInit() +{ + struct async_state *stp = &AsyncState; + + stp->mode = MODE_HUNT; + stp->length = 0; + stp->my_accmap = stp->his_accmap = 0xffffffff; +} + +void +SetLinkParams(struct lcpstate *lcp) +{ + struct async_state *stp = &AsyncState; + + stp->my_accmap = lcp->want_accmap; + stp->his_accmap = lcp->his_accmap; +} + +/* + * Encode into async HDLC byte code if necessary + */ +static void +HdlcPutByte(u_char **cp, u_char c, int proto) +{ + u_char *wp; + + wp = *cp; + if ((c < 0x20 && (proto == PROTO_LCP || (AsyncState.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))) { + *wp++ = HDLC_ESC; + c ^= HDLC_XOR; + } + *wp++ = c; + *cp = wp; +} + +void +AsyncOutput(int pri, struct mbuf *bp, int proto) +{ + struct async_state *hs = &AsyncState; + u_char *cp, *sp, *ep; + struct mbuf *wp; + int cnt; + + if (plength(bp) > HDLCSIZE) { + pfree(bp); + return; + } + cp = hs->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); + if (cp >= ep) { + pfree(bp); + return; + } + } + wp = wp->next; + } + *cp++ = HDLC_SYN; + + cnt = cp - hs->xbuff; + LogDumpBuff(LogASYNC, "WriteModem", hs->xbuff, cnt); + WriteModem(pri, (char *) hs->xbuff, cnt); + ModemAddOutOctets(cnt); + pfree(bp); +} + +static struct mbuf * +AsyncDecode(u_char c) +{ + struct async_state *hs = &AsyncState; + struct mbuf *bp; + + if ((hs->mode & MODE_HUNT) && c != HDLC_SYN) + return (NULLBUFF); + + 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; + return (bp); + } + break; + case HDLC_ESC: + if (!(hs->mode & MODE_ESC)) { + hs->mode |= MODE_ESC; + break; + } + /* Fall into ... */ + default: + if (hs->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; + break; + } + if (hs->mode & MODE_ESC) { + c ^= HDLC_XOR; + hs->mode &= ~MODE_ESC; + } + hs->hbuff[hs->length++] = c; + break; + } + return NULLBUFF; +} + +void +AsyncInput(u_char *buff, int cnt) +{ + struct mbuf *bp; + + ModemAddInOctets(cnt); + if (DEV_IS_SYNC) { + bp = mballoc(cnt, MB_ASYNC); + memcpy(MBUF_CTOP(bp), buff, cnt); + bp->cnt = cnt; + HdlcInput(bp); + } else { + while (cnt > 0) { + bp = AsyncDecode(*buff++); + if (bp) + HdlcInput(bp); + cnt--; + } + } +} diff --git a/usr.sbin/ppp/async.h b/usr.sbin/ppp/async.h new file mode 100644 index 00000000000..0f185c4793c --- /dev/null +++ b/usr.sbin/ppp/async.h @@ -0,0 +1,8 @@ +/* + * $Id: async.h,v 1.1 1997/11/23 20:27:33 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 new file mode 100644 index 00000000000..c3a2b055e24 --- /dev/null +++ b/usr.sbin/ppp/auth.c @@ -0,0 +1,223 @@ +/* + * 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 1997/11/23 20:27:33 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 "log.h" +#include "defs.h" +#include "timer.h" +#include "fsm.h" +#include "lcpproto.h" +#include "ipcp.h" +#include "loadalias.h" +#include "vars.h" +#include "filter.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[4]; + 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); + memset(&DefHisAddress, '\0', sizeof(DefHisAddress)); + n -= 2; + if (n > 0) { + if (ParseAddr(n--, (char const *const *)(vector+2), + &DefHisAddress.ipaddr, + &DefHisAddress.mask, + &DefHisAddress.width) == 0) { + return (0); /* Invalid */ + } + } + IpcpInit(); + 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[4]; + 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)); + } + n -= 2; + if (n > 0 && setaddr) { + LogPrintf(LogDEBUG, "AuthGetSecret: n = %d, %s\n", n, vector[2]); + if (ParseAddr(n--, (char const *const *)(vector+2), + &DefHisAddress.ipaddr, + &DefHisAddress.mask, + &DefHisAddress.width) != 0) + IpcpInit(); + } + 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/auth.h b/usr.sbin/ppp/auth.h new file mode 100644 index 00000000000..aa430576da9 --- /dev/null +++ b/usr.sbin/ppp/auth.h @@ -0,0 +1,41 @@ +/* + * 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: auth.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ + +typedef enum { + VALID, + INVALID, + NOT_FOUND +} LOCAL_AUTH_VALID; + +struct authinfo { + void (*ChallengeFunc) (int); + struct pppTimer authtimer; + int retry; + int id; +}; + +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); diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c new file mode 100644 index 00000000000..e60d64070d7 --- /dev/null +++ b/usr.sbin/ppp/ccp.c @@ -0,0 +1,284 @@ +/* + * 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 1997/11/23 20:27:33 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" + +struct ccpstate CcpInfo; + +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 *); + +#define REJECTED(p, x) (p->his_reject & (1<<x)) + +struct fsm CcpFsm = { + "CCP", + PROTO_CCP, + CCP_MAXCODE, + OPEN_ACTIVE, + ST_INITIAL, + 0, 0, 0, + 0, + {0, 0, 0, NULL, NULL, NULL}, + {0, 0, 0, NULL, NULL, NULL}, + 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 */ + "MSPPC", /* 18: Microsoft PPC */ + "GAND", /* 19: Gandalf FZA */ + "V42BIS", /* 20: ARG->DATA.42bis compression */ + "BSD", /* BSD LZW Compress */ +}; + +#define NCFTYPES (sizeof(cftypes)/sizeof(char *)) + +int +ReportCcpStatus(struct cmdargs const *arg) +{ + struct ccpstate *icp = &CcpInfo; + struct fsm *fp = &CcpFsm; + + if (VarTerm) { + fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); + fprintf(VarTerm, "myproto = %s, hisproto = %s\n", + cftypes[icp->want_proto], cftypes[icp->his_proto]); + fprintf(VarTerm, "Input: %ld --> %ld, Output: %ld --> %ld\n", + icp->orgin, icp->compin, icp->orgout, icp->compout); + } + return 0; +} + +void +CcpInit() +{ + struct ccpstate *icp = &CcpInfo; + + FsmInit(&CcpFsm); + memset(icp, '\0', sizeof(struct ccpstate)); + if (Enabled(ConfPred1)) + icp->want_proto = TY_PRED1; + 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; + struct ccpstate *icp = &CcpInfo; + + cp = ReqBuff; + LogPrintf(LogCCP, "CcpSendConfigReq\n"); + if (icp->want_proto && !REJECTED(icp, TY_PRED1)) { + *cp++ = TY_PRED1; + *cp++ = 2; + } + FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); +} + +void +CcpSendResetReq(struct fsm *fp) +{ + LogPrintf(LogCCP, "CcpSendResetReq\n"); + 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) +{ + Pred1Init(2); /* Initialize Output part */ +} + +static void +CcpLayerStart(struct fsm *fp) +{ + LogPrintf(LogCCP, "CcpLayerStart.\n"); +} + +static void +CcpLayerFinish(struct fsm *fp) +{ + LogPrintf(LogCCP, "CcpLayerFinish.\n"); +} + +static void +CcpLayerDown(struct fsm *fp) +{ + LogPrintf(LogCCP, "CcpLayerDown.\n"); +} + +/* + * Called when CCP has reached to OPEN state + */ +static void +CcpLayerUp(struct fsm *fp) +{ + LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state); + LogPrintf(LogCCP, "myproto = %d, hisproto = %d\n", + CcpInfo.want_proto, CcpInfo.his_proto); + Pred1Init(3); /* Initialize Input and Output */ +} + +void +CcpUp() +{ + FsmUp(&CcpFsm); + LogPrintf(LogCCP, "CCP Up event!!\n"); +} + +void +CcpOpen() +{ + if (Enabled(ConfPred1)) + FsmOpen(&CcpFsm); +} + +static void +CcpDecodeConfig(u_char *cp, int plen, int mode_type) +{ + int type, length; + char tbuff[100]; + + ackp = AckBuff; + nakp = NakBuff; + rejp = RejBuff; + + while (plen >= sizeof(struct fsmconfig)) { + if (plen < 0) + break; + type = *cp; + length = cp[1]; + if (type < NCFTYPES) + snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length); + else + snprintf(tbuff, sizeof(tbuff), " "); + + LogPrintf(LogCCP, "%s\n", tbuff); + + switch (type) { + case TY_PRED1: + switch (mode_type) { + case MODE_REQ: + if (Acceptable(ConfPred1)) { + memcpy(ackp, cp, length); + ackp += length; + CcpInfo.his_proto = type; + } else { + memcpy(rejp, cp, length); + rejp += length; + } + break; + case MODE_NAK: + case MODE_REJ: + CcpInfo.his_reject |= (1 << type); + CcpInfo.want_proto = 0; + break; + } + break; + case TY_BSD: + default: + CcpInfo.my_reject |= (1 << type); + memcpy(rejp, cp, length); + rejp += length; + break; + } + plen -= length; + cp += length; + } +} + +void +CcpInput(struct mbuf *bp) +{ + if (phase == PHASE_NETWORK) + FsmInput(&CcpFsm, bp); + else { + if (phase > PHASE_NETWORK) + LogPrintf(LogERROR, "Unexpected CCP in phase %d\n", phase); + pfree(bp); + } +} diff --git a/usr.sbin/ppp/ccp.h b/usr.sbin/ppp/ccp.h new file mode 100644 index 00000000000..f6343a53cbf --- /dev/null +++ b/usr.sbin/ppp/ccp.h @@ -0,0 +1,56 @@ +/* + * 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 1997/11/23 20:27:33 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 */ + +struct ccpstate { + u_long his_proto; /* peer's compression protocol */ + u_long want_proto; /* my compression protocol */ + + u_long his_reject; /* Request codes rejected by peer */ + u_long my_reject; /* Request codes I have rejected */ + + u_long orgout, compout; + u_long orgin, compin; +}; + +extern struct ccpstate CcpInfo; +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 *); diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c new file mode 100644 index 00000000000..539d629e3ff --- /dev/null +++ b/usr.sbin/ppp/chap.c @@ -0,0 +1,311 @@ +/* + * PPP CHAP 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: chap.c,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ +#include <sys/param.h> +#include <netinet/in.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 "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 "hdlc.h" +#include "phase.h" +#include "loadalias.h" +#include "vars.h" +#include "auth.h" + +static const char *chapcodes[] = { + "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" +}; + +static void +ChapOutput(u_int code, u_int id, const 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, "ChapOutput", bp); + LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); + HdlcOutput(PRI_LINK, PROTO_CHAP, bp); +} + + +static char challenge_data[80]; +static int challenge_len; + +static void +SendChapChallenge(int chapid) +{ + int len, i; + char *cp; + + randinit(); + cp = challenge_data; + *cp++ = challenge_len = random() % 32 + 16; + for (i = 0; i < challenge_len; i++) + *cp++ = random() & 0xff; + len = strlen(VarAuthName); + memcpy(cp, VarAuthName, len); + cp += len; + ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data); +} + +struct authinfo AuthChapInfo = { + SendChapChallenge, +}; + +static void +RecvChapTalk(struct fsmheader *chp, struct mbuf *bp) +{ + int valsize, len; + int arglen, keylen, namelen; + char *cp, *argp, *ap, *name, *digest; + char *keyp; + MD5_CTX MD5context; /* context for MD5 */ + char answer[100]; + char cdigest[16]; +#ifdef HAVE_DES + int ix; + MD4_CTX MD4context; /* context for MD4 */ +#endif + + len = ntohs(chp->length); + LogPrintf(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(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name); + + switch (chp->code) { + case CHAP_CHALLENGE: + keyp = VarAuthKey; + keylen = strlen(VarAuthKey); + name = VarAuthName; + namelen = strlen(VarAuthName); + +#ifdef HAVE_DES + if (VarMSChap) + 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); + return; + } +#ifdef HAVE_DES + if (VarMSChap) { + digest = argp; /* this is the response */ + *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ + memset(digest, '\0', 24); + digest += 24; + + ap = answer; /* this is the challenge */ + memcpy(ap, keyp, keylen); + ap += 2 * keylen; + memcpy(ap, cp, valsize); + LogDumpBuff(LogDEBUG, "recv", ap, valsize); + ap += valsize; + for (ix = keylen; ix > 0 ; ix--) { + answer[2*ix-2] = answer[ix-1]; + answer[2*ix-1] = 0; + } + MD4Init(&MD4context); + MD4Update(&MD4context, answer, 2 * keylen); + 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); + } else { +#endif + digest = argp; + *digest++ = 16; /* value size */ + ap = answer; + *ap++ = chp->id; + memcpy(ap, keyp, keylen); + ap += keylen; + memcpy(ap, cp, valsize); + LogDumpBuff(LogDEBUG, "recv", ap, valsize); + ap += valsize; + MD5Init(&MD5context); + MD5Update(&MD5context, answer, ap - answer); + MD5Final(digest, &MD5context); + LogDumpBuff(LogDEBUG, "answer", digest, 16); + memcpy(digest + 16, name, namelen); + ap += namelen; + /* Send answer to the peer */ + ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17); +#ifdef HAVE_DES + } +#endif + free(argp); + break; + case CHAP_RESPONSE: + /* + * Get a secret key corresponds to the peer + */ + keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE); + if (keyp) { + /* + * Compute correct digest value + */ + keylen = strlen(keyp); + ap = answer; + *ap++ = chp->id; + memcpy(ap, keyp, keylen); + ap += keylen; + MD5Init(&MD5context); + MD5Update(&MD5context, answer, ap - answer); + MD5Update(&MD5context, challenge_data + 1, challenge_len); + MD5Final(cdigest, &MD5context); + LogDumpBuff(LogDEBUG, "got", cp, 16); + LogDumpBuff(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)-1); + strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); + if (logout(ut.ut_line)) + logwtmp(ut.ut_line, "", ""); + login(&ut); + Utmp = 1; + } + NewPhase(PHASE_NETWORK); + break; + } + } + + /* + * Peer is not registerd, or response digest is wrong. + */ + ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9); + reconnect(RECON_FALSE); + LcpClose(); + break; + } +} + +static void +RecvChapResult(struct fsmheader *chp, struct mbuf *bp) +{ + int len; + struct lcpstate *lcp = &LcpInfo; + + len = ntohs(chp->length); + LogPrintf(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); + } + } else { + + /* + * Maybe, we shoud close LCP. Of cause, peer may take close action, too. + */ + ; + } +} + +void +ChapInput(struct mbuf *bp) +{ + int len = plength(bp); + struct fsmheader *chp; + + if (len >= sizeof(struct fsmheader)) { + chp = (struct fsmheader *) MBUF_CTOP(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); + /* Fall into.. */ + case CHAP_CHALLENGE: + RecvChapTalk(chp, bp); + break; + case CHAP_SUCCESS: + case CHAP_FAILURE: + RecvChapResult(chp, bp); + break; + } + } + } + pfree(bp); +} diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/chap.h new file mode 100644 index 00000000000..c41ecde74a4 --- /dev/null +++ b/usr.sbin/ppp/chap.h @@ -0,0 +1,30 @@ +/* + * 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: chap.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ + +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +extern struct authinfo AuthChapInfo; + +extern void ChapInput(struct mbuf *); diff --git a/usr.sbin/ppp/chap_ms.c b/usr.sbin/ppp/chap_ms.c new file mode 100644 index 00000000000..370bd94c06f --- /dev/null +++ b/usr.sbin/ppp/chap_ms.c @@ -0,0 +1,115 @@ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * 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 Eric Rosenquist. The name of the author 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: chap_ms.c,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + */ + +#include <sys/types.h> + +#include <des.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <syslog.h> + +#include "command.h" +#include "mbuf.h" +#include "timer.h" +#include "chap.h" +#include "chap_ms.h" + +/* unused, for documentation only */ +/* only NTResp is filled in for FreeBSD */ +typedef struct { + 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 *); + +static void /* IN 8 octets IN 16 octets OUT 24 octets */ +ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response) +{ + char ZPasswordHash[21]; + + memset(ZPasswordHash, '\0', sizeof(ZPasswordHash)); + memcpy(ZPasswordHash, pwHash, 16); + + DesEncrypt(challenge, ZPasswordHash + 0, response + 0); + DesEncrypt(challenge, ZPasswordHash + 7, response + 8); + DesEncrypt(challenge, ZPasswordHash + 14, response + 16); +} + +static void /* IN 8 octets IN 7 octest OUT 8 octets */ +DesEncrypt(u_char *clear, u_char *key, u_char *cipher) +{ + des_cblock des_key; + des_key_schedule key_schedule; + + MakeKey(key, des_key); + des_set_key(&des_key, key_schedule); + des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); +} + +static u_char Get7Bits(u_char *input, int startBit) +{ + register unsigned int word; + + word = (unsigned)input[startBit / 8] << 8; + word |= (unsigned)input[startBit / 8 + 1]; + + word >>= 15 - (startBit % 8 + 7); + + return word & 0xFE; +} + +/* IN 56 bit DES key missing parity bits + OUT 64 bit DES key with parity bits added */ +static void MakeKey(u_char *key, u_char *des_key) +{ + des_key[0] = Get7Bits(key, 0); + des_key[1] = Get7Bits(key, 7); + des_key[2] = Get7Bits(key, 14); + des_key[3] = Get7Bits(key, 21); + des_key[4] = Get7Bits(key, 28); + des_key[5] = Get7Bits(key, 35); + des_key[6] = Get7Bits(key, 42); + des_key[7] = Get7Bits(key, 49); + + des_set_odd_parity((des_cblock *)des_key); +} + +/* passwordHash 16-bytes MD4 hashed password + 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) +{ + u_char response[24]; + + ChallengeResponse(challenge, passwordHash, response); + memcpy(passwordHash, response, 24); + passwordHash += 24; + *passwordHash = 1; +} diff --git a/usr.sbin/ppp/chap_ms.h b/usr.sbin/ppp/chap_ms.h new file mode 100644 index 00000000000..74ddc3b5e85 --- /dev/null +++ b/usr.sbin/ppp/chap_ms.h @@ -0,0 +1,31 @@ +/* + * chap.h - Cryptographic Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * 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 Eric Rosenquist. The name of the author 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: chap_ms.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + */ + +/* Max # of (Unicode) chars in an NT password */ +#define MAX_NT_PASSWORD 256 + +/* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */ +#define MS_CHAP_RESPONSE_LEN 49 + +extern void ChapMS(char *, char *, int); diff --git a/usr.sbin/ppp/chat.c b/usr.sbin/ppp/chat.c new file mode 100644 index 00000000000..2f42b56abb0 --- /dev/null +++ b/usr.sbin/ppp/chat.c @@ -0,0 +1,641 @@ +/* + * 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.1 1997/11/23 20:27:33 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/socket.h> +#include <sys/time.h> +#include <sys/uio.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 "sig.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]; + +#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) { + strcpy(VarPhoneCopy, VarPhoneList); + 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 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(); + ExpandString(estr, buff, sizeof(buff), 0); + LogPrintf(LogCHAT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff); + 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 +ExecStr(char *command, char *out) +{ + int pid; + int fids[2]; + char *vector[MAXARGS]; + int stat, nb; + char *cp; + char tmp[300]; + + cp = inbuff + strlen(inbuff) - 1; + while (cp > inbuff) { + if (*cp < ' ' && *cp != '\t') { + cp++; + break; + } + cp--; + } + if (snprintf(tmp, sizeof tmp, "%s %s", command, cp) >= sizeof tmp) { + LogPrintf(LogCHAT, "Too long string to ExecStr: \"%s\"\n", command); + return; + } + MakeArgs(tmp, vector, VECSIZE(vector)); + + if (pipe(fids) < 0) { + LogPrintf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", + strerror(errno)); + return; + } + pid = fork(); + if (pid == 0) { + TermTimerService(); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGALRM, SIG_DFL); + close(fids[0]); + if (dup2(fids[1], 1) < 0) { + LogPrintf(LogCHAT, "dup2(fids[1], 1) in ExecStr: %s\n", strerror(errno)); + return; + } + close(fids[1]); + nb = open("/dev/tty", O_RDWR); + if (dup2(nb, 0) < 0) { + LogPrintf(LogCHAT, "dup2(nb, 0) in ExecStr: %s\n", strerror(errno)); + return; + } + setuid(geteuid()); + LogPrintf(LogCHAT, "exec: %s\n", command); + pid = execvp(command, (char **)vector); + LogPrintf(LogCHAT, "execvp failed for (%d/%d): %s\n", pid, errno, command); + exit(127); + } else { + close(fids[1]); + for (;;) { + nb = read(fids[0], out, 1); + if (nb <= 0) + break; + out++; + } + *out = '\0'; + close(fids[0]); + close(fids[1]); + waitpid(pid, &stat, WNOHANG); + } +} + +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); + } else { + ExpandString(str, buff + 2, sizeof(buff) - 2, 1); + } + if (strstr(str, "\\P")) /* Do not log the password itself. */ + LogPrintf(LogCHAT, "sending: %s\n", str); + else + LogPrintf(LogCHAT, "sending: %s\n", 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 jmp_buf ChatEnv; +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; + + if (!script || !*script) + return MATCH; + + /* While we're chatting, we want an INT to fail us */ + if (setjmp(ChatEnv)) { + signal(SIGINT, oint); + return (-1); + } + 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 new file mode 100644 index 00000000000..4a53844c35c --- /dev/null +++ b/usr.sbin/ppp/chat.h @@ -0,0 +1,29 @@ +/* + * 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 new file mode 100644 index 00000000000..002cc44f5db --- /dev/null +++ b/usr.sbin/ppp/command.c @@ -0,0 +1,1628 @@ +/* + * 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 1997/11/23 20:27:33 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 "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 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 *mes = NULL; + + if (mode & MODE_DDIAL) + mes = "Working in dedicated dial mode."; + else if (mode & MODE_BACKGROUND) + mes = "Working in background mode."; + else if (mode & MODE_AUTO) + mes = "Working in auto mode."; + else if (mode & MODE_DIRECT) + mes = "Working in direct mode."; + else if (mode & MODE_DEDICATED) + mes = "Working in dedicated mode."; + if (mes) { + if (Display && VarTerm) + fprintf(VarTerm, "%s\n", mes); + return 0; + } + return 1; +} + +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 (arg->argc > 0 && (res = LoadCommand(arg)) != 0) + return res; + + tries = 0; + do { + 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) { + nointr_sleep(1); + ModemTimeout(NULL); + PacketMode(); + 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; + FILE *oVarTerm; + 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; + + 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); + + if (fd > 2) + if (VarTerm) { + oVarTerm = VarTerm; + VarTerm = 0; + if (oVarTerm && oVarTerm != stdout) + fclose(oVarTerm); + } else + close(fd); + + 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) + fprintf(VarTerm, "ppp: Pausing until %s finishes\n", arg->argv[0]); + execvp(argv[0], argv); + } else { + if (VarTerm) + fprintf(VarTerm, "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(1); + + 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"}, + {"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 ALL | dest [gateway [mask]]"}, + {"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) + fprintf(VarTerm, " Idle Timer: %d secs LQR Timer: %d secs" + " Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout, + VarRetryTimeout); + 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", VarAuthKey); +#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: %ld\n", VarMRU); + return 0; +} + +static int +ShowPreferredMTU(struct cmdargs const *arg) +{ + if (VarTerm) + if (VarPrefMTU) + fprintf(VarTerm, " Preferred MTU: %ld\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"}, + {"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"}, +#ifndef NOMSEXT + {"msext", NULL, ShowMSExt, LOCAL_AUTH, + "Show MS PPP extentions", "show msext"}, +#endif + {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, + "Show version string", "show version"}, + {"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) +{ + struct cmdtab const *cmd; + int val = 1; + int nmatch; + struct cmdargs arg; + + cmd = FindCommand(cmds, *argv, &nmatch); + if (nmatch > 1) + LogPrintf(LogWARN, "%s: Ambiguous command\n", *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: Invalid command\n", *argv); + + if (val == -1) + LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax); + else if (val) + LogPrintf(LogCOMMAND, "%s: Failed %d\n", *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; +} + +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) { + strcpy(buf, label); + strcat(buf, ": "); + } + n = strlen(buf); + for (f = 0; f < argc; f++) { + if (n < sizeof(buf)-1 && f) + buf[n++] = ' '; + 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); + 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, "Enter to terminal mode.\n"); + fprintf(VarTerm, "Type `~?' for help.\n"); + } + TtyTermMode(); + return (0); +} + +static int +QuitCommand(struct cmdargs const *arg) +{ + if (VarTerm) { + DropClient(); + 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); + 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 +SetIdleTimeout(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; + + hp = gethostbyname(cp); + if (hp && hp->h_addrtype == AF_INET) + memcpy(&ipaddr, hp->h_addr, hp->h_length); + else if (inet_aton(cp, &ipaddr) == 0) + ipaddr.s_addr = 0; + return (ipaddr); +} + +static int +SetInterfaceAddr(struct cmdargs const *arg) +{ + DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L; + + if (arg->argc > 4) + return -1; + + HaveTriggerAddress = 0; + ifnetmask.s_addr = 0; + + if (arg->argc > 0) { + if (ParseAddr(arg->argc, arg->argv, + &DefMyAddress.ipaddr, + &DefMyAddress.mask, + &DefMyAddress.width) == 0) + return 1; + if (arg->argc > 1) { + if (ParseAddr(arg->argc, arg->argv+1, + &DefHisAddress.ipaddr, + &DefHisAddress.mask, + &DefHisAddress.width) == 0) + return 2; + 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; + } + if (DefHisAddress.ipaddr.s_addr == 0) { + DefHisAddress.mask.s_addr = 0; + DefHisAddress.width = 0; + } + IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; + IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; + + if ((mode & MODE_AUTO) && + OsSetIpaddress(DefMyAddress.ipaddr, DefHisAddress.ipaddr, ifnetmask) < 0) + return 4; + + 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; + int param = (int)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 (modem != -1) + LogPrintf(LogWARN, "Cannot change device to \"%s\" when \"%s\" is open\n", + argp, VarDevice); + else { + strncpy(VarDevice, argp, sizeof(VarDevice) - 1); + VarDevice[sizeof(VarDevice) - 1] = '\0'; + VarBaseDevice = strrchr(VarDevice, '/'); + VarBaseDevice = VarBaseDevice ? VarBaseDevice + 1 : ""; + } + 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'; + strcpy(VarPhoneCopy, VarPhoneList); + 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 (strcmp(*arg->argv, "active") == 0) + VarOpenMode = OPEN_ACTIVE; + else if (strcmp(*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", (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"}, + {"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, SetIdleTimeout, LOCAL_AUTH, + "Set Idle timeout", "set timeout value"}, +#ifndef NOMSEXT + {"ns", NULL, SetNS, LOCAL_AUTH, + "Set NameServer", "set ns pri-addr [sec-addr]"}, + {"nbns", NULL, SetNBNS, LOCAL_AUTH, + "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"}, +#endif + {"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); + 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; + + if (arg->argc == 3) { + if (strcasecmp(arg->argv[0], "MYADDR") == 0) + dest = IpcpInfo.want_ipaddr; + else + dest = GetIpAddr(arg->argv[0]); + netmask = GetIpAddr(arg->argv[1]); + if (strcasecmp(arg->argv[2], "HISADDR") == 0) + gateway = IpcpInfo.his_ipaddr; + else + gateway = GetIpAddr(arg->argv[2]); + OsSetRoute(RTM_ADD, dest, gateway, netmask); + return 0; + } + return -1; +} + +static int +DeleteCommand(struct cmdargs const *arg) +{ + struct in_addr dest, gateway, netmask; + + if (arg->argc == 1 && strcasecmp(arg->argv[0], "all") == 0) + DeleteIfRoutes(0); + else if (arg->argc > 0 && arg->argc < 4) { + if (strcasecmp(arg->argv[0], "MYADDR") == 0) + dest = IpcpInfo.want_ipaddr; + else + dest = GetIpAddr(arg->argv[0]); + netmask.s_addr = INADDR_ANY; + if (arg->argc > 1) { + if (strcasecmp(arg->argv[1], "HISADDR") == 0) + gateway = IpcpInfo.his_ipaddr; + else + gateway = GetIpAddr(arg->argv[1]); + if (arg->argc == 3) { + if (inet_aton(arg->argv[2], &netmask) == 0) { + LogPrintf(LogWARN, "Bad netmask value.\n"); + return -1; + } + } + } else + gateway.s_addr = INADDR_ANY; + OsSetRoute(RTM_DELETE, dest, gateway, netmask); + } 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); + 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); + 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 new file mode 100644 index 00000000000..e74f7c48031 --- /dev/null +++ b/usr.sbin/ppp/command.h @@ -0,0 +1,62 @@ +/* + * 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/defs.c b/usr.sbin/ppp/defs.c new file mode 100644 index 00000000000..a942a097f37 --- /dev/null +++ b/usr.sbin/ppp/defs.c @@ -0,0 +1,92 @@ +/* + * $Id: defs.c,v 1.1 1997/11/23 20:27:33 brian Exp $ + */ + +#include <sys/param.h> +#include <netinet/in.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#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); + else + *dstsystem = '\0'; +} + +const char * +GetLabel() +{ + return *dstsystem ? dstsystem : NULL; +} + +void +randinit() +{ +#ifdef __FreeBSD__ + static int initdone; + + if (!initdone) { + initdone = 1; + srandomdev(); + } +#else + srandom(time(NULL)^getpid()); +#endif +} + + +int +GetShortHost() +{ + char *p; + + if (gethostname(VarShortHost, sizeof(VarShortHost))) { + LogPrintf(LogERROR, "GetShortHost: gethostbyname: %s\n", strerror(errno)); + return 0; + } + + if ((p = strchr(VarShortHost, '.'))) + *p = '\0'; + + return 1; +} + +void +DropClient() +{ + FILE *oVarTerm; + + if (VarTerm && !(mode & MODE_INTER)) { + oVarTerm = VarTerm; + VarTerm = 0; + if (oVarTerm) + fclose(oVarTerm); + close(netfd); + netfd = -1; + LogPrintf(LogPHASE, "Client connection closed.\n"); + } +} diff --git a/usr.sbin/ppp/defs.h b/usr.sbin/ppp/defs.h new file mode 100644 index 00000000000..7d3e846dc39 --- /dev/null +++ b/usr.sbin/ppp/defs.h @@ -0,0 +1,95 @@ +/* + * 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: defs.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ + +/* + * Check 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 */ +#else +# ifdef __OpenBSD__ +# define MODEM_DEV "/dev/cua01" /* name of tty device */ +# define BASE_MODEM_DEV "cua01" /* name of base tty device */ +# else +# define MODEM_DEV "/dev/tty01" /* name of tty device */ +# define BASE_MODEM_DEV "tty01" /* name of base tty device */ +# endif +#endif + +#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 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 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 +#define EX_SOCK 2 +#define EX_MODEM 3 +#define EX_DIAL 4 +#define EX_DEAD 5 +#define EX_DONE 6 +#define EX_REBOOT 7 +#define EX_ERRDEAD 8 +#define EX_HANGUP 10 +#define EX_TERM 11 +#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; + +extern void SetLabel(const char *); +extern const char *GetLabel(void); +extern void randinit(void); +extern int GetShortHost(void); +extern void DropClient(void); diff --git a/usr.sbin/ppp/filter.c b/usr.sbin/ppp/filter.c new file mode 100644 index 00000000000..119ce0f3f09 --- /dev/null +++ b/usr.sbin/ppp/filter.c @@ -0,0 +1,495 @@ +/* + * 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 1997/11/23 20:27:33 brian Exp $ + * + * TODO: Shoud send ICMP error message when we discard packets. + */ + +#include <sys/param.h> +#include <sys/socket.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_long 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); + } + pmask->s_addr = 0xffffffff; /* Assume 255.255.255.255 as default */ + + cp = strchr(*argv, '/'); + 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; + } + + *pwidth = bits; + 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); +} + +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/filter.h b/usr.sbin/ppp/filter.h new file mode 100644 index 00000000000..6235b9f6c84 --- /dev/null +++ b/usr.sbin/ppp/filter.h @@ -0,0 +1,87 @@ +/* + * 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.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ + +/* + * Actions + */ +#define A_NONE 0 +#define A_PERMIT 1 +#define A_DENY 2 +#define A_MASK 3 +#define A_UHOST 4 +#define A_UPORT 8 + +/* + * Known protocols + */ +#define P_NONE 0 +#define P_TCP 1 +#define P_UDP 2 +#define P_ICMP 3 + +/* + * Operations + */ +#define OP_NONE 0 +#define OP_EQ 1 +#define OP_GT 2 +#define OP_LT 4 + +struct filterent { + int action; /* Filtering action */ + int swidth; /* Effective source address width */ + struct in_addr saddr; /* Source address */ + struct in_addr smask; /* Source address mask */ + int dwidth; /* Effective destination address width */ + struct in_addr daddr; /* Destination address */ + struct in_addr dmask; /* Destination address mask */ + int proto; /* Protocol */ + struct { + short srcop; + u_short srcport; + short dstop; + u_short dstport; + int estab; + } opt; +}; + +#define MAXFILTERS 20 + +#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 */ + +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 *); diff --git a/usr.sbin/ppp/fsm.c b/usr.sbin/ppp/fsm.c new file mode 100644 index 00000000000..58083329105 --- /dev/null +++ b/usr.sbin/ppp/fsm.c @@ -0,0 +1,789 @@ +/* + * 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 1997/11/23 20:27:33 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" +#include "pred.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 (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); +} + +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 { + FsmInitRestartCounter(fp); + FsmSendConfigReq(fp); + NewState(fp, ST_REQSENT); + } + 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(LogERROR, "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_long *lp, magic; + + cp = MBUF_CTOP(bp); + lp = (u_long *) 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_long *lp, magic; + + lp = (u_long *) 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\n"); + CcpRecvResetReq(fp); + LogPrintf(fp->LogLevel, "SendResetAck\n"); + FsmOutput(fp, CODE_RESETACK, fp->reqid, NULL, 0); + pfree(bp); +} + +static void +FsmRecvResetAck(struct fsm * fp, struct fsmheader * lhp, struct mbuf * bp) +{ + LogPrintf(fp->LogLevel, "RecvResetAck\n"); + Pred1Init(1); /* Initialize Input part */ + fp->reqid++; + pfree(bp); +} + +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; + 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/fsm.h b/usr.sbin/ppp/fsm.h new file mode 100644 index 00000000000..e2f95d44fde --- /dev/null +++ b/usr.sbin/ppp/fsm.h @@ -0,0 +1,132 @@ +/* + * 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: fsm.h,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ + +/* + * State of machine + */ +#define ST_INITIAL 0 +#define ST_STARTING 1 +#define ST_CLOSED 2 +#define ST_STOPPED 3 +#define ST_CLOSING 4 +#define ST_STOPPING 5 +#define ST_REQSENT 6 +#define ST_ACKRCVD 7 +#define ST_ACKSENT 8 +#define ST_OPENED 9 + +#define ST_MAX 10 +#define ST_UNDEF -1 + +#define MODE_REQ 0 +#define MODE_NAK 1 +#define MODE_REJ 2 +#define MODE_NOP 3 + +#define OPEN_ACTIVE 0 +#define OPEN_PASSIVE 1 + +struct fsm { + const char *name; /* Name of protocol */ + u_short proto; /* Protocol number */ + u_short max_code; + int open_mode; + int state; /* State of the machine */ + int reqid; /* Next request id */ + int restart; /* Restart counter value */ + int maxconfig; + + int reqcode; /* Request code sent */ + struct pppTimer FsmTimer; /* Restart Timer */ + + /* + * This timer times the ST_STOPPED state out after the given value + * (specified via "set stopped ..."). Although this isn't specified in the + * rfc, the rfc *does* say that "the application may use higher level + * timers to avoid deadlock". The StoppedTimer takes effect when the other + * side ABENDs rather than going into ST_ACKSENT (and sending the ACK), + * causing ppp to time out and drop into ST_STOPPED. At this point, + * nothing will change this state :-( + */ + 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); +}; + +struct fsmheader { + u_char code; /* Request code */ + u_char id; /* Identification */ + u_short length; /* Length of packet */ +}; + +#define CODE_CONFIGREQ 1 +#define CODE_CONFIGACK 2 +#define CODE_CONFIGNAK 3 +#define CODE_CONFIGREJ 4 +#define CODE_TERMREQ 5 +#define CODE_TERMACK 6 +#define CODE_CODEREJ 7 +#define CODE_PROTOREJ 8 +#define CODE_ECHOREQ 9 /* Used in LCP */ +#define CODE_ECHOREP 10 /* Used in LCP */ +#define CODE_DISCREQ 11 +#define CODE_IDENT 12 /* Used in LCP Extension */ +#define CODE_TIMEREM 13 /* Used in LCP Extension */ +#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; +}; + +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 *); diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c new file mode 100644 index 00000000000..1feff8d3d86 --- /dev/null +++ b/usr.sbin/ppp/hdlc.c @@ -0,0 +1,423 @@ +/* + * PPP High Level Link Control (HDLC) 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: hdlc.c,v 1.1 1997/11/23 20:27:33 brian Exp $ + * + * TODO: + */ +#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 "lcpproto.h" +#include "ipcp.h" +#include "ip.h" +#include "vjcomp.h" +#include "pap.h" +#include "chap.h" +#include "lcp.h" +#include "async.h" +#include "lqr.h" +#include "loadalias.h" +#include "vars.h" +#include "pred.h" +#include "modem.h" +#include "ccp.h" + +struct hdlcstat { + int badfcs; + int badaddr; + int badcommand; + int unknownproto; +} HdlcStat; + +static int ifOutPackets; +static int ifOutOctets; +static int ifOutLQRs; +static int ifInPackets; +static int ifInOctets; + +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] = { + /* 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, + /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +u_char EscMap[33]; + +void +HdlcInit() +{ + ifInOctets = ifOutOctets = 0; + ifInPackets = ifOutPackets = 0; + ifOutLQRs = 0; +} + +/* + * HDLC FCS computation. Read RFC 1171 Appendix B and CCITT X.25 section + * 2.27 for further details. + */ +inline u_short +HdlcFcs(u_short fcs, u_char * cp, int len) +{ + while (len--) + fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; + return (fcs); +} + +void +HdlcOutput(int pri, u_short proto, struct mbuf * bp) +{ + 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 (CcpInfo.want_proto == TY_PRED1) { + Pred1Output(pri, proto, bp); + return; + } + } + } + if (DEV_IS_SYNC) + mfcs = NULLBUFF; + else + mfcs = mballoc(2, MB_HDLCOUT); + mhp = mballoc(4, MB_HDLCOUT); + mhp->cnt = 0; + cp = MBUF_CTOP(mhp); + if (proto == PROTO_LCP || LcpInfo.his_acfcomp == 0) { + *cp++ = HDLC_ADDR; + *cp++ = HDLC_UI; + mhp->cnt += 2; + } + + /* + * If possible, compress protocol field. + */ + if (LcpInfo.his_protocomp && (proto & 0xff00) == 0) { + *cp++ = proto; + mhp->cnt++; + } else { + *cp++ = proto >> 8; + *cp = proto & 0377; + mhp->cnt += 2; + } + mhp->next = bp; + bp->next = mfcs; + + lqr = &MyLqrData; + lqr->PeerOutPackets = ifOutPackets++; + ifOutOctets += plength(mhp) + 1; + lqr->PeerOutOctets = ifOutOctets; + + 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; + lqr->PeerOutLQRs = ++ifOutLQRs; + LqrDump("LqrOutput", lqr); + LqrChangeOrder(lqr, (struct lqrdata *) (MBUF_CTOP(bp))); + } + if (!DEV_IS_SYNC) { + fcs = HdlcFcs(INITFCS, MBUF_CTOP(mhp), mhp->cnt); + fcs = HdlcFcs(fcs, MBUF_CTOP(bp), bp->cnt); + fcs = ~fcs; + cp = MBUF_CTOP(mfcs); + *cp++ = fcs & 0377; /* Low byte first!! */ + *cp++ = fcs >> 8; + } + LogDumpBp(LogHDLC, "HdlcOutput", mhp); + for (statp = ProtocolStat; statp->number; statp++) + if (statp->number == proto) + break; + statp->out_count++; + if (DEV_IS_SYNC) + ModemOutput(pri, mhp); + else + AsyncOutput(pri, mhp, proto); +} + +void +DecodePacket(u_short proto, struct mbuf * bp) +{ + u_char *cp; + + LogPrintf(LogDEBUG, "DecodePacket: proto = %04x\n", proto); + + switch (proto) { + case PROTO_LCP: + LcpInput(bp); + break; + case PROTO_PAP: + PapInput(bp); + break; + case PROTO_LQR: + HisLqrSave.SaveInLQRs++; + LqrInput(bp); + break; + case PROTO_CHAP: + ChapInput(bp); + break; + case PROTO_VJUNCOMP: + case PROTO_VJCOMP: + bp = VjCompInput(bp, proto); + if (bp == NULLBUFF) { + break; + } + /* fall down */ + case PROTO_IP: + IpInput(bp); + break; + case PROTO_IPCP: + IpcpInput(bp); + break; + case PROTO_CCP: + CcpInput(bp); + break; + case PROTO_COMPD: + Pred1Input(bp); + break; + default: + LogPrintf(LogPHASE, "Unknown protocol 0x%04x\n", 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; + } + } while (statp->number); + if (cnt) + fprintf(VarTerm, "\n"); + return (1); +} + +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); + } + return 0; +} + +static struct hdlcstat laststat; + +void +HdlcErrorCheck() +{ + 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); + } + laststat = HdlcStat; +} + +void +HdlcInput(struct mbuf * bp) +{ + u_short fcs, proto; + u_char *cp, addr, ctrl; + struct protostat *statp; + + LogDumpBp(LogHDLC, "HdlcInput:", bp); + if (DEV_IS_SYNC) + fcs = GOODFCS; + else + fcs = HdlcFcs(INITFCS, MBUF_CTOP(bp), bp->cnt); + HisLqrSave.SaveInOctets += bp->cnt + 1; + + LogPrintf(LogDEBUG, "HdlcInput: fcs = %04x (%s)\n", + fcs, (fcs == GOODFCS) ? "good" : "bad"); + if (fcs != GOODFCS) { + HisLqrSave.SaveInErrors++; + LogPrintf(LogDEBUG, "HdlcInput: Bad FCS\n"); + HdlcStat.badfcs++; + pfree(bp); + return; + } + if (!DEV_IS_SYNC) + bp->cnt -= 2; /* discard FCS part */ + + if (bp->cnt < 2) { /* XXX: raise this bar ? */ + pfree(bp); + return; + } + cp = MBUF_CTOP(bp); + + ifInPackets++; + ifInOctets += bp->cnt; + + if (!LcpInfo.want_acfcomp) { + + /* + * We expect that packet is not compressed. + */ + addr = *cp++; + if (addr != HDLC_ADDR) { + HisLqrSave.SaveInErrors++; + HdlcStat.badaddr++; + LogPrintf(LogDEBUG, "HdlcInput: addr %02x\n", *cp); + pfree(bp); + return; + } + ctrl = *cp++; + if (ctrl != HDLC_UI) { + HisLqrSave.SaveInErrors++; + HdlcStat.badcommand++; + LogPrintf(LogDEBUG, "HdlcInput: %02x\n", *cp); + pfree(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. + */ + 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) + break; + statp->in_count++; + HisLqrSave.SaveInPackets++; + + DecodePacket(proto, bp); +} diff --git a/usr.sbin/ppp/hdlc.h b/usr.sbin/ppp/hdlc.h new file mode 100644 index 00000000000..7e2f900883e --- /dev/null +++ b/usr.sbin/ppp/hdlc.h @@ -0,0 +1,67 @@ +/* + * 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 1997/11/23 20:27:33 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 void DecodePacket(u_short, struct mbuf *); +extern int ReportHdlcStatus(struct cmdargs const *); +extern int ReportProtStatus(struct cmdargs const *); diff --git a/usr.sbin/ppp/id.c b/usr.sbin/ppp/id.c new file mode 100644 index 00000000000..e9ce99a602f --- /dev/null +++ b/usr.sbin/ppp/id.c @@ -0,0 +1,146 @@ +/* + * $Id: id.c,v 1.1 1997/11/23 20:27:34 brian Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <sys/ioctl.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "main.h" +#ifdef __OpenBSD__ +#include <util.h> +#else +#include <libutil.h> +#endif +#include "id.h" + +static int uid; +static int gid; +static int euid; +static int egid; + +void +ID0init() +{ + uid = getuid(); + gid = getgid(); + euid = geteuid(); + egid = getegid(); +} + +static void +ID0setuser(void) +{ + if (seteuid(uid) == -1) { + LogPrintf(LogERROR, "ID0setuser: Unable to seteuid!\n"); + Cleanup(EX_NOPERM); + } +} + +uid_t +ID0realuid() +{ + return uid; +} + +static void +ID0set0(void) +{ + if (seteuid(euid) == -1) { + LogPrintf(LogERROR, "ID0set0: Unable to seteuid!\n"); + Cleanup(EX_NOPERM); + } +} + +int +ID0ioctl(int fd, unsigned long req, void *arg) +{ + int ret; + + ID0set0(); + ret = ioctl(fd, req, arg); + LogPrintf(LogID0, "%d = ioctl(%d, %d, %p)\n", ret, fd, req, arg); + ID0setuser(); + return ret; +} + +int +ID0unlink(const char *name) +{ + int ret; + + ID0set0(); + ret = unlink(name); + LogPrintf(LogID0, "%d = unlink(\"%s\")\n", ret, name); + ID0setuser(); + return ret; +} + +int +ID0socket(int domain, int type, int protocol) +{ + int ret; + + ID0set0(); + ret = socket(domain, type, protocol); + LogPrintf(LogID0, "%d = socket(%d, %d, %d)\n", ret, domain, type, protocol); + ID0setuser(); + return ret; +} + +FILE * +ID0fopen(const char *path, const char *mode) +{ + FILE *ret; + + ID0set0(); + ret = fopen(path, mode); + LogPrintf(LogID0, "%p = fopen(\"%s\", \"%s\")\n", ret, path, mode); + ID0setuser(); + return ret; +} + +int +ID0open(const char *path, int flags) +{ + int ret; + + ID0set0(); + ret = open(path, flags); + LogPrintf(LogID0, "%d = open(\"%s\", %d)\n", ret, path, flags); + ID0setuser(); + return ret; +} + +int +ID0uu_lock(const char *basettyname) +{ + int ret; + + ID0set0(); + ret = uu_lock(basettyname); + LogPrintf(LogID0, "%d = uu_lock(\"%s\")\n", ret, basettyname); + ID0setuser(); + return ret; +} + +int +ID0uu_unlock(const char *basettyname) +{ + int ret; + + ID0set0(); + ret = uu_unlock(basettyname); + LogPrintf(LogID0, "%d = uu_unlock(\"%s\")\n", ret, basettyname); + ID0setuser(); + return ret; +} diff --git a/usr.sbin/ppp/id.h b/usr.sbin/ppp/id.h new file mode 100644 index 00000000000..45049873e4d --- /dev/null +++ b/usr.sbin/ppp/id.h @@ -0,0 +1,13 @@ +/* + * $Id: id.h,v 1.1 1997/11/23 20:27:34 brian Exp $ + */ + +extern void ID0init(void); +extern uid_t ID0realuid(void); +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 ID0uu_lock(const char *); +extern int ID0uu_unlock(const char *); diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ip.c new file mode 100644 index 00000000000..4120503042e --- /dev/null +++ b/usr.sbin/ppp/ip.c @@ -0,0 +1,522 @@ +/* + * PPP IP Protocol 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: ip.c,v 1.1 1997/11/23 20:27:34 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/select.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/if_tun.h> + +#ifndef NOALIAS +#include <alias.h> +#endif +#include <errno.h> +#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 "lcpproto.h" +#include "hdlc.h" +#include "loadalias.h" +#include "vars.h" +#include "filter.h" +#include "os.h" +#include "ipcp.h" +#include "vjcomp.h" +#include "lcp.h" +#include "modem.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() +{ + if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { + StopTimer(&IdleTimer); + IdleTimer.func = IdleTimeout; + IdleTimer.load = VarIdleTimeout * SECTICKS; + IdleTimer.state = TIMER_STOPPED; + StartTimer(&IdleTimer); + } +} + +void +UpdateIdleTimer() +{ + if (OsLinkIsUp()) + StartIdleTimer(); +} + +void +StopIdleTimer() +{ + StopTimer(&IdleTimer); +} + +/* + * If any IP layer traffic is detected, refresh IdleTimer. + */ +static void +RestartIdleTimer(void) +{ + if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { + StartTimer(&IdleTimer); + ipIdleSecs = 0; + } +} + +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, +}; + +#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) + +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) +{ + switch (op) { + case OP_EQ: + return (pport == rport); + case OP_GT: + return (pport > rport); + case OP_LT: + return (pport < rport); + default: + return (0); + } +} + +/* + * Check a packet against with defined filters + */ +static int +FilterCheck(struct ip * pip, int direction) +{ + struct filterent *fp = Filters[direction]; + int gotinfo, cproto, estab, n; + struct tcphdr *th; + struct udphdr *uh; + struct icmp *ih; + char *ptop; + u_short sport, dport; + + if (fp->action) { + cproto = gotinfo = estab = 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) { + return (A_PERMIT); + } + LogPrintf(LogDEBUG, "rule = %d\n", n); + 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) == + (fp->daddr.s_addr & fp->dmask.s_addr)) { + if (fp->proto) { + if (!gotinfo) { + ptop = (char *) pip + (pip->ip_hl << 2); + + switch (pip->ip_p) { + case IPPROTO_ICMP: + cproto = P_ICMP; + ih = (struct icmp *) ptop; + sport = ih->icmp_type; + estab = 1; + break; + case IPPROTO_UDP: + cproto = P_UDP; + uh = (struct udphdr *) ptop; + sport = ntohs(uh->uh_sport); + dport = ntohs(uh->uh_dport); + estab = 1; + break; + case IPPROTO_TCP: + cproto = P_TCP; + th = (struct tcphdr *) ptop; + 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); + break; + default: + return (A_DENY);/* We'll block unknown type of packet */ + } + 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 (cproto == fp->proto) { + if ((fp->opt.srcop == OP_NONE || + 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)) { + return (fp->action); + } + } + } else { + /* Address is mached. Make a decision. */ + LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); + return (fp->action); + } + } + } + fp++; + } + return (A_DENY); /* No rule is mached. Deny this packet */ + } + return (A_PERMIT); /* No rule is given. Permit this packet */ +} + +static void +IcmpError(struct ip * pip, int code) +{ +#ifdef notdef + struct mbuf *bp; + + if (pip->ip_p != IPPROTO_ICMP) { + bp = mballoc(cnt, MB_IPIN); + memcpy(MBUF_CTOP(bp), ptr, cnt); + SendPppFrame(bp); + RestartIdleTimer(); + IpcpAddOutOctets(cnt); + } +#endif +} + +/* + * For debugging aid. + */ +int +PacketCheck(char *cp, int nb, int direction) +{ + struct ip *pip; + struct tcphdr *th; + struct udphdr *uh; + struct icmp *icmph; + char *ptop; + int mask, len, n; + int pri = PRI_NORMAL; + int logit, loglen; + static char logbuf[200]; + + logit = LogIsKept(LogTCPIP); + loglen = 0; + + pip = (struct ip *) cp; + + if (logit && loglen < sizeof logbuf) { + snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", + Direction[direction]); + loglen += strlen(logbuf + loglen); + } + ptop = (cp + (pip->ip_hl << 2)); + + switch (pip->ip_p) { + case IPPROTO_ICMP: + if (logit && loglen < sizeof logbuf) { + icmph = (struct icmp *) ptop; + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); + loglen += strlen(logbuf + loglen); + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); + loglen += strlen(logbuf + loglen); + } + break; + case IPPROTO_UDP: + if (logit && loglen < sizeof logbuf) { + uh = (struct udphdr *) ptop; + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "UDP: %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) + pri = PRI_FAST; + else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { + if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) + pri = PRI_FAST; + } + if (logit && loglen < sizeof logbuf) { + len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); + loglen += strlen(logbuf + loglen); + snprintf(logbuf + loglen, sizeof logbuf - loglen, + "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); + loglen += strlen(logbuf + loglen); + n = 0; + for (mask = TH_FIN; mask != 0x40; mask <<= 1) { + if (th->th_flags & mask) { + snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); + loglen += strlen(logbuf + loglen); + } + n++; + } + snprintf(logbuf + loglen, sizeof logbuf - loglen, + " seq:%x ack:%x (%d/%d)", + ntohl(th->th_seq), ntohl(th->th_ack), len, nb); + loglen += strlen(logbuf + loglen); + if ((th->th_flags & TH_SYN) && nb > 40) { + u_short *sp; + + ptop += 20; + sp = (u_short *) ptop; + if (ntohs(sp[0]) == 0x0204) { + snprintf(logbuf + loglen, sizeof logbuf - loglen, + " MSS = %d", ntohs(sp[1])); + loglen += strlen(logbuf + loglen); + } + } + } + break; + } + + if ((FilterCheck(pip, direction) & A_DENY)) { + if (logit) + LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); + if (direction == 0) + IcmpError(pip, pri); + 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; + } + return (pri); + } +} + +void +IpInput(struct mbuf * bp) +{ /* IN: Pointer to IP pakcet */ + u_char *cp; + struct mbuf *wp; + int nb, nw; + struct tun_data tun; + + tun_fill_header(tun, AF_INET); + cp = tun.data; + nb = 0; + for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ + memcpy(cp, MBUF_CTOP(wp), wp->cnt); + cp += wp->cnt; + nb += wp->cnt; + } + +#ifndef NOALIAS + if (mode & MODE_ALIAS) { + struct tun_data *frag; + int iresult; + char *fptr; + + iresult = VarPacketAliasIn(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); + return; + } + if (iresult == PKT_ALIAS_OK + || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { + if (PacketCheck(tun.data, nb, FL_IN) < 0) { + pfree(bp); + return; + } + IpcpAddInOctets(nb); + + nb = ntohs(((struct ip *) tun.data)->ip_len); + nb += sizeof(tun)-sizeof(tun.data); + nw = write(tun_out, &tun, nb); + if (nw != nb) + if (nw == -1) + LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, + strerror(errno)); + else + LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + + if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { + while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { + VarPacketAliasFragmentIn(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); + if (nw != nb) + if (nw == -1) + LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, + strerror(errno)); + else + LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + free(frag); + } + } + } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { + nb = ntohs(((struct ip *) tun.data)->ip_len); + nb += sizeof(tun)-sizeof(tun.data); + frag = (struct tun_data *)malloc(nb); + if (frag == NULL) + LogPrintf(LogALERT, "IpInput: 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); + } + } + } else +#endif /* #ifndef NOALIAS */ + { /* no aliasing */ + if (PacketCheck(tun.data, nb, FL_IN) < 0) { + pfree(bp); + return; + } + IpcpAddInOctets(nb); + nb += sizeof(tun)-sizeof(tun.data); + nw = write(tun_out, &tun, nb); + if (nw != nb) + if (nw == -1) + LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); + else + LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); + } + pfree(bp); + + RestartIdleTimer(); +} + +static struct mqueue IpOutputQueues[PRI_FAST + 1]; + +void +IpEnqueue(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 0 +int +IsIpEnqueued() +{ + struct mqueue *queue; + int exist = 0; + + for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { + if (queue->qlen > 0) { + exist = 1; + break; + } + } + return (exist); +} +#endif + +void +IpStartOutput() +{ + struct mqueue *queue; + struct mbuf *bp; + int cnt; + + if (IpcpFsm.state != ST_OPENED) + return; + for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { + if (queue->top) { + bp = Dequeue(queue); + if (bp) { + cnt = plength(bp); + SendPppFrame(bp); + RestartIdleTimer(); + IpcpAddOutOctets(cnt); + break; + } + } + } +} diff --git a/usr.sbin/ppp/ip.h b/usr.sbin/ppp/ip.h new file mode 100644 index 00000000000..cf8d012dd5f --- /dev/null +++ b/usr.sbin/ppp/ip.h @@ -0,0 +1,30 @@ +/* + * 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: ip.h,v 1.1 1997/11/23 20:27:34 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); diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c new file mode 100644 index 00000000000..0bc970f71d3 --- /dev/null +++ b/usr.sbin/ppp/ipcp.c @@ -0,0 +1,601 @@ +/* + * 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 1997/11/23 20:27:34 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 <limits.h> +#include <stdio.h> +#include <string.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 "lcpproto.h" +#include "lcp.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" + +#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 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 *); + +#define REJECTED(p, x) (p->his_reject & (1<<x)) + +struct fsm IpcpFsm = { + "IPCP", + PROTO_IPCP, + IPCP_MAXCODE, + OPEN_ACTIVE, + ST_INITIAL, + 0, 0, 0, + + 0, + {0, 0, 0, NULL, NULL, NULL}, + {0, 0, 0, NULL, NULL, NULL}, + 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(char *)) + +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(cftypes)/sizeof(char *)) + +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 ipcpstate *icp = &IpcpInfo; + struct fsm *fp = &IpcpFsm; + + if (!VarTerm) + return 1; + fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); + fprintf(VarTerm, " his side: %s, %lx\n", + inet_ntoa(icp->his_ipaddr), icp->his_compproto); + fprintf(VarTerm, " my side: %s, %lx\n", + inet_ntoa(icp->want_ipaddr), icp->want_compproto); + + fprintf(VarTerm, "Defaults:\n"); + fprintf(VarTerm, " My Address: %s/%d\n", + inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); + 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); + } + } +} + +void +IpcpInit() +{ + struct ipcpstate *icp = &IpcpInfo; + + FsmInit(&IpcpFsm); + memset(icp, '\0', sizeof(struct ipcpstate)); + if ((mode & MODE_DEDICATED) && !GetLabel()) { + icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; + } else { + icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; + icp->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) { + icp->want_ipaddr.s_addr = TriggerAddress.s_addr; + LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress)); + } + if (Enabled(ConfVjcomp)) + icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8) | 1; + else + icp->want_compproto = 0; + icp->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 ipcpstate *icp = &IpcpInfo; + + cp = ReqBuff; + LogPrintf(LogIPCP, "IpcpSendConfigReq\n"); + if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) + PutConfValue(LogIPCP, &cp, cftypes, TY_IPADDR, 6, + ntohl(icp->want_ipaddr.s_addr)); + if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { + if (icp->heis1172) + PutConfValue(LogIPCP, &cp, cftypes, TY_COMPPROTO, 4, + icp->want_compproto >> 16); + else + PutConfValue(LogIPCP, &cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); + } + 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, ifnetmask) < 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_long *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], length); + else + snprintf(tbuff, sizeof(tbuff), " ??? "); + + switch (type) { + case TY_IPADDR: /* RFC1332 */ + lp = (u_long *) (cp + 2); + ipaddr.s_addr = *lp; + LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + + switch (mode_type) { + case MODE_REQ: + 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); + 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; + } + break; + case MODE_REJ: + IpcpInfo.his_reject |= (1 << type); + break; + } + break; + case TY_COMPPROTO: + lp = (u_long *) (cp + 2); + compproto = htonl(*lp); + LogPrintf(LogIPCP, "%s %08x\n", tbuff, 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_long *) (cp + 2); + ipaddr.s_addr = *lp; + lp = (u_long *) (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_long *) (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_long *) (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); +} diff --git a/usr.sbin/ppp/ipcp.h b/usr.sbin/ppp/ipcp.h new file mode 100644 index 00000000000..50b0f8ba195 --- /dev/null +++ b/usr.sbin/ppp/ipcp.h @@ -0,0 +1,79 @@ +/* + * 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 1997/11/23 20:27:34 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_long his_compproto; + + struct in_addr want_ipaddr; /* IP address I'm willing to use */ + u_long want_compproto; + + u_long his_reject; /* Request codes rejected by peer */ + u_long 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 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); diff --git a/usr.sbin/ppp/lcp.c b/usr.sbin/ppp/lcp.c new file mode 100644 index 00000000000..df6880b6f2d --- /dev/null +++ b/usr.sbin/ppp/lcp.c @@ -0,0 +1,716 @@ +/* + * 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 1997/11/23 20:27:34 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/select.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/if_tun.h> + +#include <signal.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" + +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 *); + +#define REJECTED(p, x) (p->his_reject & (1<<x)) + +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(char *)) + +struct fsm LcpFsm = { + "LCP", /* Name of protocol */ + PROTO_LCP, /* Protocol Number */ + LCP_MAXCODE, + OPEN_ACTIVE, + ST_INITIAL, /* State of machine */ + 0, 0, 0, + 0, + {0, 0, 0, NULL, NULL, NULL}, + {0, 0, 0, NULL, NULL, NULL}, + 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 %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n" + " REJECT %04lx\n", + lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp, + lcp->his_magic, lcp->his_reject); + fprintf(VarTerm, + " my side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n" + " REJECT %04lx\n", + lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp, + lcp->want_magic, lcp->my_reject); + fprintf(VarTerm, "\nDefaults: MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap); + fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE) ? "active" : "passive"); + return 0; +} + +/* + * Generate random number which will be used as magic number. + */ +static u_long +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; +} + +void +PutConfValue(int level, u_char ** cpp, const char **types, u_char type, + int len, u_long val) +{ + u_char *cp; + struct in_addr ina; + + cp = *cpp; + *cp++ = type; + *cp++ = len; + if (len == 6) { + if (type == TY_IPADDR) { + ina.s_addr = htonl(val); + LogPrintf(level, " %s [%d] %s\n", + types[type], len, inet_ntoa(ina)); + } else + LogPrintf(level, " %s [%d] %08x\n", types[type], len, val); + *cp++ = (val >> 24) & 0377; + *cp++ = (val >> 16) & 0377; + } else + LogPrintf(level, " %s [%d] %d\n", types[type], len, val); + *cp++ = (val >> 8) & 0377; + *cp++ = val & 0377; + *cpp = cp; +} + +static void +LcpSendConfigReq(struct fsm * fp) +{ + u_char *cp; + struct lcpstate *lcp = &LcpInfo; + struct lqrreq *req; + + LogPrintf(LogLCP, "LcpSendConfigReq\n"); + cp = ReqBuff; + if (!DEV_IS_SYNC) { + if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) { + *cp++ = TY_ACFCOMP; + *cp++ = 2; + LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]); + } + if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) { + *cp++ = TY_PROTOCOMP; + *cp++ = 2; + LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]); + } + if (!REJECTED(lcp, TY_ACCMAP)) + PutConfValue(LogLCP, &cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap); + } + if (!REJECTED(lcp, TY_MRU)) + PutConfValue(LogLCP, &cp, cftypes, TY_MRU, 4, lcp->want_mru); + if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) + PutConfValue(LogLCP, &cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic); + if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { + req = (struct lqrreq *) cp; + req->type = TY_QUALPROTO; + req->length = sizeof(struct lqrreq); + req->proto = htons(PROTO_LQR); + req->period = htonl(lcp->want_lqrperiod); + cp += sizeof(struct lqrreq); + LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod); + } + switch (lcp->want_auth) { + case PROTO_PAP: + PutConfValue(LogLCP, &cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth); + break; + case PROTO_CHAP: + PutConfValue(LogLCP, &cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth); +#ifdef HAVE_DES + *cp++ = VarMSChap ? 0x80 : 0x05; /* Use MSChap vs. RFC 1994 (MD5) */ +#else + *cp++ = 0x05; /* Use MD5 */ +#endif + 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) +{ + const char *request; + int type, length, mru, mtu; + u_long *lp, magic, accmap; + u_short *sp, proto; + struct lqrreq *req; + + ackp = AckBuff; + nakp = NakBuff; + rejp = RejBuff; + + while (plen >= sizeof(struct fsmconfig)) { + type = *cp; + length = cp[1]; + if (type < NCFTYPES) + request = cftypes[type]; + else + request = "???"; + + 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_long *) (cp + 2); + accmap = htonl(*lp); + LogPrintf(LogLCP, " %s %08x\n", request, 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); + LogPrintf(LogLCP, " %s proto = %04x\n", request, proto); + + switch (mode_type) { + case MODE_REQ: + switch (proto) { + case PROTO_PAP: + if (length != 4) { + LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); + 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; + *nakp++ = 5; + } else + goto reqreject; + break; + case PROTO_CHAP: + if (length < 5) { + LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); + 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 not implemented, NAK.\n", request); + memcpy(nakp, cp, length); + nakp += length; + break; + } + break; + case MODE_NAK: + 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_long *) (cp + 2); + magic = ntohl(*lp); + LogPrintf(LogLCP, " %s %08x\n", request, magic); + + switch (mode_type) { + case MODE_REQ: + if (LcpInfo.want_magic) { + /* Validate magic number */ + if (magic == LcpInfo.want_magic) { + LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n", + 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, " %s magic %08x has NAKed\n", request, magic); + LcpInfo.want_magic = GenerateMagic(); + break; + case MODE_REJ: + LogPrintf(LogLCP, " %s magic has REJected\n", request); + 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: + LogPrintf(LogLCP, " %s[02x]\n", request, type); + if (mode_type == MODE_REQ) { + reqreject: + memcpy(rejp, cp, length); + rejp += length; + LcpInfo.my_reject |= (1 << type); + } + 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 new file mode 100644 index 00000000000..a624cae9698 --- /dev/null +++ b/usr.sbin/ppp/lcp.h @@ -0,0 +1,78 @@ +/* + * 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 1997/11/23 20:27:34 brian Exp $ + * + * TODO: + */ + +struct lcpstate { + u_long his_mru; + u_long his_accmap; + u_long his_magic; + u_long his_lqrperiod; + u_char his_protocomp; + u_char his_acfcomp; + u_short his_auth; + + u_long want_mru; + u_long want_accmap; + u_long want_magic; + u_long want_lqrperiod; + u_char want_protocomp; + u_char want_acfcomp; + u_short want_auth; + + u_long his_reject; /* Request codes rejected by peer */ + u_long 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 */ + +struct lqrreq { + u_char type; + u_char length; + u_short proto; /* Quality protocol */ + u_long period; /* Reporting interval */ +}; + +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 void PutConfValue(int, u_char **, const char **, u_char, int, u_long); +extern int ReportLcpStatus(struct cmdargs const *); +extern void LcpInput(struct mbuf *); diff --git a/usr.sbin/ppp/lcpproto.h b/usr.sbin/ppp/lcpproto.h new file mode 100644 index 00000000000..dadb2311e2b --- /dev/null +++ b/usr.sbin/ppp/lcpproto.h @@ -0,0 +1,39 @@ +/* + * 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: lcpproto.h,v 1.1 1997/11/23 20:27:34 brian Exp $ + * + * TODO: + */ + +/* + * Definition of protocol numbers + */ +#define PROTO_IP 0x0021 /* IP */ +#define PROTO_VJUNCOMP 0x002f /* VJ Uncompressed */ +#define PROTO_VJCOMP 0x002d /* VJ Compressed */ +#define PROTO_ICOMPD 0x00fb /* Individual link compressed */ +#define PROTO_COMPD 0x00fd /* Compressed datagram */ + +#define PROTO_IPCP 0x8021 +#define PROTO_ICCP 0x80fb +#define PROTO_CCP 0x80fd + +#define PROTO_LCP 0xc021 +#define PROTO_PAP 0xc023 +#define PROTO_LQR 0xc025 +#define PROTO_CHAP 0xc223 diff --git a/usr.sbin/ppp/loadalias.c b/usr.sbin/ppp/loadalias.c new file mode 100644 index 00000000000..3e4cf3bc4ed --- /dev/null +++ b/usr.sbin/ppp/loadalias.c @@ -0,0 +1,92 @@ +/* + * $Id: loadalias.c,v 1.1 1997/11/23 20:27:34 brian Exp $ + */ + +#include <sys/param.h> +#include <netinet/in.h> + +#include <alias.h> +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "systems.h" +#include "id.h" +#include "loadalias.h" +#include "defs.h" +#include "vars.h" + +#define _PATH_ALIAS "/usr/lib/libalias.so." ## __libalias_version + +#define off(item) ((int)&(((struct aliasHandlers *)0)->item)) +#define entry(a) { off(a), "_" #a } + +static struct { + int offset; + const char *name; +} map[] = { + entry(PacketAliasGetFragment), + entry(PacketAliasInit), + entry(PacketAliasIn), + entry(PacketAliasOut), + entry(PacketAliasRedirectAddr), + entry(PacketAliasRedirectPort), + entry(PacketAliasSaveFragment), + entry(PacketAliasSetAddress), + entry(PacketAliasSetMode), + entry(PacketAliasFragmentIn), + { 0, 0 } +}; + +static void *dl; + +int +loadAliasHandlers(struct aliasHandlers * h) +{ + const char *path; + const char *env; + int i; + + path = _PATH_ALIAS; + env = getenv("_PATH_ALIAS"); + if (env) + if (ID0realuid() == 0) + path = env; + else + LogPrintf(LogALERT, "Ignoring environment _PATH_ALIAS value (%s)\n", env); + + dl = dlopen(path, RTLD_LAZY); + if (dl == (void *) 0) { + LogPrintf(LogWARN, "_PATH_ALIAS (%s): Invalid lib: %s\n", + path, dlerror()); + return -1; + } + for (i = 0; map[i].name; i++) { + *(void **) ((char *) h + map[i].offset) = dlsym(dl, map[i].name); + if (*(void **) ((char *) h + map[i].offset) == (void *) 0) { + LogPrintf(LogWARN, "_PATH_ALIAS (%s): %s: %s\n", path, + map[i].name, dlerror()); + (void) dlclose(dl); + dl = (void *) 0; + return -1; + } + } + + VarPacketAliasInit(); + + return 0; +} + +void +unloadAliasHandlers() +{ + if (dl) { + dlclose(dl); + dl = (void *) 0; + } +} diff --git a/usr.sbin/ppp/loadalias.h b/usr.sbin/ppp/loadalias.h new file mode 100644 index 00000000000..a4cc571e24d --- /dev/null +++ b/usr.sbin/ppp/loadalias.h @@ -0,0 +1,21 @@ +/* + * $Id: loadalias.h,v 1.1 1997/11/23 20:27:34 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 *); +}; + +extern int loadAliasHandlers(struct aliasHandlers *); +extern void unloadAliasHandlers(void); diff --git a/usr.sbin/ppp/log.c b/usr.sbin/ppp/log.c new file mode 100644 index 00000000000..b6a52c61d5b --- /dev/null +++ b/usr.sbin/ppp/log.c @@ -0,0 +1,222 @@ +/* + * $Id: log.c,v 1.1 1997/11/23 20:27:34 brian Exp $ + */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include <stdarg.h> +#include <stdio.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/log.h b/usr.sbin/ppp/log.h new file mode 100644 index 00000000000..d37ef9e7cab --- /dev/null +++ b/usr.sbin/ppp/log.h @@ -0,0 +1,44 @@ +/* + * $Id: log.h,v 1.1 1997/11/23 20:27:34 brian Exp $ + */ + +#define LogMIN (1) +#define LogASYNC (1) /* syslog(LOG_INFO, ....) */ +#define LogCARRIER (2) +#define LogCCP (3) +#define LogCHAT (4) +#define LogCOMMAND (5) +#define LogCONNECT (6) +#define LogDEBUG (7) /* syslog(LOG_DEBUG, ....) */ +#define LogHDLC (8) +#define LogID0 (9) +#define LogIPCP (10) +#define LogLCP (11) +#define LogLINK (12) +#define LogLQM (13) +#define LogPHASE (14) +#define LogTCPIP (15) +#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, ) */ +#define LogERROR (18) /* syslog(LOG_ERR, ....), + sent to VarTerm */ +#define LogALERT (19) /* syslog(LOG_ALERT, ....) */ +#define LogMAX (19) + +/* 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); diff --git a/usr.sbin/ppp/lqr.c b/usr.sbin/ppp/lqr.c new file mode 100644 index 00000000000..df3bea3d898 --- /dev/null +++ b/usr.sbin/ppp/lqr.c @@ -0,0 +1,270 @@ +/* + * 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 1997/11/23 20:27:34 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 "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" +#include "main.h" + +struct pppTimer LqrTimer; + +static u_long lastpeerin = (u_long) - 1; + +static int lqmmethod; +static int echoseq; +static int gotseq; +static int lqrsendcnt; + +struct echolqr { + u_long magic; + u_long signature; + u_long 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_long 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)); + gotseq = seq; + } + } +} + +void +LqrChangeOrder(struct lqrdata * src, struct lqrdata * dst) +{ + u_long *sp, *dp; + int n; + + sp = (u_long *) src; + dp = (u_long *) dst; + for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_long); 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, "** 1 Too many ECHO packets are lost. **\n"); + lqmmethod = 0; /* Prevent rcursion 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 - gotseq > 5) { + LogPrintf(LogPHASE, "** 2 Too many ECHO packets are lost. **\n"); + lqmmethod = 0; /* Prevent rcursion via LcpClose() */ + reconnect(RECON_TRUE); + LcpClose(); + } else + SendEchoReq(); + } + if (lqmmethod && Enabled(ConfLqr)) + 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 LQR responce to peer, if i) We are not running LQR timer. ii) + * Two successive LQR's PeerInLQRs are same. + */ + if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) { + lqmmethod |= LQM_LQR; + SendLqrReport(0); + } + lastpeerin = HisLqrData.PeerInLQRs; + } + pfree(bp); +} + +/* + * When LCP is reached to opened state, We'll start LQM activity. + */ +void +StartLqm() +{ + struct lcpstate *lcp = &LcpInfo; + int period; + + lqrsendcnt = 0; /* start waiting all over for ECHOs */ + echoseq = 0; + gotseq = 0; + + lqmmethod = LQM_ECHO; + if (Enabled(ConfLqr)) + lqmmethod |= LQM_LQR; + StopTimer(&LqrTimer); + LogPrintf(LogLQM, "LQM method = %d\n", lqmmethod); + + if (lcp->his_lqrperiod || lcp->want_lqrperiod) { + + /* + * We need to run timer. Let's figure out period. + */ + period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod; + StopTimer(&LqrTimer); + LqrTimer.state = TIMER_STOPPED; + LqrTimer.load = period * SECTICKS / 100; + LqrTimer.func = SendLqrReport; + SendLqrReport(0); + StartTimer(&LqrTimer); + LogPrintf(LogLQM, "Will send LQR every %d.%d secs\n", + period / 100, period % 100); + } else { + LogPrintf(LogLQM, "LQR is not activated.\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(0); + 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 new file mode 100644 index 00000000000..ee378abc154 --- /dev/null +++ b/usr.sbin/ppp/lqr.h @@ -0,0 +1,64 @@ +/* + * 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 1997/11/23 20:27:34 brian Exp $ + * + * TODO: + */ + +/* + * Structure of LQR packet defined in RFC1333 + */ +struct lqrdata { + u_long MagicNumber; + u_long LastOutLQRs; + u_long LastOutPackets; + u_long LastOutOctets; + u_long PeerInLQRs; + u_long PeerInPackets; + u_long PeerInDiscards; + u_long PeerInErrors; + u_long PeerInOctets; + u_long PeerOutLQRs; + u_long PeerOutPackets; + u_long PeerOutOctets; +}; + +struct lqrsave { + u_long SaveInLQRs; + u_long SaveInPackets; + u_long SaveInDiscards; + u_long SaveInErrors; + u_long SaveInOctets; +}; + +struct lqrdata MyLqrData, HisLqrData; +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 new file mode 100644 index 00000000000..daa6565fb1b --- /dev/null +++ b/usr.sbin/ppp/main.c @@ -0,0 +1,1091 @@ +/* + * 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 1997/11/23 20:27:34 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 <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/if_tun.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 <sysexits.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 "ccp.h" +#include "lcp.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 "lcpproto.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(0, F_GETFL, 0); + if (stat > 0) { + stat |= O_NONBLOCK; + (void) fcntl(0, 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(0, TCSADRAIN, &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(0, &newtio); + newtio.c_lflag |= (ECHO | ISIG | ICANON); + newtio.c_iflag = oldtio.c_iflag; + newtio.c_oflag |= OPOST; + tcsetattr(0, TCSADRAIN, &newtio); + stat = fcntl(0, F_GETFL, 0); + if (stat > 0) { + stat |= O_NONBLOCK; + (void) fcntl(0, 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(0, TCSADRAIN, &comtio); + stat = fcntl(0, F_GETFL, 0); + if (stat > 0) { + stat &= ~O_NONBLOCK; + (void) fcntl(0, F_SETFL, stat); + } + TermMode = 1; +} + +void +TtyOldMode() +{ + int stat; + + stat = fcntl(0, F_GETFL, 0); + if (stat > 0) { + stat &= ~O_NONBLOCK; + (void) fcntl(0, F_SETFL, stat); + } + tcsetattr(0, TCSANOW, &oldtio); +} + +void +Cleanup(int excode) +{ + DropClient(); + 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(0)); +} + +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 ! */ +} + +static void +Greetings(void) +{ + if (VarTerm) { + fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); + fflush(VarTerm); + } +} + +int +main(int argc, char **argv) +{ + FILE *lockfile; + char *name, *label; + + VarTerm = 0; + name = strrchr(argv[0], '/'); + LogOpen(name ? name + 1 : argv[0]); + + 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"; + VarTerm = 0; + LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); + } + LogClose(); + return 1; + } + + if (!GetShortHost()) + return 1; + Greetings(); + 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, "open_tun: %s\n", strerror(errno)); + return EX_START; + } + if (mode & MODE_INTER) { + fprintf(VarTerm, "Interactive mode\n"); + netfd = STDOUT_FILENO; + } else 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; + } + + tcgetattr(0, &oldtio); /* Save original tty mode */ + + 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(1); + close(2); + + if (mode & MODE_DIRECT) + TtyInit(1); + else if (mode & MODE_DAEMON) { + setsid(); + close(0); + } + } else { + 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); + } else + LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", + pid_filename, strerror(errno)); + + 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() +{ + if (RawModem() < 0) { + LogPrintf(LogWARN, "PacketMode: Not connected.\n"); + return; + } + AsyncInit(); + VjInit(15); + LcpInit(); + IpcpInit(); + CcpInit(); + LcpUp(); + + LcpOpen(VarOpenMode); + 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'; + if (n) + DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client"); + Prompt(); + } else if (n <= 0) + DropClient(); + return; + } + + /* + * We are in terminal mode, decode special sequences + */ + n = read(fileno(VarTerm), &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) { + VarOpenMode = OPEN_ACTIVE; + PacketMode(); + } + 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); + } +} + + +static void +DoLoop(void) +{ + fd_set rfds, wfds, efds; + int pri, i, n, wfd, nfds; + struct sockaddr_in hisaddr; + struct timeval timeout, *tp; + int ssize = sizeof(hisaddr); + const u_char *cp; + int tries; + int qlen; + int res; + pid_t pgroup; + struct tun_data tun; +#define rbuff tun.data + + pgroup = getpgrp(); + + if (mode & MODE_DIRECT) { + LogPrintf(LogDEBUG, "Opening modem\n"); + if (OpenModem() < 0) + return; + LogPrintf(LogPHASE, "Packet mode enabled\n"); + PacketMode(); + } 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) + if (VarOpenMode == OPEN_ACTIVE) + PacketMode(); + } + + /* + * 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) { + nointr_sleep(1); /* little pause to allow peer starts */ + ModemTimeout(NULL); + PacketMode(); + 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(); + } + 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); + } + + /* + * *** IMPORTANT *** + * + * CPU is serviced every TICKUNIT micro seconds. This value must be chosen + * with great care. If this values is too big, it results loss of + * characters from modem and poor responce. If this values is too small, + * ppp process eats many CPU time. + */ +#ifndef SIGALRM + nointr_usleep(TICKUNIT); + TimerService(); +#else + handle_signals(); +#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)) { + LogPrintf(LogPHASE, "connected to client.\n"); + wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); + if (wfd < 0) { + LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); + continue; + } + if (netfd >= 0) { + write(wfd, "already in use.\n", 16); + close(wfd); + continue; + } else + netfd = wfd; + VarTerm = fdopen(netfd, "a+"); + LocalAuthInit(); + Greetings(); + IsInteractive(1); + Prompt(); + } + if (netfd >= 0 && FD_ISSET(netfd, &rfds) && + ((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) { + /* something to read from tty */ + ReadTty(); + } + if (modem >= 0) { + if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ + ModemStartOutput(modem); + } + if (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(); + } 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); + 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); + dial_up = 1; /* XXX */ + } + continue; + } + 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/main.h b/usr.sbin/ppp/main.h new file mode 100644 index 00000000000..b44c699569c --- /dev/null +++ b/usr.sbin/ppp/main.h @@ -0,0 +1,31 @@ +/* + * 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.h,v 1.1 1997/11/23 20:27:34 brian Exp $ + * + */ + +extern int TermMode; +extern int tunno; + +extern void Cleanup(int); +extern void TtyTermMode(void); +extern void PacketMode(void); +extern void TtyOldMode(void); +extern void TtyCommandMode(int); diff --git a/usr.sbin/ppp/mbuf.c b/usr.sbin/ppp/mbuf.c new file mode 100644 index 00000000000..af0066f97c7 --- /dev/null +++ b/usr.sbin/ppp/mbuf.c @@ -0,0 +1,175 @@ +/* + * 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 1997/11/23 20:27:34 brian Exp $ + * + */ +#include <sys/param.h> +#include <sys/socket.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" + +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; + 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/mbuf.h b/usr.sbin/ppp/mbuf.h new file mode 100644 index 00000000000..0b203a6cc01 --- /dev/null +++ b/usr.sbin/ppp/mbuf.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: mbuf.h,v 1.1 1997/11/23 20:27:34 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 cnt; /* available byte count in buffer */ + short type; + struct mbuf *next; /* link to next mbuf */ + struct mbuf *pnext; /* link to next packet */ +}; + +struct mqueue { + struct mbuf *top; + struct mbuf *last; + int qlen; +}; + +#define NULLBUFF ((struct mbuf *)0) + +#define MBUF_CTOP(bp) (bp->base + 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_IPQ 10 +#define MB_MAX MB_IPQ + +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 DumpBp(struct mbuf *); +extern void LogMemory(void); +extern int ShowMemMap(struct cmdargs const *); diff --git a/usr.sbin/ppp/modem.c b/usr.sbin/ppp/modem.c new file mode 100644 index 00000000000..8a8bb140fc1 --- /dev/null +++ b/usr.sbin/ppp/modem.c @@ -0,0 +1,913 @@ +/* + * 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 1997/11/23 20:27:35 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 <termios.h> +#include <time.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(LogDEBUG, "Dequeue: Not zero (%d)!!!\n", queue->qlen); + } + } + return (bp); +} + +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; +} + +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(); + } 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); +} + +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); + } else + LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", fn, strerror(errno)); + + return 0; +} + +static void +UnlockModem(void) +{ + if (*VarDevice != '/') + return; + + snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, VarBaseDevice); + if (ID0unlink(fn) == -1) + LogPrintf(LogALERT, "Warning: Can't remove %s: %s\n", fn, strerror(errno)); + + 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; + + if (modem >= 0) + LogPrintf(LogDEBUG, "OpenModem: Modem is already open!\n"); + /* We're going back into "term" mode */ + else if (mode & MODE_DIRECT) { + struct cmdargs arg; + arg.cmd = NULL; + arg.data = (const void *)VAR_DEVICE; + if (isatty(0)) { + LogPrintf(LogDEBUG, "OpenModem(direct): Modem is a tty\n"); + cp = ttyname(0); + arg.argc = 1; + arg.argv = (char const *const *)&cp; + SetVariable(&arg); + if (LockModem() == -1) { + close(0); + return -1; + } + modem = 0; + HaveModem(); + } else { + LogPrintf(LogDEBUG, "OpenModem(direct): Modem is not a tty\n"); + arg.argc = 0; + arg.argv = NULL; + SetVariable(&arg); + /* We don't call ModemTimeout() with this type of connection */ + HaveModem(); + return modem = 0; + } + } else { + if (strncmp(VarDevice, "/dev/", 5) == 0) { + if (LockModem() == -1) + return (-1); + modem = ID0open(VarDevice, O_RDWR | O_NONBLOCK); + if (modem < 0) { + LogPrintf(LogERROR, "OpenModem failed: %s: %s\n", VarDevice, + strerror(errno)); + UnlockModem(); + return (-1); + } + 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 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]; + + strcpy(ScriptBuffer, VarHangupScript); /* arrays are the same size */ + 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) { + ClosePhysicalModem(); + if (Utmp) { + struct utmp ut; + strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); + ut.ut_line[sizeof(ut.ut_line)-1] = '\0'; + if (logout(ut.ut_line)) + logwtmp(ut.ut_line, "", ""); + else + LogPrintf(LogERROR, "CloseLogicalModem: No longer logged in on %s\n", + ut.ut_line); + Utmp = 0; + } + 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/modem.h b/usr.sbin/ppp/modem.h new file mode 100644 index 00000000000..0fd81148090 --- /dev/null +++ b/usr.sbin/ppp/modem.h @@ -0,0 +1,42 @@ +/* + * 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: modem.h,v 1.1 1997/11/23 20:27:35 brian Exp $ + * + * TODO: + */ + +extern int RawModem(void); +extern void UpModem(int); +extern void DownModem(int); +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); +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 ModemAddInOctets(int); +extern void ModemAddOutOctets(int); diff --git a/usr.sbin/ppp/os.c b/usr.sbin/ppp/os.c new file mode 100644 index 00000000000..19c3ce97fc6 --- /dev/null +++ b/usr.sbin/ppp/os.c @@ -0,0 +1,380 @@ +/* + * 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.1 1997/11/23 20:27:35 brian Exp $ + * + */ +#include <sys/param.h> +#include <sys/time.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/if_tun.h> +#include <net/route.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 "ccp.h" +#include "modem.h" + +char *IfDevName; + +static struct ifaliasreq ifra; +static struct ifreq ifrq; +static struct in_addr oldmine, oldhis; +static int linkup; + +static int +SetIpDevice(struct in_addr myaddr, + struct in_addr hisaddr, + struct in_addr netmask, + int updown) +{ + struct sockaddr_in *sock_in; + int s; + int changeaddr = 0; + u_long mask, addr; + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); + return (-1); + } + if (updown == 0) { + if (Enabled(ConfProxy)) + cifproxyarp(s, oldhis.s_addr); + 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_addr)); + memset(&ifra.ifra_mask, '\0', sizeof(ifra.ifra_addr)); + 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) { + changeaddr = 1; + } + + /* + * Set interface address + */ + sock_in = (struct sockaddr_in *) & (ifra.ifra_addr); + sock_in->sin_family = AF_INET; + sock_in->sin_addr = oldmine = 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 = oldhis = 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 (changeaddr) { + + /* + * Interface already exists. Just change the address. + */ + memcpy(&ifrq.ifr_addr, &ifra.ifra_addr, sizeof(struct sockaddr)); + if (ID0ioctl(s, SIOCSIFADDR, &ifra) < 0) + LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFADDR): %s\n", + strerror(errno)); + memcpy(&ifrq.ifr_dstaddr, &ifra.ifra_broadaddr, sizeof(struct sockaddr)); + if (ID0ioctl(s, SIOCSIFDSTADDR, &ifrq) < 0) + LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFDSTADDR): %s\n", + strerror(errno)); +#ifdef notdef + memcpy(&ifrq.ifr_broadaddr, &ifra.ifra_mask, sizeof(struct sockaddr)); + if (ID0ioctl(s, SIOCSIFBRDADDR, &ifrq) < 0) + LogPrintf(LogERROR, "SetIpDevice: ioctl(SIFBRDADDR): %s\n", + strerror(errno)); +#endif + } else if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { + LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", + strerror(errno)); + close(s); + return (-1); + } + if (Enabled(ConfProxy)) + sifproxyarp(s, hisaddr.s_addr); + } + close(s); + return (0); +} + +int +OsSetIpaddress(struct in_addr myaddr, + struct in_addr hisaddr, + struct in_addr netmask) +{ + return (SetIpDevice(myaddr, hisaddr, netmask, 1)); +} + +static struct in_addr peer_addr; +struct in_addr defaddr; + +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, 0); + + 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 new file mode 100644 index 00000000000..42a3f685ff7 --- /dev/null +++ b/usr.sbin/ppp/os.h @@ -0,0 +1,30 @@ +/* + * 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.1 1997/11/23 20:27:35 brian Exp $ + * + * TODO: + */ + +extern char *IfDevName; + +extern int OsSetIpaddress(struct in_addr, 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); diff --git a/usr.sbin/ppp/pap.c b/usr.sbin/ppp/pap.c new file mode 100644 index 00000000000..51e1e0b1290 --- /dev/null +++ b/usr.sbin/ppp/pap.c @@ -0,0 +1,216 @@ +/* + * 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 1997/11/23 20:27:35 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" + +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)-1); + strncpy(ut.ut_line, VarBaseDevice, sizeof(ut.ut_line)-1); + if (logout(ut.ut_line)) + logwtmp(ut.ut_line, "", ""); + login(&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/pap.h b/usr.sbin/ppp/pap.h new file mode 100644 index 00000000000..60862b826ed --- /dev/null +++ b/usr.sbin/ppp/pap.h @@ -0,0 +1,29 @@ +/* + * 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: pap.h,v 1.1 1997/11/23 20:27:35 brian Exp $ + * + * TODO: + */ + +#define PAP_REQUEST 1 +#define PAP_ACK 2 +#define PAP_NAK 3 + +extern struct authinfo AuthPapInfo; + +extern void PapInput(struct mbuf *); diff --git a/usr.sbin/ppp/patch/auth4.patch b/usr.sbin/ppp/patch/auth4.patch new file mode 100644 index 00000000000..a7231be4ae1 --- /dev/null +++ b/usr.sbin/ppp/patch/auth4.patch @@ -0,0 +1,12 @@ +--- main.c.orig Tue Nov 18 18:15:16 1997 ++++ main.c Tue Nov 18 18:16:33 1997 +@@ -396,6 +396,9 @@ + Greetings(); + 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"); + diff --git a/usr.sbin/ppp/patch/command5.patch b/usr.sbin/ppp/patch/command5.patch new file mode 100644 index 00000000000..36930703fd0 --- /dev/null +++ b/usr.sbin/ppp/patch/command5.patch @@ -0,0 +1,24 @@ +Index: command.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/command.c,v +retrieving revision 1.103 +diff -c -r1.103 command.c +*** command.c 1997/11/18 00:19:28 1.103 +--- command.c 1997/11/18 19:35:36 +*************** +*** 1013,1019 **** + void (*DiscardAll)(void); + + res = 0; +! if (strcasecmp(argv[0], "local")) { + Discard = LogDiscard; + Keep = LogKeep; + DiscardAll = LogDiscardAll; +--- 1013,1019 ---- + void (*DiscardAll)(void); + + res = 0; +! if (argc == 0 || strcasecmp(argv[0], "local")) { + Discard = LogDiscard; + Keep = LogKeep; + DiscardAll = LogDiscardAll; diff --git a/usr.sbin/ppp/patch/loopback2.patch b/usr.sbin/ppp/patch/loopback2.patch new file mode 100644 index 00000000000..03ca19a6cec --- /dev/null +++ b/usr.sbin/ppp/patch/loopback2.patch @@ -0,0 +1,36 @@ +Index: ppp.linkup.sample +=================================================================== +RCS file: /home/ncvs/src/etc/ppp/ppp.linkup.sample,v +retrieving revision 1.11 +diff -u -r1.11 ppp.linkup.sample +--- ppp.linkup.sample 1997/11/08 20:58:41 1.11 ++++ ppp.linkup.sample 1997/11/18 19:00:19 +@@ -53,3 +53,28 @@ + # + min5minutes: + !bg sh -c "sleep 240; pppctl -p mypassword 3000 set timeout 60" ++ ++# If you want to test ppp, do it through a loopback: ++# ++# Requires a line in /etc/services: ++# ppploop 6671/tcp # loopback ppp daemon ++# ++# and a line in /etc/inetd.conf: ++# ppploop stream tcp nowait root /usr/sbin/ppp ppp -direct loop-in ++# ++loop: ++ set timeout 0 ++ set log phase chat connect lcp ipcp command ++ set device localhost:ppploop ++ set dial ++ set login ++ set escape 0xff ++ set ifaddr 127.0.0.2 127.0.0.3 ++ set openmode passive ++ set server /tmp/loop "" ++ ++loop-in: ++ set timeout 0 ++ set log phase chat connect lcp ipcp command ++ set escape 0xff ++ allow mode direct diff --git a/usr.sbin/ppp/patch/random.patch b/usr.sbin/ppp/patch/random.patch new file mode 100644 index 00000000000..f490b9f1f61 --- /dev/null +++ b/usr.sbin/ppp/patch/random.patch @@ -0,0 +1,11 @@ +--- defs.c.orig Tue Nov 18 18:40:03 1997 ++++ defs.c Tue Nov 18 18:40:19 1997 +@@ -46,7 +46,7 @@ + void + randinit() + { +- srandom(time(NULL)); ++ srandom(time(NULL)&getpid()); + } + + diff --git a/usr.sbin/ppp/patch/thr.patch b/usr.sbin/ppp/patch/thr.patch new file mode 100644 index 00000000000..1a9a9c64e21 --- /dev/null +++ b/usr.sbin/ppp/patch/thr.patch @@ -0,0 +1,972 @@ +Index: Makefile +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/Makefile,v +retrieving revision 1.30 +diff -c -r1.30 Makefile +*** Makefile 1997/11/16 22:15:02 1.30 +--- Makefile 1997/11/18 13:35:35 +*************** +*** 4,11 **** + SRCS= alias_cmd.c arp.c async.c auth.c ccp.c chap.c chat.c \ + command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c lcp.c \ + loadalias.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 timer.c tun.c \ +! vars.c vjcomp.c + CFLAGS+=-Wall -Wmissing-prototypes + LDADD+= -lmd -lcrypt -lutil + DPADD+= ${LIBMD} ${LIBCRYPT} ${LIBUTIL} +--- 4,11 ---- + SRCS= alias_cmd.c arp.c async.c auth.c ccp.c chap.c chat.c \ + command.c defs.c filter.c fsm.c hdlc.c id.c ip.c ipcp.c lcp.c \ + loadalias.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 + LDADD+= -lmd -lcrypt -lutil + DPADD+= ${LIBMD} ${LIBCRYPT} ${LIBUTIL} +Index: ip.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/ip.c,v +retrieving revision 1.30 +diff -c -r1.30 ip.c +*** ip.c 1997/11/16 22:15:03 1.30 +--- ip.c 1997/11/18 12:46:18 +*************** +*** 251,257 **** + memcpy(MBUF_CTOP(bp), ptr, cnt); + SendPppFrame(bp); + RestartIdleTimer(); +! ipOutOctets += cnt; + } + #endif + } +--- 251,257 ---- + memcpy(MBUF_CTOP(bp), ptr, cnt); + SendPppFrame(bp); + RestartIdleTimer(); +! IpcpAddOutOctets(cnt); + } + #endif + } +*************** +*** 405,411 **** + pfree(bp); + return; + } +! ipInOctets += nb; + + nb = ntohs(((struct ip *) tun.data)->ip_len); + nb += sizeof(tun)-sizeof(tun.data); +--- 405,411 ---- + pfree(bp); + return; + } +! IpcpAddInOctets(nb); + + nb = ntohs(((struct ip *) tun.data)->ip_len); + nb += sizeof(tun)-sizeof(tun.data); +*************** +*** 450,456 **** + pfree(bp); + return; + } +! ipInOctets += nb; + nb += sizeof(tun)-sizeof(tun.data); + nw = write(tun_out, &tun, nb); + if (nw != nb) +--- 450,456 ---- + pfree(bp); + return; + } +! IpcpAddInOctets(nb); + nb += sizeof(tun)-sizeof(tun.data); + nw = write(tun_out, &tun, nb); + if (nw != nb) +*************** +*** 509,515 **** + cnt = plength(bp); + SendPppFrame(bp); + RestartIdleTimer(); +! ipOutOctets += cnt; + break; + } + } +--- 509,515 ---- + cnt = plength(bp); + SendPppFrame(bp); + RestartIdleTimer(); +! IpcpAddOutOctets(cnt); + break; + } + } +Index: ipcp.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/ipcp.c,v +retrieving revision 1.36 +diff -c -r1.36 ipcp.c +*** ipcp.c 1997/11/14 15:39:14 1.36 +--- ipcp.c 1997/11/18 14:09:09 +*************** +*** 33,38 **** +--- 33,39 ---- + #include <limits.h> + #include <stdio.h> + #include <string.h> ++ #include <time.h> + #include <unistd.h> + + #include "mbuf.h" +*************** +*** 51,56 **** +--- 52,58 ---- + #include "vars.h" + #include "vjcomp.h" + #include "ip.h" ++ #include "throughput.h" + + #ifndef NOMSEXT + struct in_addr ns_entries[2]; +*************** +*** 62,68 **** + struct in_range DefHisAddress; + struct in_addr TriggerAddress; + int HaveTriggerAddress; +- struct pppTimer IpcpReportTimer; + + static void IpcpSendConfigReq(struct fsm *); + static void IpcpSendTerminateAck(struct fsm *); +--- 64,69 ---- +*************** +*** 73,83 **** + static void IpcpLayerUp(struct fsm *); + static void IpcpLayerDown(struct fsm *); + static void IpcpInitRestartCounter(struct fsm *); +- static int IpcpOctetsIn(void); +- static int IpcpOctetsOut(void); +- +- static int lastInOctets, lastOutOctets; +- static int StartingIpIn, StartingIpOut; + + #define REJECTED(p, x) (p->his_reject & (1<<x)) + +--- 74,79 ---- +*************** +*** 126,157 **** + + #define NCFTYPES128 (sizeof(cftypes)/sizeof(char *)) + +! /* +! * Function called every second. Updates connection period and idle period, +! * also update LQR information. +! */ +! static void +! IpcpReportFunc() + { +! ipConnectSecs++; +! if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) +! ipIdleSecs++; +! lastInOctets = ipInOctets; +! lastOutOctets = ipOutOctets; +! StopTimer(&IpcpReportTimer); +! IpcpReportTimer.state = TIMER_STOPPED; +! StartTimer(&IpcpReportTimer); + } + +! static void +! IpcpStartReport() + { +! ipIdleSecs = ipConnectSecs = 0; +! StopTimer(&IpcpReportTimer); +! IpcpReportTimer.state = TIMER_STOPPED; +! IpcpReportTimer.load = SECTICKS; +! IpcpReportTimer.func = IpcpReportFunc; +! StartTimer(&IpcpReportTimer); + } + + int +--- 122,139 ---- + + #define NCFTYPES128 (sizeof(cftypes)/sizeof(char *)) + +! struct pppThroughput throughput; +! +! void +! IpcpAddInOctets(int n) + { +! throughput_addin(&throughput, n); + } + +! void +! IpcpAddOutOctets(int n) + { +! throughput_addout(&throughput, n); + } + + int +*************** +*** 167,176 **** + inet_ntoa(icp->his_ipaddr), icp->his_compproto); + fprintf(VarTerm, " my side: %s, %lx\n", + inet_ntoa(icp->want_ipaddr), icp->want_compproto); +- fprintf(VarTerm, "Connected: %d secs, idle: %d secs\n\n", +- ipConnectSecs, ipIdleSecs); +- fprintf(VarTerm, " %d octets in, %d octets out\n", +- IpcpOctetsIn(), IpcpOctetsOut()); + + fprintf(VarTerm, "Defaults:\n"); + fprintf(VarTerm, " My Address: %s/%d\n", +--- 149,154 ---- +*************** +*** 182,187 **** +--- 160,168 ---- + else + fprintf(VarTerm, " Negotiation(trigger): MYADDR\n"); + ++ fprintf(VarTerm, "\n"); ++ throughput_disp(&throughput, VarTerm); ++ + return 0; + } + +*************** +*** 232,239 **** + icp->want_compproto = 0; + icp->heis1172 = 0; + IpcpFsm.maxconfig = 10; +! StartingIpIn = ipInOctets; +! StartingIpOut = ipOutOctets; + } + + static void +--- 213,219 ---- + icp->want_compproto = 0; + icp->heis1172 = 0; + IpcpFsm.maxconfig = 10; +! throughput_init(&throughput); + } + + static void +*************** +*** 292,321 **** + NewPhase(PHASE_TERMINATE); + } + +- static int +- IpcpOctetsIn() +- { +- return ipInOctets < StartingIpIn ? +- INT_MAX - StartingIpIn + ipInOctets - INT_MIN + 1 : +- ipInOctets - StartingIpIn; +- } +- +- static int +- IpcpOctetsOut() +- { +- return ipOutOctets < StartingIpOut ? +- INT_MAX - StartingIpOut + ipOutOctets - INT_MIN + 1 : +- ipOutOctets - StartingIpOut; +- } +- + static void + IpcpLayerDown(struct fsm * fp) + { + LogPrintf(LogIPCP, "IpcpLayerDown.\n"); +! LogPrintf(LogIPCP, "%d octets in, %d octets out\n", +! IpcpOctetsIn(), IpcpOctetsOut()); +! StopTimer(&IpcpReportTimer); +! Prompt(); + } + + /* +--- 272,283 ---- + NewPhase(PHASE_TERMINATE); + } + + static void + IpcpLayerDown(struct fsm * fp) + { + LogPrintf(LogIPCP, "IpcpLayerDown.\n"); +! throughput_stop(&throughput); +! throughput_log(&throughput, LogIPCP, NULL); + } + + /* +*************** +*** 344,352 **** + if (mode & MODE_ALIAS) + VarPacketAliasSetAddress(IpcpInfo.want_ipaddr); + OsLinkup(); +! StartingIpIn = ipInOctets; +! StartingIpOut = ipOutOctets; +! IpcpStartReport(); + StartIdleTimer(); + } + +--- 306,312 ---- + if (mode & MODE_ALIAS) + VarPacketAliasSetAddress(IpcpInfo.want_ipaddr); + OsLinkup(); +! throughput_start(&throughput); + StartIdleTimer(); + } + +Index: ipcp.h +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/ipcp.h,v +retrieving revision 1.12 +diff -c -r1.12 ipcp.h +*** ipcp.h 1997/10/26 12:42:11 1.12 +--- ipcp.h 1997/11/18 12:44:33 +*************** +*** 76,78 **** +--- 76,80 ---- + extern void IpcpOpen(void); + extern int ReportIpcpStatus(void); + extern void IpcpInput(struct mbuf *); ++ extern void IpcpAddInOctets(int); ++ extern void IpcpAddOutOctets(int); +Index: lcp.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/lcp.c,v +retrieving revision 1.46 +diff -c -r1.46 lcp.c +*** lcp.c 1997/11/16 22:15:04 1.46 +--- lcp.c 1997/11/18 13:47:30 +*************** +*** 332,338 **** + StopAllTimers() + { + StopTimer(&LcpReportTimer); +- StopTimer(&IpcpReportTimer); + StopIdleTimer(); + StopTimer(&AuthPapInfo.authtimer); + StopTimer(&AuthChapInfo.authtimer); +--- 332,337 ---- +Index: modem.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/modem.c,v +retrieving revision 1.65 +diff -c -r1.65 modem.c +*** modem.c 1997/11/18 08:49:03 1.65 +--- modem.c 1997/11/18 14:36:46 +*************** +*** 55,60 **** +--- 55,61 ---- + #include "vars.h" + #include "main.h" + #include "chat.h" ++ #include "throughput.h" + #ifdef __OpenBSD__ + #include <util.h> + #else +*************** +*** 76,81 **** +--- 77,83 ---- + static struct mbuf *modemout; + static struct mqueue OutputQueues[PRI_LINK + 1]; + static int dev_is_modem; ++ static struct pppThroughput throughput; + + static void CloseLogicalModem(void); + +*************** +*** 116,245 **** + } 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 +--- 118,197 ---- + } 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 +*************** +*** 268,276 **** + return B0; + } + +- static time_t uptime; +- u_long OctetsIn, OctetsOut; +- + void + DownConnection() + { +--- 220,225 ---- +*************** +*** 478,485 **** + static void + HaveModem() + { +! time(&uptime); +! OctetsIn = OctetsOut = 0; + connect_count++; + LogPrintf(LogPHASE, "Connected!\n"); + } +--- 427,433 ---- + static void + HaveModem() + { +! throughput_start(&throughput); + connect_count++; + LogPrintf(LogPHASE, "Connected!\n"); + } +*************** +*** 497,503 **** + LogPrintf(LogDEBUG, "OpenModem: Modem is already open!\n"); + /* We're going back into "term" mode */ + else if (mode & MODE_DIRECT) { +- HaveModem(); + if (isatty(0)) { + LogPrintf(LogDEBUG, "OpenModem(direct): Modem is a tty\n"); + cp = ttyname(0); +--- 445,450 ---- +*************** +*** 507,516 **** +--- 454,465 ---- + return -1; + } + modem = 0; ++ HaveModem(); + } else { + LogPrintf(LogDEBUG, "OpenModem(direct): Modem is not a tty\n"); + SetVariable(0, 0, 0, VAR_DEVICE); + /* We don't call ModemTimeout() with this type of connection */ ++ HaveModem(); + return modem = 0; + } + } else { +*************** +*** 599,605 **** + if (ioctl(modem, TIOCMGET, &mbits)) { + LogPrintf(LogERROR, "OpenModem: Cannot get modem status: %s\n", + strerror(errno)); +- uptime = 0; + CloseLogicalModem(); + return (-1); + } +--- 548,553 ---- +*************** +*** 609,615 **** + if (oldflag < 0) { + LogPrintf(LogERROR, "OpenModem: Cannot get modem flags: %s\n", + strerror(errno)); +- uptime = 0; + CloseLogicalModem(); + return (-1); + } +--- 557,562 ---- +*************** +*** 674,701 **** + } + } + +! void ModemAddInOctets(int n) + { +! OctetsIn += n; + } + +! void ModemAddOutOctets(int n) + { +! OctetsOut += n; + } + + static void + ClosePhysicalModem() + { + close(modem); +! if (uptime) { +! LogPrintf(LogPHASE, "Connect time: %d secs\n", time(NULL) - uptime); +! LogPrintf(LogPHASE, "Modem: %d octets in, %d octets out\n", +! OctetsIn, OctetsOut); +! OctetsIn = OctetsOut = 0; +! uptime = 0; +! } +! modem = -1; /* Mark modem as closed */ + } + + void +--- 621,645 ---- + } + } + +! void +! ModemAddInOctets(int n) + { +! throughput_addin(&throughput, n); + } + +! void +! ModemAddOutOctets(int n) + { +! throughput_addout(&throughput, n); + } + + static void + ClosePhysicalModem() + { ++ LogPrintf(LogDEBUG, "ClosePhysicalModem\n"); + close(modem); +! modem = -1; +! throughput_log(&throughput, LogPHASE, "Modem"); + } + + void +*************** +*** 703,715 **** + { + struct termios tio; + +! LogPrintf(LogDEBUG, "Hangup modem (%s), uptime %ld\n", +! modem >= 0 ? "open" : "closed", (long)uptime); +! StopTimer(&ModemTimer); + + if (modem < 0) + return; + + if (TermMode) { + LogPrintf(LogDEBUG, "HangupModem: Not in 'term' mode\n"); + return; +--- 647,660 ---- + { + 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; +*************** +*** 735,740 **** +--- 680,686 ---- + char ScriptBuffer[SCRIPT_LEN]; + + strcpy(ScriptBuffer, VarHangupScript); /* arrays are the same size */ ++ LogPrintf(LogDEBUG, "HangupModem: Script: %s\n", ScriptBuffer); + if (flag || !(mode & MODE_DEDICATED)) { + DoChat(ScriptBuffer); + tcflush(modem, TCIOFLUSH); +*************** +*** 755,760 **** +--- 701,707 ---- + static void + CloseLogicalModem() + { ++ LogPrintf(LogDEBUG, "CloseLogicalModem\n"); + if (modem >= 0) { + ClosePhysicalModem(); + if (Utmp) { +*************** +*** 957,962 **** +--- 904,912 ---- + 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; + } +Index: ppp.8 +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/ppp.8,v +retrieving revision 1.79 +diff -c -r1.79 ppp.8 +*** ppp.8 1997/11/14 20:07:39 1.79 +--- ppp.8 1997/11/18 13:04:44 +*************** +*** 1548,1563 **** + may be one of the following: + + .Bl -tag -width 20 +! .It vjcomp +! Default: Enabled and Accepted. This option decides if Van Jacobson +! header compression will be used. +! +! .It lqr +! Default: Disabled and Accepted. This option decides if Link Quality +! Requests will be sent. LQR is a protocol that allows +! .Nm +! to determine that the link is down without relying on the modems +! carrier detect. + + .It chap + Default: Disabled and Accepted. CHAP stands for Challenge Handshake +--- 1548,1557 ---- + may be one of the following: + + .Bl -tag -width 20 +! .It acfcomp +! Default: Enabled and Accepted. ACFComp stands for Address and Control +! Field Compression. Non LCP packets usually have very similar address +! and control fields - making them easily compressible. + + .It chap + Default: Disabled and Accepted. CHAP stands for Challenge Handshake +*************** +*** 1593,1598 **** +--- 1587,1606 ---- + .Dq set encrypt + command for further details. + ++ .It lqr ++ Default: Disabled and Accepted. This option decides if Link Quality ++ Requests will be sent. LQR is a protocol that allows ++ .Nm ++ to determine that the link is down without relying on the modems ++ carrier detect. ++ ++ .It msext ++ Default: Disabled. This option allows the use of Microsoft's ++ .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". ++ + .It pap + Default: Disabled and Accepted. PAP stands for Password Authentication + Protocol. Only one of PAP and CHAP (above) may be negotiated. With +*************** +*** 1619,1655 **** + .Pa /etc/ppp/ppp.conf . + PAP is accepted by default. + +! .It acfcomp +! Default: Enabled and Accepted. ACFComp stands for Address and Control +! Field Compression. Non LCP packets usually have very similar address +! and control fields - making them easily compressible. + + .It protocomp + 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 pred1 +! Default: Enabled and Accepted. This option decides if Predictor 1 +! compression will be used. +! +! .It msext +! Default: Disabled. This option allows the use of Microsoft's +! .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". +! + .El + The following options are not actually negotiated with the peer. + Therefore, accepting or denying them makes no sense. + + .Bl -tag -width 20 +- .It proxy +- Default: Disabled. Enabling this option will tell +- .Nm +- to proxy ARP for the peer. +- + .It passwdauth + Default: Disabled. Enabling this option will tell the PAP authentication + code to use the password file (see +--- 1627,1651 ---- + .Pa /etc/ppp/ppp.conf . + PAP is accepted by default. + +! .It pred1 +! Default: Enabled and Accepted. This option decides if Predictor 1 +! compression will be used. + + .It protocomp + 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 vjcomp +! Default: Enabled and Accepted. This option decides 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 passwdauth + Default: Disabled. Enabling this option will tell the PAP authentication + code to use the password file (see +*************** +*** 1657,1662 **** +--- 1653,1678 ---- + to authenticate the caller rather than the + .Pa /etc/ppp/ppp.secret + file. ++ ++ .It proxy ++ Default: Disabled. Enabling this option will tell ++ .Nm ++ to proxy ARP for the peer. ++ ++ .It throughput ++ Default: Disabled. Enabling this option will tell ++ .Nm ++ to gather thoroughput 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 ++ .Em PPP ++ layer shuts down, and is also available using the ++ .Dq show ++ command. Troughput statistics are available at the ++ .Dq IPCP ++ and ++ .Dq modem ++ levels. + + .It utmp + Default: Enabled. Normally, when a user is authenticated using PAP or +Index: vars.c +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/vars.c,v +retrieving revision 1.34 +diff -c -r1.34 vars.c +*** vars.c 1997/11/11 22:58:14 1.34 +--- vars.c 1997/11/18 11:31:31 +*************** +*** 65,70 **** +--- 65,71 ---- + {"msext", CONF_DISABLE, CONF_NONE}, + {"passwdauth", CONF_DISABLE, CONF_NONE}, + {"utmp", CONF_ENABLE, CONF_NONE}, ++ {"throughput", CONF_DISABLE, CONF_NONE}, + {NULL}, + }; + +Index: vars.h +=================================================================== +RCS file: /home/ncvs/src/usr.sbin/ppp/vars.h,v +retrieving revision 1.33 +diff -c -r1.33 vars.h +*** vars.h 1997/11/09 22:07:29 1.33 +--- vars.h 1997/11/18 11:30:37 +*************** +*** 43,49 **** + #define ConfMSExt 8 + #define ConfPasswdAuth 9 + #define ConfUtmp 10 +! #define MAXCONFS 11 + + #define Enabled(x) (pppConfs[x].myside & CONF_ENABLE) + #define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT) +--- 43,50 ---- + #define ConfMSExt 8 + #define ConfPasswdAuth 9 + #define ConfUtmp 10 +! #define ConfThroughput 11 +! #define MAXCONFS 12 + + #define Enabled(x) (pppConfs[x].myside & CONF_ENABLE) + #define Acceptable(x) (pppConfs[x].hisside & CONF_ACCEPT) diff --git a/usr.sbin/ppp/patch/thr.tgz b/usr.sbin/ppp/patch/thr.tgz Binary files differnew file mode 100644 index 00000000000..31425a069b5 --- /dev/null +++ b/usr.sbin/ppp/patch/thr.tgz diff --git a/usr.sbin/ppp/pathnames.h b/usr.sbin/ppp/pathnames.h new file mode 100644 index 00000000000..989731e946a --- /dev/null +++ b/usr.sbin/ppp/pathnames.h @@ -0,0 +1,43 @@ +/* + * 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 new file mode 100644 index 00000000000..646151f27f4 --- /dev/null +++ b/usr.sbin/ppp/phase.c @@ -0,0 +1,66 @@ +/* + * $Id: phase.c,v 1.1 1997/11/23 20:27:35 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 "ipcp.h" +#include "ccp.h" +#include "defs.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" +}; + +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 = %x, mine = %x\n", lcp->his_auth, 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 new file mode 100644 index 00000000000..75b909e6d00 --- /dev/null +++ b/usr.sbin/ppp/phase.h @@ -0,0 +1,32 @@ +/* + * 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.1 1997/11/23 20:27:35 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 */ +#define PHASE_OSLINKED 5 /* The OS is linked up */ + +extern int phase; /* Curent phase */ + +extern void NewPhase(int); diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8 new file mode 100644 index 00000000000..086152ddb78 --- /dev/null +++ b/usr.sbin/ppp/ppp.8 @@ -0,0 +1,2453 @@ +.\" $Id: ppp.8,v 1.1 1997/11/23 20:27:35 brian Exp $ +.Dd 20 September 1995 +.Os OpenBSD +.Dt PPP 8 +.Sh NAME +.Nm ppp +.Nd Point to Point Protocol (a.k.a. iijppp) +.Sh SYNOPSIS +.Nm +.\" SOMEONE FIX ME ! The .Op macro can't handle enough args ! +[ +.Fl auto | +.Fl background | +.Fl ddial | +.Fl direct | +.Fl dedicated +] +.Op Fl alias +.Op Ar system +.Sh DESCRIPTION +This is a user process +.Em PPP +software package. Normally, +.Em PPP +is implemented as a part of the kernel (e.g. as managed by +.Xr pppd 8 ) +and it's thus somewhat hard to debug and/or modify its behaviour. +However, in this implementation +.Em PPP +is done as a user process with the help of the +tunnel device driver (tun). + +.Sh Major Features + +.Bl -diag +.It Provides interactive user interface. +Using its command mode, the user can +easily enter commands to establish the connection with the remote end, check +the status of connection and close the connection. All functions can +also be optionally password protected for security. + +.It Supports both manual and automatic dialing. +Interactive mode has a +.Dq term +command which enables you to talk to your modem directly. When your +modem is connected to the remote peer and it starts to talk +.Em PPP , +.Nm +detects it and switches to packet mode automatically. Once you have +determined the proper sequence for connecting with the remote host, you +can write a chat script to define the necessary dialing and login +procedure for later convenience. + +.It Supports on-demand dialup capability. +By using +.Fl auto +mode, +.Nm +will act as a daemon and wait for a packet to be sent over the +.Em PPP +link. When this happens, the daemon automatically dials and establishes the +connection. + +In almost the same manner +.Fl ddial +mode (direct-dial mode) also automatically dials and establishes the +connection. However, it differs in that it will dial the remote site +any time it detects the link is down, even if there are no packets to be +sent. This mode is useful for full-time connections where we worry less +about line charges and more about being connected full time. + +A third +.Fl dedicated +mode is also available. This mode is targeted at a dedicated link +between two machines. +.Nm Ppp +will never voluntarily quit from dedicated mode - you must send it the +.Dq quit all +command via its diagnostic socket. A +.Dv SIGHUP +will force an LCP renegotiation, and a +.Dv SIGTERM +will force it to exit. + +.It Supports packet aliasing. +Packet aliasing (a.k.a. IP masquerading) allows computers on a +private, unregistered network to access the Internet. The +.Em PPP +host acts as a masquerading gateway. IP addresses as well as TCP and +UDP port numbers are aliased for outgoing packets and de-aliased for +returning packets. + +.It Supports background PPP connections. +In background mode, if +.Nm +successfully establishes the connection, it will become a daemon. +Otherwise, it will exit with an error. This allows the setup of +scripts that wish to execute certain commands only if the connection +is successfully established. + +.It Supports server-side PPP connections. +In direct mode, +.nm +acts as server which accepts incoming +.Em PPP +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 +.Em PPP +protocol for authentication instead. + +.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. + +.It Tunnel driver supports bpf. +The user can use +.Xr tcpdump 1 +to check the packet flow over the +.Em PPP +link. + +.It Supports PPP over TCP capability. + + +.It Supports IETF draft Predictor-1 compression. +.Nm +supports not only VJ-compression but also Predictor-1 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 +.Em all +data flowing through the link, thus reducing overhead 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) + +.Sh PERMISSIONS +.Nm Ppp +is installed as user +.Dv root +and group +.Dv network , +with permissions +.Dv 4550 . +By default, +.Nm +will not run if the invoking user id is not zero. This may be overridden +by using the +.Dq allow users +command in +.Pa /etc/ppp/ppp.conf . +When running as a normal user, +.Nm +switches to user id 0 in order to alter the system routing table, set up +system lock files and read the ppp configuration files. All +external commands (executed via the "shell" or "!bg" commands) are executed +as the user id that invoked +.Nm ppp . +Refer to the +.Sq ID0 +logging facility if you're interested in what exactly is done as user id +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 +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: + +.Dl pseudo-device tun N + +where +.Ar N +is the maximum number of +.Em PPP +connections you wish to support. + +Second, check your +.Pa /dev +directory for the tunnel device entries +.Pa /dev/tunN , +where +.Sq N +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. +.Nm Ppp +uses +.Xr syslog 3 +to log information. A common log file name is +.Pa /var/log/ppp.log . +To make output go to this file, put the following lines in the +.Pa /etc/syslog.conf +file: + +.Dl !ppp +.Dl *.*<TAB>/var/log/ppp.log + +Make sure you use actual TABs here. If you use spaces, the line will be +silently ignored. + +It is possible to have more than one +.Em PPP +log file by creating a link to the +.Nm +executable: + +.Dl # cd /usr/sbin +.Dl # ln ppp ppp0 + +and using + +.Dl !ppp0 +.Dl *.* /var/log/ppp0.log + +in +.Pa /etc/syslog.conf . +Don't forget to send a +.Dv HUP +signal to +.Xr syslogd 8 +after altering +.Pa /etc/syslog.conf . + +.Sh MANUAL DIALING + +In the following examples, we assume that your machine name is +.Dv awfulhak . + +If you set your host name and password in +.Pa /etc/ppp/ppp.secret , +you can't do anything except run the help, passwd and quit commands. + +.Bd -literal -offset indent +ppp on "your host name"> help + help : Display this message + passwd : Password for security + quit : Quit the PPP program +ppp on awfulhak> pass <password> +.Ed + +The "on" part of your prompt will change to "ON" if you specify the +correct password. + +.Bd -literal -offset indent +ppp ON awfulhak> +.Ed + +You can now specify the device name, speed and parity for your modem, +and whether CTS/RTS signalling should be used (CTS/RTS is used by +default). If your hardware does not provide CTS/RTS lines (as +may happen when you are connected directly to certain PPP-capable +terminal servers), +.Nm +will never send any output through the port; it waits for a signal +which never comes. Thus, if you have a direct line and can't seem +to make a connection, try turning CTS/RTS off: + + +.Bd -literal -offset indent +ppp ON awfulhak> set line /dev/cuaa0 +ppp ON awfulhak> set speed 38400 +ppp ON awfulhak> set parity even +ppp ON awfulhak> set ctsrts on +ppp ON awfulhak> show modem + +* Modem related information is shown here * + +ppp ON awfulhak> +.Ed + +The term command can now be used to talk directly with your modem: + +.Bd -literal -offset indent +ppp ON awfulhak> term +at +OK +atdt123456 +CONNECT +login: ppp +Password: +Protocol: ppp +.Ed + +When the peer starts to talk in +.Em PPP , +.Nm +detects this automatically and returns to command mode. + +.Bd -literal -offset indent +ppp ON awfulhak> +PPP ON awfulhak> +.Ed + +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: + +.Bd -literal -offset indent +PPP ON awfulhak> show lcp + +* LCP related information is shown here * + +PPP ON awfulhak> show ipcp + +* IPCP related information is shown here * +.Ed + +At this point, your machine has a host route to the peer. This means +that you can only make a connection with the host on the other side +of the link. If you want to add a default route entry (telling your +machine to send all packets without another routing entry to the other +side of the +.Em PPP +link), enter the following command: + +.Bd -literal -offset indent +PPP ON awfulhak> add 0 0 HISADDR +.Ed + +The string +.Sq HISADDR +represents the IP address of the connected peer. This variable is only +available once a connection has been established. A common error +is to specify the above command in your +.Pa /etc/ppp/ppp.conf +file. This won't work as the remote IP address hasn't been +established when this file is read. + +You can now use your network applications (ping, telnet, ftp etc.) +in other windows on your machine. + +Refer to the +.Em PPP COMMAND LIST +section for details on all available commands. + +.Sh AUTOMATIC DIALING + +To use automatic dialing, you must prepare some Dial and Login chat scripts. +See the example definitions in +.Pa /etc/ppp/ppp.conf.sample +(the format of +.Pa /etc/ppp/ppp.conf +is pretty simple). + +Each line contains one comment, inclusion, label or command: + +.Bl -bullet -compact +.It +A line starting with a +.Pq Dq # +character is treated as a comment line. + +.It +An inclusion is a line beginning with the word +.Sq !include . +It must have one argument - the file to include. You may wish to +.Dq !include ~/.ppp.conf +for compatibility with older versions of +.Nm ppp . + +.It +A label name starts in the first column and is followed by +a colon +.Pq Dq \&: . + +.It +A command line must contain a space or tab in the first column. +.El + +.Pp +The +.Pa /etc/ppp/ppp.conf +file should consist of at least a +.Dq default +section. This section is always executed. It should also contain +one or more sections, named according to their purpose, for example, +.Dq MyISP +would represent your ISP, and +.Dq ppp-in +would represent an incoming +.Nm +configuration. + +You can now specify the destination label name when you invoke +.Nm ppp . +Commands associated with the +.Dq default +label are executed, followed by those associated with the destination +label provided. When +.Nm +is started with no arguments, the +.Dq default +section is still executed. The load command can be used to manually +load a section from the +.Pa /etc/ppp/ppp.conf +file: + +.Bd -literal -offset indent +PPP ON awfulhak> load MyISP +.Ed + +Once the connection is made, the +.Sq ppp +portion of the prompt will change to +.Sq PPP : + +.Bd -literal -offset indent +# ppp MyISP +... +ppp ON awfulhak> dial +dial OK! +login OK! +PPP ON awfulhak> +.Ed + +If the +.Pa /etc/ppp/ppp.linkup +file is available, its contents are executed +when the +.Em PPP +connection is established. See the provided +.Dq pmdemand +example in +.Pa /etc/ppp/ppp.conf.sample +which adds a default route. The 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 +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 . + +.Sh BACKGROUND DIALING + +If you want to establish a connection using +.Nm +non-interactively (such as from a +.Xr crontab 5 +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 ) + +When +.Fl background +is specified, +.Nm +attempts to establish the connection immediately. If multiple phone +numbers are specified, each phone number will be tried once. If the +attempt fails, +.Nm +exits immediately with a non-zero exit code. + +If it succeeds, then +.Nm +becomes a daemon, and returns an exit status of zero to its caller. +The daemon exits automatically if the connection is dropped by the +remote system, or it receives a +.Dv TERM +signal. + +.Sh DIAL ON DEMAND + +Demand dialing is enabled with the +.Fl auto +or +.Fl ddial +options. You must also specify the destination label in +.Pa /etc/ppp/ppp.conf +to use. It must contain the +.Dq set ifaddr +command to define the remote peers IP address. (refer to +.Pa /etc/ppp/ppp.conf.sample ) + +.Bd -literal -offset indent +# ppp -auto pmdemand +... +# +.Ed + +When +.Fl auto +or +.Fl ddial +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): + +.Bd -literal -offset indent +# pppctl -v 3000 show ipcp +Password: +IPCP [Opened] + his side: xxxx + .... +.Ed + +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 +.Nm +program listen on a diagnostic port by configuring +.Pa /etc/ppp/ppp.secret , +and sending it a +.Dv USR1 +signal. + +In +.Fl auto +mode, when an outgoing packet is detected, +.Nm +will perform the dialing action (chat script) and try to connect +with the peer. In +.Fl ddial +mode, the dialing action is performed any time the line is found +to be down. + +If the connect fails, the default behaviour is to wait 30 seconds +and then attempt to connect when another outgoing packet is detected. +This behaviour can be changed with +.Bd -literal -offset indent +set redial seconds|random[.nseconds|random] [dial_attempts] +.Ed +.Pp +.Sq Seconds +is the number of seconds to wait before attempting +to connect again. If the argument is +.Sq random , +the delay period is a random value between 0 and 30 seconds. +.Sq Nseconds +is the number of seconds to wait before attempting +to dial the next number in a list of numbers (see the +.Dq set phone +command). The default is 3 seconds. Again, if the argument is +.Sq random , +the delay period is a random value between 0 and 30 seconds. +.Sq dial_attempts +is the number of times to try to connect for each outgoing packet +that is received. The previous value is unchanged if this parameter +is omitted. If a value of zero is specified for +.Sq dial_attempts , +.Nm +will keep trying until a connection is made. +.Bd -literal -offset indent +set redial 10.3 4 +.Ed +.Pp +will attempt to connect 4 times for each outgoing packet that is +detected with a 3 second delay between each number and a 10 second +delay after all numbers have been tried. If multiple phone numbers +are specified, the total number of attempts is still 4 (it does not +attempt each number 4 times). + +Modifying the dial delay is very useful when running +.Nm +in demand +dial mode on both ends of the link. If each end has the same timeout, +both ends wind up calling each other at the same time if the link +drops and both ends have packets queued. + +At some locations, the serial link may not be reliable, and carrier +may be lost at inappropriate times. It is possible to have +.Nm +redial should carrier be unexpectedly lost during a session. +.Bd -literal -offset indent +set reconnect timeout ntries +.Ed + +This command tells +.Nm +to re-establish the connection +.Ar ntries +times on loss of carrier with a pause of +.Ar timeout +seconds before each try. For example, +.Bd -literal -offset indent +set reconnect 3 5 +.Ed + +tells +.Nm +that on an unexpected loss of carrier, it should wait +.Ar 3 +seconds before attempting to reconnect. This may happen up to +.Ar 5 +times before +.Nm +gives up. The default value of ntries is zero (no reconnect). Care +should be taken with this option. If the local timeout is slightly +longer than the remote timeout, the reconnect feature will always be +triggered (up to the given number of times) after the remote side +times out and hangs up. + +NOTE: In this context, losing too many LQRs constitutes a loss of +carrier and will trigger a reconnect. + +If the +.Fl background +flag is specified, all phone numbers are dialed at most once until +a connection is made. The next number redial period specified with +the +.Dq set redial +command is honoured, as is the reconnect tries value. If your redial +value is less than the number of phone numbers specified, not all +the specified numbers will be tried. + +To terminate the program, type + + PPP ON awfulhak> close + ppp ON awfulhak> quit all + +.Pp +A simple +.Dq quit +command will terminate the +.Xr pppctl 8 +or +.Xr telnet 1 +connection but not the +.Nm +program itself. +You must use +.Dq quit all +to terminate +.Nm +as well. + +.Sh RECEIVING INCOMING PPP CONNECTIONS (Method 1) + +To handle an incoming +.Em PPP +connection request, follow these steps: + +.Bl -enum +.It +Make sure the modem and (optionally) +.Pa /etc/rc.serial +is configured correctly. +.Bl -bullet -compact +.It +Use Hardware Handshake (CTS/RTS) for flow control. +.It +Modem should be set to NO echo back (ATE0) and NO results string (ATQ1). +.El + +.It +Edit +.Pa /etc/ttys +to enable a +.Xr getty 8 +on the port where the modem is attached. + +For example: + +.Dl ttyd1 "/usr/libexec/getty std.38400" dialup on secure + +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 + +.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 +.Ed + +(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 . + +.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. + +.El + +.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: + +.Bl -enum + +.It +Get, configure, and install mgetty+sendfax v0.99 or later making +sure you have used the AUTO_PPP option. + +.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 + +.It +Prepare an account for the incoming user. +.Bd -literal +Pfred:xxxx:66:66:Fred's PPP:/home/ppp:/etc/ppp/ppp-dialup +.Ed + +.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 + +.Sh PPP OVER TCP (a.k.a Tunneling) + +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: + +.Dl set device ui-gate:6669 + +Instead of opening a serial device, +.Nm +will open a TCP connection to the given machine on the given +socket. It should be noted however that +.Nm +doesn't use the telnet protocol and will be unable to negotiate +with a telnet server. You should set up a port for receiving this +.Em PPP +connection on the receiving machine (ui-gate). This is +done by first updating +.Pa /etc/services +to name the service: + +.Dl ppp-in 6669/tcp # Incoming PPP connections over TCP + +and updating +.Pa /etc/inetd.conf +to tell +.Xr inetd 8 +how to deal with incoming connections on that port: + +.Dl ppp-in stream tcp nowait root /usr/sbin/ppp ppp -direct ppp-in + +Don't forget to send a +.Dv HUP +signal to +.Xr inetd 8 +after you've updated +.Pa /etc/inetd.conf . + +Here, we use a label named +.Dq ppp-in . +The entry in +.Pa /etc/ppp/ppp.conf +on ui-gate (the receiver) should contain the following: + +.Bd -literal -offset indent +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.1 +.Ed + +You may also want to enable PAP or CHAP for security. To enable PAP, add +the following line: +.Bd -literal -offset indent + enable PAP +.Ed +.Pp +You'll also need to create the following entry in +.Pa /etc/ppp/ppp.secret : +.Bd -literal -offset indent +MyAuthName MyAuthPasswd +.Ed +.Pp +The entry in +.Pa /etc/ppp/ppp.conf +on awfulhak (the initiator) should contain the following: + +.Bd -literal -offset indent +ui-gate: + set escape 0xff + set device ui-gate:ppp-in + set dial + set timeout 30 5 4 + set log Phase Chat Connect Carrier 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.2 +.Ed +.Pp +Again, if you're enabling PAP, you'll also need: +.Bd -literal -offset indent + set authname MyAuthName + set authkey MyAuthKey +.Ed + +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 + +.Dl awfulhak # ppp -background ui-gate + +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. + +The networks are effectively bridged - the underlying TCP +connection may be across a public network (such as the +Internet), and the +.Em PPP +traffic is conceptually encapsulated +(although not packet by packet) inside the TCP stream between +the two gateways. + +The major disadvantage of this mechanism is that there are two +"guaranteed delivery" mechanisms in place - the underlying TCP +stream and whatever protocol is used over the +.Em PPP +link - probably TCP again. If packets are lost, both levels will +get in each others way trying to negotiate sending of the missing +packet. + +.Sh PACKET ALIASING + +The +.Fl alias +command line option enables packet aliasing. This allows the +.Nm +host to act as a masquerading gateway for other computers over +a local area network. Outgoing IP packets are aliased so that +they appear to come from the +.Nm +host, and incoming packets are de-aliased so that they are routed +to the correct machine on the local area network. + +Packet aliasing allows computers on private, unregistered +subnets to have Internet access, although they are invisible +from the outside world. + +In general, correct +.Nm +operation should first be verified with packet aliasing disabled. +Then, the +.Fl alias +option should be switched on, and network applications (web browser, +.Xr telnet 1 , +.Xr ftp 1 , +.Xr ping 8 , +.Xr traceroute 8 ) +should be checked on the +.Nm +host. Finally, the same or similar applications should be checked on other +computers in the LAN. + +If network applications work correctly on the +.Nm +host, but not on other machines in the LAN, then the masquerading +software is working properly, but the host is either not forwarding +or possibly receiving IP packets. Check that IP forwarding is enabled in +.Pa /etc/rc.conf +and that other machines have designated the +.Nm +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 +.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] +.Bl -enum +.It +.Sq filter-name +should be one of ifilter, ofilter, dfilter or afilter. +.It +There are two actions: +.Sq permit +and +.Sq deny . +If a given packet +matches the rule, the associated action is taken immediately. +.It +.Sq src_width +and +.Sq dst_width +work like a netmask to represent an address range. +.It +.Sq proto +must be one of icmp, udp or tcp. +.It +.Sq port number +can be specified by number and service name from +.Pa /etc/services . + +.El + +.It +Each filter can hold up to 20 rules, starting from rule 0. +The entire rule set is not effective until rule 0 is defined, +ie. the default is to allow everything through. + +.It +If no rule is matched to a packet, that packet will be discarded +(blocked). + +.It +Use +.Dq set filter-name -1 +to flush all rules. + +.El + +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 +and +.Dq set timeout [lqrtimer [retrytimer]] +commands: + +.Bd -literal -offset indent +ppp ON awfulhak> set timeout 600 +.Ed + +The timeout period is measured in seconds, the default values for which +are timeout = 180 or 3 min, lqrtimer = 30sec and retrytimer = 3sec. +To disable the idle timer function, use the command + +.Bd -literal -offset indent +ppp ON awfulhak> set timeout 0 +.Ed + +In +.Fl auto +mode, an idle timeout causes the +.Em PPP +session to be +closed, though the +.Nm +program itself remains running. Another trigger packet will cause it to +attempt to reestablish the link. + +.Sh PREDICTOR-1 COMPRESSION + +This version supports CCP and Predictor type 1 compression based on +the current IETF-draft specs. As a default behaviour, +.Nm +will attempt to use (or be willing to accept) this capability when the +peer agrees (or requests it). + +To disable CCP/predictor functionality completely, use the +.Dq disable pred1 +and +.Dq deny pred1 +commands. + +.Sh CONTROLLING IP ADDRESS + +.Nm +uses IPCP to negotiate IP addresses. Each side of the connection +specifies the IP address that it's willing to use, and if the requested +IP address is acceptable then +.Nm +returns ACK to the requester. Otherwise, +.Nm +returns NAK to suggest that the peer use a different IP address. When +both sides of the connection agree to accept the received request (and +send ACK), IPCP is set to the open state and a network level connection +is established. + +To control this IPCP behaviour, this implementation has the +.Dq set ifaddr +command for defining the local and remote IP address: + +.Bd -literal -offset indent +set ifaddr [src_addr [dst_addr [netmask [trigger_addr]]]] +.Ed + +where, +.Sq src_addr +is the IP address that the local side is willing to use, +.Sq dst_addr +is the IP address which the remote side should use and +.Sq netmask +is the netmask that should be used. +.Sq Src_addr +and +.Sq dst_addr +default 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. +Some incorrect +.Em PPP +implementations require that the peer negotiates a specific IP +address instead of +.Sq src_addr . +If this is the case, +.Sq trigger_addr +may be used to specify this IP number. This will not affect the +routing table unless the other side agrees with this proposed number. + +.Bd -literal -offset indent +set ifaddr 192.244.177.38 192.244.177.2 255.255.255.255 0.0.0.0 +.Ed + +The above specification means: +.Bl -bullet -compact +.It +I will first suggest that my IP address should be 0.0.0.0, but I +will only accept an address of 192.244.177.38. + +.It +I strongly insist that the peer uses 192.244.177.2 as his own +address and won't permit the use of any IP address but 192.244.177.2. +When the peer requests another IP address, I will always suggest that +it uses 192.244.177.2. + +.It +The routing table entry will have a netmask of 0xffffffff. +.El + +This is all fine when each side has a pre-determined IP address, however +it is often the case that one side is acting as a server which controls +all IP addresses and the other side should obey the direction from it. + +In order to allow more flexible behaviour, `ifaddr' variable allows the +user to specify IP address more loosely: + +.Dl set ifaddr 192.244.177.38/24 192.244.177.2/20 + +A number followed by a slash (/) represent the number of bits significant in +the IP address. The above example signifies that: + +.Bl -bullet -compact +.It +I'd like to use 192.244.177.38 as my address if it is possible, but I'll +also accept any IP address between 192.244.177.0 and 192.244.177.255. + +.It +I'd like to make him use 192.244.177.2 as his own address, but I'll also +permit him to use any IP address between 192.244.176.0 and +192.244.191.255. + +.It +As you may have already noticed, 192.244.177.2 is equivalent to saying +192.244.177.2/32. + +.It +As an exception, 0 is equivalent to 0.0.0.0/0, meaning that I have no +preferred IP address and will obey the remote peers selection. When +using zero, no routing table entries will be made until a connection +is established. + +.It +192.244.177.2/0 means that I'll accept/permit any IP address but I'll +try to insist that 192.244.177.2 be used first. +.El + +.Sh CONNECTING WITH YOUR INTERNET SERVICE PROVIDER + +The following steps should be taken when connecting to your ISP: + +.Bl -enum +.It +Describe your providers phone number(s) in the dial script using the +.Dq set phone +command. This command allows you to set multiple phone numbers for +dialing and redialing separated by either a pipe (|) or a colon (:) +.Bd -literal -offset indent +set phone "111[|222]...[:333[|444]...]... +.Ed +Numbers after the first in a pipe-separated list are only used if the +previous number was used in a failed dial or login script. Numbers +separated by a colon are used sequentially, irrespective of what happened +as a result of using the previous number. For example: +.Bd -literal -offset indent +set phone "1234567|2345678:3456789|4567890" +.Ed +.Pp +Here, the 1234567 number is attempted. If the dial or login script fails, +the 2345678 number is used next time, but *only* if the dial or login script +fails. On the dial after this, the 3456789 number is used. The 4567890 +number is only used if the dial or login script using the 3456789 fails. If +the login script of the 2345678 number fails, the next number is still the +3456789 number. As many pipes and colons can be used as are necessary +(although a given site would usually prefer to use either the pipe or the +colon, but not both). The next number redial timeout is used between all +numbers. When the end of the list is reached, the normal redial period is +used before starting at the beginning again. + +The selected phone number is substituted for the \\\\T string in the +.Dq set dial +command (see below). + +.It +Set up your redial requirements using +.Dq set redial . +For example, if you have a bad telephone line or your provider is +usually engaged (not so common these days), you may want to specify +the following: +.Bd -literal -offset indent +set redial 10 4 +.Ed +.Pp +This says that up to 4 phone calls should be attempted with a pause of 10 +seconds before dialing the first number again. + +.It +Describe your login procedure using the +.Dq set dial +and +.Dq set login +commands. The +.Dq set dial +command is used to talk to your modem and establish a link with your +ISP, for example: +.Bd -literal -offset indent +set dial "ABORT BUSY ABORT NO\\\\sCARRIER TIMEOUT 4 \\"\\" ATZ OK-ATZ-OK ATDT\\\\T TIMEOUT 60 CONNECT" +.Ed +.Pp +This modem "chat" string means: + +.Bl -bullet +.It +Abort if the string "BUSY" or "NO CARRIER" are received. +.It +Set the timeout to 4. +.It +Expect nothing. +.It +Send ATZ. +.It +Expect OK. If that's not received, send ATZ and expect OK. +.It +Send ATDTxxxxxxx where xxxxxxx is the next number in the phone list from +above. +.It +Set the timeout to 60. +.It +Wait for the CONNECT string. +.El + +Once the connection is established, the login script is executed. This +script is written in the same style as the dial script: +.Bd -literal -offset indent +set login "TIMEOUT 15 login:-\\\\r-login: awfulhak word: xxx ocol: PPP HELLO" +.Ed +.Pp +This login "chat" string means: + +.Bl -bullet +.It +Set the timeout to 15 seconds. +.It +Expect "login:". If it's not received, send a carriage return and expect +"login:" again. +.It +Send "awfulhak" +.It +Expect "word:" (the tail end of a "Password:" prompt). +.It +Send "xxx". +.It +Expect "ocol:" (the tail end of a "Protocol:" prompt). +.It +Send "PPP". +.It +Expect "HELLO". +.El +.Pp +Login scripts vary greatly between ISPs. + +.It +Use +.Dq set line +and +.Dq set speed +to specify your serial line and speed, for example: +.Bd -literal -offset indent +set line /dev/cuaa0 +set speed 115200 +.Ed +.Pp +Cuaa0 is the first serial port on FreeBSD. If you're running +.Nm +on OpenBSD, cua00 is the first. A speed of 115200 should be specified +if you have a modem capable of bit rates of 28800 or more. In general, +the serial speed should be about four times the modem speed. + +.It +Use the +.Dq set ifaddr +command to define the IP address. +.Bl -bullet +.It +If you know what IP address your provider uses, then use it as the remote +address (dst_addr), otherwise choose something like 10.0.0.2/0 (see below). +.It +If your provider has assigned a particular IP address to you, then use +it as your address (src_addr). +.It +If your provider assigns your address dynamically, choose a suitably +unobtrusive and unspecific IP number as your address. 10.0.0.1/0 would +be appropriate. The bit after the / specifies how many bits of the +address you consider to be important, so if you wanted to insist on +something in the class C network 1.2.3.0, you could specify 1.2.3.1/24. +.It +If you find that your ISP accepts the first IP number that you suggest, +specify third and forth arguments of +.Dq 0.0.0.0 . +This will force your ISP to assign a number. (The third argument will +be ignored as it is less restrictive than the default mask for your +.Sq src_addr . +.El +.Pp +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 +.Ed + +.It +In most cases, your ISP will also be your default router. If this is +the case, add the lines + +.Bd -literal -offset indent +delete ALL +add 0 0 HISADDR +.Ed + +.Pp +to +.Pa /etc/ppp/ppp.conf . +.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. +.Pp +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 0 0 HISADDR +.Ed + +HISADDR is a macro meaning the "other side"s IP number, and is +available once an IP number has been agreed (using IPCP). +Now, once a connection is established, +.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 0 0 HISADDR +.Ed +.Pp +after a successful dial. + +.It +If your provider requests that you use PAP/CHAP authentication methods, add +the next lines to your +.Pa /etc/ppp/ppp.conf +file: +.Bd -literal -offset indent +set authname MyName +set authkey MyPassword +.Ed +.Pp +Both are accepted by default, so +.Nm +will provide whatever your ISP requires. +.El + +Please refer to +.Pa /etc/ppp/ppp.conf.sample +and +.Pa /etc/ppp/ppp.linkup.sample +for some real examples. The pmdemand label should be appropriate for most +ISPs. + +.Sh LOGGING FACILITY + +.Nm +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 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 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 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. +.It Li Error Output to both the terminal device and the log file using +LOG_ERROR. +.It Li Alert Output to the log file using LOG_ALERT +.El + +.Pp +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 . + +.Pp +It is also possible to log directly to the screen. The syntax is +the same except that the word +.Dq local +should immediately follow +.Dq set log . +The default is +.Dq set log local +(ie. no direct screen logging). + +.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> show log +Log: Carrier Link Phase Warning Error Alert +Local: Warning Error Alert +PPP ON awfulhak> set log -link +tcp/ip -warning +PPP ON awfulhak> set log local +command +PPP ON awfulhak> show log +Log: Carrier Phase TCP/IP Warning Error Alert +Local: Command Warning Error Alert +.Ed + +.Pp +Log messages of level Warning, Error and Alert are not controllable +using +.Dq set log Op local . + +.Pp +The +.Ar Warning +level is special in that it will not be logged if it can be displayed +locally. + +.Sh SIGNAL HANDLING + +.Nm Ppp +deals with the following signals: + +.Bl -tag -width 20 +.It INT +Receipt of this signal causes the termination of the current connection +(if any). This will cause +.Nm +to exit unless it is in +.Fl auto +or +.Fl ddial +mode. + +.It HUP, TERM & QUIT +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. + +.El + +.Sh PPP COMMAND LIST + +This section lists the available commands and their effect. They are +usable either from an interactive +.Nm +session, from a configuration file or from a +.Xr pppctl 8 +or +.Xr telnet 1 +session. + +.Bl -tag -width 20 +.It accept|deny|enable|disable option.... +These directives tell +.Nm +how to negotiate the initial connection with the peer. Each +.Dq option +has a default of either accept or deny and enable or disable. +.Dq Accept +means that the option will be ACK'd if the peer asks for it. +.Dq Deny +means that the option will be NAK'd if the peer asks for it. +.Dq Enable +means that the option will be requested by us. +.Dq Disable +means that the option will not be requested by us. +.Pp +.Dq Option +may be one of the following: + +.Bl -tag -width 20 +.It acfcomp +Default: Enabled and Accepted. ACFComp stands for Address and Control +Field Compression. Non LCP packets usually have very similar address +and control fields - making them easily compressible. + +.It chap +Default: Disabled and Accepted. CHAP stands for Challenge Handshake +Authentication Protocol. Only one of CHAP and PAP (below) may be +negotiated. With CHAP, the authenticator sends a "challenge" message +to its peer. The peer uses a one-way hash function to encrypt the +challenge and sends the result back. The authenticator does the same, +and compares the results. The advantage of this mechanism is that no +passwords are sent across the connection. + +A challenge is made when the connection is first made. Subsequent +challenges may occur. If you want to have your peer authenticate +itself, you must +.Dq enable chap . +in +.Pa /etc/ppp/ppp.conf , +and have an entry in +.Pa /etc/ppp/ppp.secret +for the peer. +.Pp +When using CHAP as the client, you need only specify +.Dq AuthName +and +.Dq AuthKey +in +.Pa /etc/ppp/ppp.conf . +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. + +.It lqr +Default: Disabled and Accepted. This option decides if Link Quality +Requests will be sent. LQR is a protocol that allows +.Nm +to determine that the link is down without relying on the modems +carrier detect. + +.It msext +Default: Disabled. This option allows the use of Microsoft's +.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". + +.It pap +Default: Disabled and Accepted. PAP stands for Password Authentication +Protocol. Only one of PAP and CHAP (above) may be negotiated. With +PAP, the ID and Password are sent repeatedly to the peer until +authentication is acknowledged or the connection is terminated. This +is a rather poor security mechanism. It is only performed when the +connection is first established. + +If you want to have your peer authenticate itself, you must +.Dq enable pap . +in +.Pa /etc/ppp/ppp.conf , +and have an entry in +.Pa /etc/ppp/ppp.secret +for the peer (although see the +.Dq passwdauth +option below). +.Pp +When using PAP as the client, you need only specify +.Dq AuthName +and +.Dq AuthKey +in +.Pa /etc/ppp/ppp.conf . +PAP is accepted by default. + +.It pred1 +Default: Enabled and Accepted. This option decides if Predictor 1 +compression will be used. + +.It protocomp +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 vjcomp +Default: Enabled and Accepted. This option decides 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 passwdauth +Default: Disabled. Enabling this option will tell the PAP authentication +code to use the password file (see +.Xr passwd 5 ) +to authenticate the caller rather than the +.Pa /etc/ppp/ppp.secret +file. + +.It proxy +Default: Disabled. Enabling this option will tell +.Nm +to proxy ARP for the peer. + +.It throughput +Default: Disabled. Enabling this option will tell +.Nm +to gather thoroughput 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 +.Em PPP +layer shuts down, and is also available using the +.Dq show +command. Troughput statistics are available at the +.Dq IPCP +and +.Dq modem +levels. + +.It utmp +Default: Enabled. Normally, when a user is authenticated using PAP or +CHAP, and when +.Nm +is running in +.Fl direct +mode, an entry is made in the utmp and wtmp files for that user. Disabling +this option will tell +.Nm +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 + +.It add dest mask gateway +.Dq Dest +is the destination IP address and +.Dq mask +is its mask. +.Dq 0 0 +refers to the default route. +.Dq Gateway +is the next hop gateway to get to the given +.Dq dest +machine/network. + +.It allow ..... +This command controls access to +.Nm +and its configuration files. It is possible to allow user-level access, +depending on the configuration file label and on the mode that +.Nm +is being run in. For example, you may wish to configure +.Nm +so that only user +.Sq fred +may access label +.Sq fredlabel +in +.Fl background +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 +.Dq allow users +command is found. The +.Sq default +section is always checked first (although 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 +to everything except a given label by specifying default users in the +.Sq default +section, and then specifying a new user list for that label. +.Pp +If user +.Sq * +is specified, access is allowed to all users. + +.It allow mode|modes modelist... +By default, access using all +.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. +Again, as with the +.Dq allow users +command, each +.Dq allow modes +command overrides the previous, and the +.Sq default +section is always checked first. +.Pp +Possible modes are: +.Sq interactive , +.Sq auto , +.Sq direct , +.Sq dedicated , +.Sq ddial , +.Sq background +and +.Sq * . +.El + +.It alias ..... +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 +.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] +This command allows us to redirect connections arriving at +.Dq aliasPORT +for machine [aliasIP] to +.Dq targetPORT +on +.Dq targetIP . +If proto is specified, 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] +This command allows data for +.Dq addr_alias +to be redirected to +.Dq 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 log [yes|no] +This option causes various aliasing statistics and information to +be logged to the file +.Pa /var/log/alias.log . + +.It alias same_ports [yes|no] +When enabled, this command will tell the alias library attempt to +avoid changing the port number on outgoing packets. This is useful +if you want to support protocols such as RPC and LPD which require +connections to come from a well known port. + +.It alias use_sockets [yes|no] +When enabled, this option tells the alias library to create a +socket so that it can guarantee a correct incoming ftp data or +IRC connection. + +.It alias unregistered_only [yes|no] +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 + +.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 +.Nm +while the command executes, use the +.Dv shell +command instead. + +.It close +Close the current connection (but don't quit). + +.It delete ALL | dest [gateway [mask]] +If +.Dq ALL +is specified, all non-direct entries in the routing for the interface +that +.Nm +is using are deleted. This means all entries for tunN, except the entry +representing the actual link. When +.Dq ALL +is not used, any existing route with the given +.Dq dest , +destination network +.Dq mask +and +.Dq gateway +is deleted. The default +.Dq mask +value is 0.0.0.0. + +.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] +Show a list of available commands. If +.Dq command +is specified, show the usage string for that command. + +.It load [remote] +Load the given +.Dq remote +label. If +.Dq remote +is not given, the +.Dq default +label is assumed. + +.It passwd pass +Specify the password required for access to the full +.Nm +command set. + +.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 +or +.Xr telnet 1 +session will not close the current connection. + +.It save +This option is not (yet) implemented. + +.It set[up] 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. +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 +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, preventing +the actual password from being logged. + +.It set authname 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 +This sets the device to which +.Nm +will talk to the given +.Dq value . +All serial device names are expected to begin with +.Pa /dev/ . +If +.Dq value +does not begin with +.Pa /dev/ , +it must be of the format +.Dq host:port . +If this is the case, +.Nm +will attempt to connect to the given +.Dq host +on the given +.Dq port . +Refer to the section on +.Em PPP OVER TCP +above for further details. + +.It set dial chat-script +This specifies the chat script that will be used to dial the other +side. See also the +.Dv set login +command below. Refer to +.Xr chat 8 +and to the example configuration files for details of the chat script +format. The string \\\\T will be replaced with the current phone number +(see +.Dq set phone +below) and the string \\\\P will be replaced with the password (see +.Dq set key +above). + +.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 + +.It set escape 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]]]] +This command specifies the IP addresses that will be used during +IPCP negotiation. Addresses are specified using the format + +.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. + +If +.Dq triggeraddr +is specified, it is used in place of +.Dq myaddr +in the initial IPCP negotiation. However, only an address in the +.Dq myaddr +range will be accepted. + +.It set loopback on|off +When set to +.Dq 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 +.Dq off , +.Nm +will send the packet, probably resulting in an ICMP redirect from +the other end. + +.It set log [local] [+|-]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 +This 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 +.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 openmode active|passive +By default, openmode is always active. That is, +.Nm +will always initiate LCP/IPCP/CCP negotiation. If you want to wait for the +peer to initiate negotiations, you may use the value +.Dq passive . + +.It set parity odd|even|none|mark +This allows the line parity to be set. The default value is none. + +.It set phone 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 +a colon (:). Numbers after the pipe are only dialed if the dial or login +script for the previous number failed. Numbers separated by a colon are +tried sequentially, irrespective of the reason the line was dropped. +If multiple numbers are given, +.Nm +will dial them according to these rules until a connection is made, retrying +the maximum number of times specified by +.Dq set redial +below. In +.Fl background +mode, each number is attempted at most once. + +.It set reconnect timeout ntries +Should the line drop unexpectedly (due to loss of CD or LQR +failure), a connection will be re-established after the given +.Dq timeout . +The line will be re-connected at most +.Dq ntries +times. +.Dq Ntries +defaults to zero. A value of +.Dq random +for +.Dq timeout +will result in a variable pause, somewhere between 0 and 30 seconds. + +.It set redial seconds[.nseconds] [attempts] +.Nm Ppp +can be instructed to attempt to redial +.Dq attempts +times. If more than one number is specified (see +.Dq set phone +above), a pause of +.Dq nseconds +is taken before dialing each number. A pause of +.Dq seconds +is taken before starting at the first number again. A value of +.Dq 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. 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. + +.It set server|socket TcpPort|LocalName|none [password] [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 +.Ar none +instructs +.Nm +to close any existing socket. If you wish to specify a unix 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 +beginning with +.Sq 0 . +Refer to +.Xr umask 2 +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. + +.Pp +When using +.Nm +with a server socket, the +.Xr pppctl 8 +command is the preferred mechanism of communications. Currently, +.Xr telnet 1 +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 +This sets the speed of the serial device. + +.It set timeout Idle [ lqr [ retry ] ] +This command allows the setting of the idle timer, the LQR timer (if +enabled) and the retry timer. + +.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 help|? +This command gives a summary of available set commands. +.El + +.It shell|! [command] +If +.Dq 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 - +.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 +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 authkey. + +.It show ccp +Show the current CCP statistics. + +.It show compress +Show the current compress statistics. + +.It show escape +Show the current escape characters. + +.It show hdlc +Show the current HDLC statistics. + +.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 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. + +.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 version +Show the current version number of +.Nm ppp . + +.It show help|? +Give a summary of available show commands. +.El + +.It term +Go into terminal mode. Characters typed at the keyboard are sent to +the modem. Characters read from the modem are displayed on the +screen. When a +.Nm +peer is detected on the other side of the modem, +.Nm +automatically enables Packet Mode and goes back into command mode. + +.El + +.Sh MORE DETAILS + +.Bl -bullet -compact + +.It +Read the example configuration files. They are a good source of information. + +.It +Use +.Dq help , +.Dq show ? , +.Dq alias ? , +.Dq set ? +and +.Dq set ? <var> +commands. +.El + +.Sh FILES +.Nm Ppp +refers to four files: +.Pa ppp.conf , +.Pa ppp.linkup , +.Pa ppp.linkdown +and +.Pa ppp.secret . +These files are placed in the +.Pa /etc/ppp +directory. + +.Bl -tag -width flag +.It Pa /etc/ppp/ppp.conf +System default configuration file. + +.It Pa /etc/ppp/ppp.secret +An authorisation file for each system. + +.It Pa /etc/ppp/ppp.linkup +A file to check when +.Nm +establishes a network level connection. + +.It Pa /etc/ppp/ppp.linkdown +A file to check when +.Nm +closes a network level connection. + +.It Pa /var/log/ppp.log +Logging and debugging information file. Note, this name is specified in +.Pa /etc/syslogd.conf . +See +.Xr syslog.conf 5 +for further details. + +.It Pa /var/spool/lock/LCK..* +tty port locking file. Refer to +.Xr uucplock 3 +for further details. + +.It Pa /var/run/tunN.pid +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. + +.It Pa /var/run/ttyXX.if +The tun interface used by this port. Again, this file is only created in +.Fl background , +.Fl auto +and +.Fl ddial +modes. + +.It Pa /etc/services +Get port number if port number is using service name. +.El + +.Sh SEE ALSO + +.Xr at 1 , +.Xr chat 8 , +.Xr crontab 5 , +.Xr ftp 1 , +.Xr getty 8 , +.Xr hostname 1 , +.Xr inetd 8 , +.Xr init 8 , +.Xr login 1 , +.Xr passwd 5 , +.Xr ping 8 , +.Xr pppctl 8 , +.Xr pppd 8 , +.Xr syslog 3 , +.Xr syslog.conf 5 , +.Xr syslogd 8 , +.Xr tcpdump 1 , +.Xr telnet 1 , +.Xr traceroute 8 , +.Xr uucplock 3 + +.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). +It has since had an enormous face lift and looks substantially different. diff --git a/usr.sbin/ppp/pred.c b/usr.sbin/ppp/pred.c new file mode 100644 index 00000000000..3430cee9cfa --- /dev/null +++ b/usr.sbin/ppp/pred.c @@ -0,0 +1,222 @@ +/* + * pred.c -- Test program for Dave Rand's rendition of the + * predictor algorithm + * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson) + * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de> + * Original : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com> + * + * $Id: pred.c,v 1.1 1997/11/23 20:27:35 brian Exp $ + * + */ + +#include <sys/types.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 "lcpproto.h" +#include "ccp.h" +#include "pred.h" + +/* The following hash code is the heart of the algorithm: + * It builds a sliding hash sum of the previous 3-and-a-bit characters + * which will be used to index the guess table. + * 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) + +static unsigned short int iHash, oHash; +static unsigned char InputGuessTable[65536]; +static unsigned char OutputGuessTable[65536]; + +static int +compress(u_char * source, u_char * dest, int len) +{ + int i, bitmask; + unsigned char *flagdest, flags, *orgdest; + + orgdest = dest; + while (len) { + flagdest = dest++; + flags = 0; /* All guess wrong initially */ + for (bitmask = 1, i = 0; i < 8 && len; i++, bitmask <<= 1) { + if (OutputGuessTable[oHash] == *source) { + flags |= bitmask; /* Guess was right - don't output */ + } else { + OutputGuessTable[oHash] = *source; + *dest++ = *source; /* Guess wrong, output char */ + } + OHASH(*source++); + len--; + } + *flagdest = flags; + } + return (dest - orgdest); +} + +static void +SyncTable(u_char * source, u_char * dest, int len) +{ + + while (len--) { + if (InputGuessTable[iHash] != *source) { + InputGuessTable[iHash] = *source; + } + IHASH(*dest++ = *source++); + } +} + +static int +decompress(u_char * source, u_char * dest, int len) +{ + int i, bitmask; + unsigned char flags, *orgdest; + + orgdest = dest; + while (len) { + flags = *source++; + len--; + for (i = 0, bitmask = 1; i < 8; i++, bitmask <<= 1) { + if (flags & bitmask) { + *dest = InputGuessTable[iHash]; /* Guess correct */ + } else { + if (!len) + break; /* we seem to be really done -- cabo */ + InputGuessTable[iHash] = *source; /* Guess wrong */ + *dest = *source++; /* Read from source */ + len--; + } + IHASH(*dest++); + } + } + return (dest - orgdest); +} + +void +Pred1Init(int direction) +{ + if (direction & 1) { /* Input part */ + iHash = 0; + memset(InputGuessTable, '\0', sizeof(InputGuessTable)); + } + if (direction & 2) { /* Output part */ + oHash = 0; + memset(OutputGuessTable, '\0', sizeof(OutputGuessTable)); + } +} + +void +Pred1Output(int pri, u_short proto, struct mbuf * bp) +{ + 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); + 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); + fcs = ~fcs; + + len = compress(bufp + 2, wp, orglen); + LogPrintf(LogDEBUG, "Pred1Output: orglen (%d) --> len (%d)\n", orglen, len); + CcpInfo.orgout += orglen; + if (len < orglen) { + *hp |= 0x80; + wp += len; + CcpInfo.compout += len; + } else { + memcpy(wp, bufp + 2, orglen); + wp += orglen; + CcpInfo.compout += orglen; + } + + *wp++ = fcs & 0377; + *wp++ = fcs >> 8; + mwp->cnt = wp - MBUF_CTOP(mwp); + HdlcOutput(PRI_NORMAL, PROTO_COMPD, mwp); +} + +void +Pred1Input(struct mbuf * bp) +{ + u_char *cp, *pp; + int len, olen, len1; + struct mbuf *wp; + u_char *bufp; + u_short fcs, proto; + + wp = mballoc(MAX_MTU + 2, MB_IPIN); + cp = MBUF_CTOP(bp); + olen = plength(bp); + pp = bufp = MBUF_CTOP(wp); + *pp++ = *cp & 0177; + len = *cp++ << 8; + *pp++ = *cp; + len += *cp++; + CcpInfo.orgin += len & 0x7fff; + if (len & 0x8000) { + len1 = decompress(cp, pp, olen - 4); + CcpInfo.compin += olen; + len &= 0x7fff; + if (len != len1) { /* Error is detected. Send reset request */ + LogPrintf(LogLCP, "%s: Length Error\n", CcpFsm.name); + CcpSendResetReq(&CcpFsm); + pfree(bp); + pfree(wp); + return; + } + cp += olen - 4; + pp += len1; + } else { + CcpInfo.compin += len; + SyncTable(cp, pp, len); + cp += len; + pp += len; + } + *pp++ = *cp++; /* CRC */ + *pp++ = *cp++; + fcs = HdlcFcs(INITFCS, bufp, wp->cnt = pp - bufp); + if (fcs != GOODFCS) + LogPrintf(LogDEBUG, "Pred1Input: fcs = 0x%04x (%s), len = 0x%x," + " olen = 0x%x\n", fcs, (fcs == GOODFCS) ? "good" : "bad", + len, olen); + if (fcs == GOODFCS) { + wp->offset += 2; /* skip length */ + wp->cnt -= 4; /* skip length & CRC */ + pp = MBUF_CTOP(wp); + proto = *pp++; + if (proto & 1) { + wp->offset++; + wp->cnt--; + } else { + wp->offset += 2; + wp->cnt -= 2; + proto = (proto << 8) | *pp++; + } + DecodePacket(proto, wp); + } else { + LogDumpBp(LogHDLC, "Bad FCS", wp); + CcpSendResetReq(&CcpFsm); + pfree(wp); + } + pfree(bp); +} diff --git a/usr.sbin/ppp/pred.h b/usr.sbin/ppp/pred.h new file mode 100644 index 00000000000..74502d2001b --- /dev/null +++ b/usr.sbin/ppp/pred.h @@ -0,0 +1,25 @@ +/* + * 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: pred.h,v 1.1 1997/11/23 20:27:35 brian Exp $ + * + * TODO: + */ + +extern void Pred1Output(int, u_short, struct mbuf *); +extern void Pred1Input(struct mbuf *); +extern void Pred1Init(int); diff --git a/usr.sbin/ppp/route.c b/usr.sbin/ppp/route.c new file mode 100644 index 00000000000..f86ca6114a1 --- /dev/null +++ b/usr.sbin/ppp/route.c @@ -0,0 +1,484 @@ +/* + * PPP Routing related 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: route.c,v 1.1 1997/11/23 20:27:35 brian Exp $ + * + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <net/if_types.h> +#include <net/route.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if_dl.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 "command.h" +#include "mbuf.h" +#include "log.h" +#include "loadalias.h" +#include "defs.h" +#include "vars.h" +#include "id.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) +{ + struct rtmsg rtmes; + int s, nb, wb; + char *cp; + const char *cmdstr; + u_long *lp; + struct sockaddr_in rtdata; + + 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 | RTA_NETMASK; + 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 (gateway.s_addr) { + 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; + + lp = (u_long *) cp; + + if (mask.s_addr) { + *lp++ = 8; + cp += sizeof(int); + *lp = mask.s_addr; + } else + *lp = 0; + cp += sizeof(u_long); + + nb = cp - (char *) &rtmes; + rtmes.m_rtm.rtm_msglen = nb; + wb = write(s, &rtmes, nb); + if (wb < 0) { + 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)); + switch (rtmes.m_rtm.rtm_errno) { + case EEXIST: + LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); + break; + case ESRCH: + LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); + break; + case 0: + LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); + break; + case ENOBUFS: + default: + LogPrintf(LogTCPIP, "%s route failed: %s\n", + cmdstr, strerror(rtmes.m_rtm.rtm_errno)); + break; + } + } + LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", + wb, cmdstr, dst.s_addr, gateway.s_addr); + close(s); +} + +static void +p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) +{ + char buf[29]; + const char *cp; + struct sockaddr_in *ihost = (struct sockaddr_in *)phost; + struct sockaddr_in *mask = (struct sockaddr_in *)pmask; + struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; + + switch (phost->sa_family) { + case AF_INET: + if (!phost) + cp = ""; + else if (ihost->sin_addr.s_addr == INADDR_ANY) + cp = "default"; + else if (!mask) + cp = inet_ntoa(ihost->sin_addr); + else { + u_int msk = ntohl(mask->sin_addr.s_addr); + u_int tst; + int bits; + int len; + struct sockaddr_in net; + + for (tst = 1, bits=32; tst; tst <<= 1, bits--) + if (msk & tst) + break; + + 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; + sprintf(buf, "%s", inet_ntoa(net.sin_addr)); + 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); + else + sprintf(buf+strlen(buf), "/%d", bits); + cp = buf; + } + break; + + case AF_LINK: + if (!dl) + cp = ""; + else if (dl->sdl_nlen == 0 && dl->sdl_alen == 0 && dl->sdl_slen == 0) { + sprintf(buf, "link#%d", dl->sdl_index); + cp = buf; + } else if (dl->sdl_type == IFT_ETHER && dl->sdl_alen && + dl->sdl_alen < sizeof(buf)/3) { + int f; + u_char *MAC; + + MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; + for (f = 0; f < dl->sdl_alen; f++) + sprintf(buf+f*3, "%02x:", MAC[f]); + buf[f*3-1] = '\0'; + cp = buf; + } else + cp = "???"; + break; + + default: + cp = "???"; + break; + } + + fprintf(VarTerm, "%-*s ", width-1, cp); +} + +struct bits { + u_long b_mask; + char b_val; +} bits[] = { + + { RTF_UP, 'U' }, + { RTF_GATEWAY, 'G' }, + { RTF_HOST, 'H' }, + { RTF_REJECT, 'R' }, + { RTF_DYNAMIC, 'D' }, + { RTF_MODIFIED, 'M' }, + { RTF_DONE, 'd' }, + { RTF_CLONING, 'C' }, + { RTF_XRESOLVE, 'X' }, + { RTF_LLINFO, 'L' }, + { RTF_STATIC, 'S' }, + { RTF_PROTO1, '1' }, + { RTF_PROTO2, '2' }, + { RTF_BLACKHOLE, 'B' }, +#ifdef __FreeBSD__ + { RTF_WASCLONED, 'W' }, + { RTF_PRCLONING, 'c' }, + { RTF_PROTO3, '3' }, + { RTF_BROADCAST, 'b' }, +#endif + { 0, '\0' } +}; + +static void +p_flags(u_long f, const char *format) +{ + if (VarTerm) { + char name[33], *flags; + register struct bits *p = bits; + + for (flags = name; p->b_mask; p++) + if (p->b_mask & f) + *flags++ = p->b_val; + *flags = '\0'; + fprintf(VarTerm, format, name); + } +} + +static const char * +Index2Nam(int idx) +{ + static char ifs[50][6]; + static int nifs, debug_done; + + if (!nifs) { + int mib[6], needed, len; + char *buf, *ptr, *end; + struct sockaddr_dl *dl; + struct if_msghdr *ifm; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_IFLIST; + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); + return "???"; + } + if ((buf = malloc(needed)) == NULL) + return "???"; + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + free(buf); + return "???"; + } + end = buf + needed; + + for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { + ifm = (struct if_msghdr *)ptr; + dl = (struct sockaddr_dl *)(ifm + 1); + if (ifm->ifm_index > 0 && ifm->ifm_index <= sizeof(ifs)/sizeof(ifs[0]) + && ifs[ifm->ifm_index-1][0] == '\0') { + if ((len = dl->sdl_nlen) > sizeof(ifs[0])-1) + len = sizeof(ifs[0])-1; + strncpy(ifs[ifm->ifm_index-1], dl->sdl_data, len); + ifs[ifm->ifm_index-1][len] = '\0'; + if (len && nifs < ifm->ifm_index) + nifs = ifm->ifm_index; + } else if (LogIsKept(LogDEBUG)) + LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n", + ifm->ifm_index); + } + free(buf); + } + + if (LogIsKept(LogDEBUG) && !debug_done) { + int f; + + LogPrintf(LogDEBUG, "Found the following interfaces:\n"); + for (f = 0; f < nifs; f++) + if (*ifs[f] != '\0') + LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); + debug_done = 1; + } + + if (idx < 1 || idx > nifs || ifs[idx-1][0] == '\0') + return "???"; + + return ifs[idx-1]; +} + +int +ShowRoute(struct cmdargs const *arg) +{ + struct rt_msghdr *rtm; + struct sockaddr *sa_dst, *sa_gw, *sa_mask; + char *sp, *ep, *cp, *wp; + int needed; + int mib[6]; + + if (!VarTerm) + return 1; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + 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)); + 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)); + free(sp); + return (1); + } + ep = sp + needed; + + fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); + for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *) cp; + wp = (char *)(rtm+1); + + if (rtm->rtm_addrs & RTA_DST) { + sa_dst = (struct sockaddr *)wp; + wp += sa_dst->sa_len; + } else + sa_dst = NULL; + + if (rtm->rtm_addrs & RTA_GATEWAY) { + sa_gw = (struct sockaddr *)wp; + wp += sa_gw->sa_len; + } else + sa_gw = NULL; + + if (rtm->rtm_addrs & RTA_NETMASK) { + sa_mask = (struct sockaddr *)wp; + wp += sa_mask->sa_len; + } else + sa_mask = NULL; + + p_sockaddr(sa_dst, sa_mask, 20); + p_sockaddr(sa_gw, NULL, 20); + + p_flags(rtm->rtm_flags, "%-6.6s "); + fprintf(VarTerm, "%s\n", Index2Nam(rtm->rtm_index)); + } + free(sp); + return 0; +} + +/* + * Delete routes associated with our interface + */ +void +DeleteIfRoutes(int all) +{ + struct rt_msghdr *rtm; + struct sockaddr *sa; + struct in_addr sa_dst, sa_gw, sa_mask; + int needed; + char *sp, *cp, *ep; + u_char *wp; + int mib[6]; + + LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + LogPrintf(LogERROR, "DeleteIfRoutes: 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", + strerror(errno)); + free(sp); + return; + } + ep = sp + needed; + + 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), 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 && + (all || (rtm->rtm_flags & RTF_GATEWAY))) { + sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + wp = (u_char *) cp + rtm->rtm_msglen; + sa = (struct sockaddr *)((char *)sa + sa->sa_len); + if (sa->sa_family == AF_INET) { + LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); + sa_gw.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + sa = (struct sockaddr *)((char *)sa + sa->sa_len); + if (rtm->rtm_addrs & RTA_NETMASK) + sa_mask.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + else + sa_mask.s_addr = 0xffffffff; + if (sa_dst.s_addr == INADDR_ANY) + sa_mask.s_addr = INADDR_ANY; + LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(sa_dst)); + LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(sa_gw)); + LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); + OsSetRoute(RTM_DELETE, sa_dst, sa_gw, sa_mask); + } else + LogPrintf(LogDEBUG, "DeleteIfRoutes: Can't remove an AF_LINK !\n"); + } + } + free(sp); +} + +int +GetIfIndex(char *name) +{ + int idx; + const char *got; + + idx = 1; + while (strcmp(got = Index2Nam(idx), "???")) + if (!strcmp(got, name)) + return IfIndex = idx; + else + idx++; + return -1; +} diff --git a/usr.sbin/ppp/route.h b/usr.sbin/ppp/route.h new file mode 100644 index 00000000000..8a2629042be --- /dev/null +++ b/usr.sbin/ppp/route.h @@ -0,0 +1,27 @@ +/* + * 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 1997/11/23 20:27:35 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); +extern void DeleteIfRoutes(int); diff --git a/usr.sbin/ppp/server.c b/usr.sbin/ppp/server.c new file mode 100644 index 00000000000..73994726344 --- /dev/null +++ b/usr.sbin/ppp/server.c @@ -0,0 +1,145 @@ +/* + * $Id: server.c,v 1.1 1997/11/23 20:27:36 brian Exp $ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.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(LogERROR, "Local: Can't open socket %s: No password " + "in ppp.secret\n", name); + return 1; + } + + if (mode & MODE_INTER) { + LogPrintf(LogERROR, "Local: Can't open socket in interactive mode\n"); + return 1; + } + + 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); + ID0unlink(name); + 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(LogERROR, "Tcp: Can't open socket %d: No password " + "in ppp.secret\n", port); + return 6; + } + + if (mode & MODE_INTER) { + LogPrintf(LogERROR, "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; + } + 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/server.h b/usr.sbin/ppp/server.h new file mode 100644 index 00000000000..347b23fc978 --- /dev/null +++ b/usr.sbin/ppp/server.h @@ -0,0 +1,9 @@ +/* + * $Id: server.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + */ + +extern int server; + +extern int ServerLocalOpen(const char *, mode_t); +extern int ServerTcpOpen(int); +extern void ServerClose(void); diff --git a/usr.sbin/ppp/sig.c b/usr.sbin/ppp/sig.c new file mode 100644 index 00000000000..c7c0dab062e --- /dev/null +++ b/usr.sbin/ppp/sig.c @@ -0,0 +1,73 @@ +/* + * $Id: sig.c,v 1.1 1997/11/23 20:27:36 brian Exp $ + */ + +#include <sys/types.h> + +#include <signal.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "sig.h" + +static caused[NSIG]; /* An array of pending signals */ +static sig_type handler[NSIG]; /* all start at SIG_DFL */ + + +/* Record a signal in the "caused" array */ + +static void +signal_recorder(int sig) +{ + caused[sig - 1]++; +} + + +/* + * Set up signal_recorder, and record handler as the function to ultimately + * call in handle_signal() +*/ + +sig_type +pending_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", + __FILE__, __LINE__); + return signal(sig, fn); + } + Result = handler[sig - 1]; + if (fn == SIG_DFL || fn == SIG_IGN) { + signal(sig, fn); + handler[sig - 1] = (sig_type) 0; + } else { + handler[sig - 1] = fn; + signal(sig, signal_recorder); + } + caused[sig - 1] = 0; + return Result; +} + + +/* Call the handlers for any pending signals */ + +void +handle_signals() +{ + int sig; + int got; + + do { + got = 0; + for (sig = 0; sig < NSIG; sig++) + if (caused[sig]) { + caused[sig]--; + got++; + (*handler[sig]) (sig + 1); + } + } while (got); +} diff --git a/usr.sbin/ppp/sig.h b/usr.sbin/ppp/sig.h new file mode 100644 index 00000000000..9d2744dd01c --- /dev/null +++ b/usr.sbin/ppp/sig.h @@ -0,0 +1,11 @@ +/* + * $Id: sig.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + */ + +typedef void (*sig_type)(int); + +/* Call this instead of signal() */ +extern sig_type pending_signal(int, sig_type); + +/* Call this when you want things to *actually* happen */ +extern void handle_signals(void); diff --git a/usr.sbin/ppp/slcompress.c b/usr.sbin/ppp/slcompress.c new file mode 100644 index 00000000000..391ea214cec --- /dev/null +++ b/usr.sbin/ppp/slcompress.c @@ -0,0 +1,587 @@ +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * 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 University of California, Berkeley. The name of the + * University 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: slcompress.c,v 1.1 1997/11/23 20:27:36 brian Exp $ + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#include <sys/param.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netinet/ip.h> + +#include <stdio.h> +#include <string.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++; + +void +sl_compress_init(struct slcompress * comp, int max_state) +{ + register u_int i; + register struct cstate *tstate = comp->tstate; + + memset(comp, '\0', sizeof(*comp)); + for (i = max_state; i > 0; --i) { + tstate[i].cs_id = i; + tstate[i].cs_next = &tstate[i - 1]; + } + tstate[0].cs_next = &tstate[max_state]; + tstate[0].cs_id = 0; + comp->last_cs = &tstate[0]; + comp->last_recv = 255; + comp->last_xmit = 255; + comp->flags = SLF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero. ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ + if ((u_short)(n) >= 256) { \ + *cp++ = 0; \ + cp[1] = (n); \ + cp[0] = (n) >> 8; \ + cp += 2; \ + } else { \ + *cp++ = (n); \ + } \ +} +#define ENCODEZ(n) { \ + if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ + *cp++ = 0; \ + cp[1] = (n); \ + cp[0] = (n) >> 8; \ + cp += 2; \ + } else { \ + *cp++ = (n); \ + } \ +} + +#define DECODEL(f) { \ + if (*cp == 0) {\ + (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ + cp += 3; \ + } else { \ + (f) = htonl(ntohl(f) + (u_long)*cp++); \ + } \ +} + +#define DECODES(f) { \ + if (*cp == 0) {\ + (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ + cp += 3; \ + } else { \ + (f) = htons(ntohs(f) + (u_long)*cp++); \ + } \ +} + +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = htons((cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = htons((u_long)*cp++); \ + } \ +} + + +u_char +sl_compress_tcp(struct mbuf * m, + struct ip * ip, + struct slcompress * comp, + int compress_cid) +{ + register struct cstate *cs = comp->last_cs->cs_next; + register u_int hlen = ip->ip_hl; + register struct tcphdr *oth; + register struct tcphdr *th; + register u_int deltaS, deltaA; + register u_int changes = 0; + u_char new_seq[16]; + register u_char *cp = new_seq; + + /* + * Bail if this is an IP fragment or if the TCP packet isn't `compressible' + * (i.e., ACK isn't set or some other control bit is set). (We assume that + * 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", + ip->ip_off, m->cnt); + LogDumpBp(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); + return (TYPE_IP); + } + + /* + * Packet is compressible -- we're going to send either a COMPRESSED_TCP or + * UNCOMPRESSED_TCP packet. Either way we need to locate (or create) the + * connection state. Special case the most recently used connection since + * 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]) { + + /* + * Wasn't the first -- search for it. + * + * States are kept in a circularly linked list with last_cs pointing to the + * end of the list. The list is kept in lru order by moving a state to + * the head of the list whenever it is referenced. Since the list is + * short and, empirically, the connection we want is almost always near + * the front, we locate states via linear search. If we don't find a + * state for the datagram, the oldest state is (re-)used. + */ + register struct cstate *lcs; + register struct cstate *lastcs = comp->last_cs; + + 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]) + goto found; + } while (cs != lastcs); + + /* + * Didn't find it -- re-use oldest cstate. Send an uncompressed packet + * that tells the other side what connection number we're using for this + * conversation. Note that since the state list is circular, the oldest + * state points to the newest and we only need to set last_cs to update + * the lru linkage. + */ + INCR(sls_misses) + comp->last_cs = lcs; +#define THOFFSET(th) (th->th_off) + hlen += th->th_off; + hlen <<= 2; + if (hlen > m->cnt) + return (TYPE_IP); + goto uncompressed; + +found: + + /* + * Found it -- move to the front on the connection list. + */ + if (cs == lastcs) + comp->last_cs = lcs; + else { + lcs->cs_next = cs->cs_next; + cs->cs_next = lastcs->cs_next; + lastcs->cs_next = cs; + } + } + + /* + * Make sure that only what we expect to change changed. The first line of + * the `if' checks the IP protocol version, header length & type of + * service. The 2nd line checks the "Don't fragment" bit. The 3rd line + * checks the time-to-live and protocol (the protocol check is unnecessary + * but costless). The 4th line checks the TCP header length. The 5th line + * checks IP options, if any. The 6th line checks TCP options, if any. If + * any of these things are different between the previous & current + * datagram, we send the current datagram `uncompressed'. + */ + oth = (struct tcphdr *) & ((int *) &cs->cs_ip)[hlen]; + deltaS = hlen; + hlen += th->th_off; + hlen <<= 2; + if (hlen > m->cnt) + return (TYPE_IP); + + if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] || + ((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] || + ((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] || + THOFFSET(th) != THOFFSET(oth) || + (deltaS > 5 && + memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || + (THOFFSET(th) > 5 && + memcmp(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) { + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The receiver expects + * changes in the order: urgent, window, ack, seq (the order minimizes the + * number of temporaries needed in this section of code). + */ + if (th->th_flags & TH_URG) { + deltaS = ntohs(th->th_urp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->th_urp != oth->th_urp) { + + /* + * argh! URG not set but urp changed -- a sensible implementation should + * never do this but RFC793 doesn't prohibit the change so we have to + * deal with it. + */ + goto uncompressed; + } + deltaS = (u_short) (ntohs(th->th_win) - ntohs(oth->th_win)); + if (deltaS) { + ENCODE(deltaS); + changes |= NEW_W; + } + deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); + if (deltaA) { + if (deltaA > 0xffff) { + goto uncompressed; + } + ENCODE(deltaA); + changes |= NEW_A; + } + deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); + if (deltaS) { + if (deltaS > 0xffff) { + goto uncompressed; + } + ENCODE(deltaS); + changes |= NEW_S; + } + switch (changes) { + + case 0: + + /* + * Nothing changed. If this packet contains data and the last one didn't, + * this is probably a data packet following an ack (normal on an + * interactive connection) and we send it compressed. Otherwise it's + * probably a retransmit, retransmitted ack or window probe. Send it + * uncompressed in case the other side missed the compressed version. + */ + if (ip->ip_len != cs->cs_ip.ip_len && + ntohs(cs->cs_ip.ip_len) == hlen) + break; + + /* (fall through) */ + + case SPECIAL_I: + case SPECIAL_D: + + /* + * actual changes match one of our special case encodings -- send packet + * uncompressed. + */ + goto uncompressed; + + case NEW_S | NEW_A: + if (deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + + deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + if (th->th_flags & TH_PUSH) + changes |= TCP_PUSH_BIT; + + /* + * Grab the cksum before we overwrite it below. Then update our state with + * this packet's header. + */ + deltaA = ntohs(th->th_sum); + memcpy(&cs->cs_ip, ip, hlen); + + /* + * We want to use the original packet as our compressed packet. (cp - + * new_seq) is the number of bytes we need for compressed sequence numbers. + * In addition we need one byte for the change mask, one for the connection + * id and two for the tcp checksum. So, (cp - new_seq) + 4 bytes of header + * are needed. hlen is how many bytes of the original packet to toss so + * subtract the two to get the new packet size. + */ + deltaS = cp - new_seq; + cp = (u_char *) ip; + + /* + * Since fastq traffic can jump ahead of the background traffic, we don't + * know what order packets will go on the line. In this case, we always + * send a "new" connection id so the receiver state stays synchronized. + */ + if (comp->last_xmit == cs->cs_id && compress_cid) { + hlen -= deltaS + 3; + cp += hlen; + *cp++ = changes; + } else { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + cp += hlen; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_id; + } + m->cnt -= hlen; + m->offset += hlen; + *cp++ = deltaA >> 8; + *cp++ = deltaA; + memcpy(cp, new_seq, deltaS); + INCR(sls_compressed) + return (TYPE_COMPRESSED_TCP); + + /* + * Update connection state cs & send uncompressed packet ('uncompressed' + * means a regular ip/tcp packet but with the 'conversation id' we hope to + * use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip, ip, hlen); + ip->ip_p = cs->cs_id; + comp->last_xmit = cs->cs_id; + return (TYPE_UNCOMPRESSED_TCP); +} + + +int +sl_uncompress_tcp(u_char ** bufp, + int len, + u_int type, + struct slcompress * comp) +{ + register u_char *cp; + register u_int hlen, changes; + register struct tcphdr *th; + register struct cstate *cs; + register struct ip *ip; + + switch (type) { + + case TYPE_UNCOMPRESSED_TCP: + ip = (struct ip *) * bufp; + if (ip->ip_p >= MAX_STATES) + goto bad; + cs = &comp->rstate[comp->last_recv = ip->ip_p]; + comp->flags &= ~SLF_TOSS; + ip->ip_p = IPPROTO_TCP; + + /* + * Calculate the size of the TCP/IP header and make sure that we don't + * overflow the space we have available for it. + */ + hlen = ip->ip_hl << 2; + if (hlen + sizeof(struct tcphdr) > len) + goto bad; + th = (struct tcphdr *) & ((char *) ip)[hlen]; + hlen += THOFFSET(th) << 2; + if (hlen > MAX_HDR) + goto bad; + memcpy(&cs->cs_ip, ip, hlen); + cs->cs_ip.ip_sum = 0; + cs->cs_hlen = hlen; + INCR(sls_uncompressedin) + return (len); + + default: + goto bad; + + case TYPE_COMPRESSED_TCP: + break; + } + /* We've got a compressed packet. */ + INCR(sls_compressedin) + cp = *bufp; + changes = *cp++; + LogPrintf(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) + goto bad; + + comp->flags &= ~SLF_TOSS; + comp->last_recv = *cp++; + } else { + + /* + * this packet has an implicit state index. If we've had a line error + * since the last time we got an explicit state index, we have to toss + * the packet. + */ + if (comp->flags & SLF_TOSS) { + INCR(sls_tossed) + return (0); + } + } + cs = &comp->rstate[comp->last_recv]; + hlen = cs->cs_ip.ip_hl << 2; + th = (struct tcphdr *) & ((u_char *) & cs->cs_ip)[hlen]; + th->th_sum = htons((*cp << 8) | cp[1]); + cp += 2; + if (changes & TCP_PUSH_BIT) + th->th_flags |= TH_PUSH; + else + th->th_flags &= ~TH_PUSH; + + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; + + th->th_ack = htonl(ntohl(th->th_ack) + i); + th->th_seq = htonl(ntohl(th->th_seq) + i); + } + break; + + case SPECIAL_D: + th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) + - cs->cs_hlen); + break; + + default: + if (changes & NEW_U) { + th->th_flags |= TH_URG; + DECODEU(th->th_urp) + } else + th->th_flags &= ~TH_URG; + if (changes & NEW_W) + DECODES(th->th_win) + if (changes & NEW_A) + DECODEL(th->th_ack) + if (changes & NEW_S) { + LogPrintf(LogDEBUG, "NEW_S: %02x, %02x, %02x\n", + *cp, cp[1], cp[2]); + DECODEL(th->th_seq) + } + break; + } + if (changes & NEW_I) { + DECODES(cs->cs_ip.ip_id) + } 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)); + + /* + * At this point, cp points to the first byte of data in the packet. If + * we're not aligned on a 4-byte boundary, copy the data down so the ip & + * tcp headers will be aligned. Then back up cp by the tcp/ip header + * length to make room for the reconstructed header (we assume the packet + * we were handed has enough space to prepend 128 bytes of header). Adjust + * the length to account for the new header & fill in the IP total length. + */ + len -= (cp - *bufp); + if (len < 0) + + /* + * we must have dropped some characters (crc should detect this but the + * old slip framing won't) + */ + goto bad; + +#ifdef notdef + if ((int) cp & 3) { + if (len > 0) + (void) bcopy(cp, (caddr_t) ((int) cp & ~3), len); + cp = (u_char *) ((int) cp & ~3); + } +#endif + + cp -= cs->cs_hlen; + len += cs->cs_hlen; + cs->cs_ip.ip_len = htons(len); + memcpy(cp, &cs->cs_ip, cs->cs_hlen); + *bufp = cp; + + /* recompute the ip header checksum */ + { + register u_short *bp = (u_short *) cp; + + for (changes = 0; hlen > 0; hlen -= 2) + changes += *bp++; + changes = (changes & 0xffff) + (changes >> 16); + changes = (changes & 0xffff) + (changes >> 16); + ((struct ip *) cp)->ip_sum = ~changes; + } + return (len); +bad: + comp->flags |= SLF_TOSS; + INCR(sls_errorin) + return (0); +} + +int +ReportCompress(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); + return 0; +} diff --git a/usr.sbin/ppp/slcompress.h b/usr.sbin/ppp/slcompress.h new file mode 100644 index 00000000000..17658efca26 --- /dev/null +++ b/usr.sbin/ppp/slcompress.h @@ -0,0 +1,134 @@ +/* + * 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. + * + * 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 University of California, Berkeley. The name of the + * University 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: slcompress.h,v 1.1 1997/11/23 20:27:36 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 */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP 0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP 0x80 +#define TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + struct cstate *cs_next; /* next most recently used cstate (xmit only) */ + u_short cs_hlen; /* size of hdr (receive only) */ + u_char cs_id; /* connection # associated with this state */ + u_char cs_filler; + union { + char csu_hdr[MAX_HDR]; + struct ip csu_ip; /* ip/tcp hdr from most recent packet */ + } slcs_u; +}; + +#define cs_ip slcs_u.csu_ip +#define cs_hdr slcs_u.csu_hdr + +/* + * all the state data for one serial line (we need one of these + * per line). + */ +struct slcompress { + struct cstate *last_cs; /* most recently used tstate */ + 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 */ +}; + +/* flag values */ +#define SLF_TOSS 1 /* tossing rcvd frames because of input err */ + +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 *); diff --git a/usr.sbin/ppp/systems.c b/usr.sbin/ppp/systems.c new file mode 100644 index 00000000000..a19ca4e1e07 --- /dev/null +++ b/usr.sbin/ppp/systems.c @@ -0,0 +1,368 @@ +/* + * System configuration routines + * + * 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: systems.c,v 1.1 1997/11/23 20:27:36 brian Exp $ + * + * TODO: + */ +#include <sys/param.h> +#include <netinet/in.h> + +#include <ctype.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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 "loadalias.h" +#include "ipcp.h" +#include "pathnames.h" +#include "vars.h" +#include "server.h" +#include "chat.h" +#include "systems.h" + +#define issep(ch) ((ch) == ' ' || (ch) == '\t') + +FILE * +OpenSecret(const char *file) +{ + FILE *fp; + char line[100]; + + 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); + return (fp); +} + +void +CloseSecret(FILE * fp) +{ + fclose(fp); +} + +/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ +static void +InterpretArg(char *from, char *to) +{ + const char *env; + char *ptr, *startto, *endto; + int len; + + startto = to; + endto = to + LINE_LEN - 1; + + while(issep(*from)) + from++; + if (*from == '~') { + ptr = strchr(++from, '/'); + len = ptr ? ptr - from : strlen(from); + if (len == 0) { + if ((env = getenv("HOME")) == NULL) + env = _PATH_PPP; + strncpy(to, env, endto - to); + } else { + struct passwd *pwd; + + strncpy(to, from, len); + to[len] = '\0'; + pwd = getpwnam(to); + if (pwd) + strncpy(to, pwd->pw_dir, endto-to); + else + strncpy(to, _PATH_PPP, endto - to); + endpwent(); + } + *endto = '\0'; + to += strlen(to); + from += len; + } + + while (to < endto && *from != '\0') { + if (*from == '$') { + if (from[1] == '$') { + *to = '\0'; /* For an empty var name below */ + from += 2; + } else if (from[1] == '{') { + ptr = strchr(from+2, '}'); + if (ptr) { + len = ptr - from - 2; + if (endto - to < len ) + len = endto - to; + if (len) { + strncpy(to, from+2, len); + to[len] = '\0'; + from = ptr+1; + } else { + *to++ = *from++; + continue; + } + } else { + *to++ = *from++; + continue; + } + } else { + ptr = to; + for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++) + *ptr++ = *from; + *ptr = '\0'; + } + if (*to == '\0') + *to++ = '$'; + else if ((env = getenv(to)) != NULL) { + strncpy(to, env, endto - to); + *endto = '\0'; + to += strlen(to); + } + } else + *to++ = *from++; + } + while (to > startto) { + to--; + if (!issep(*to)) { + to++; + break; + } + } + *to = '\0'; +} + +#define CTRL_UNKNOWN (0) +#define CTRL_INCLUDE (1) + +static int +DecodeCtrlCommand(char *line, char *arg) +{ + if (!strncasecmp(line, "include", 7) && issep(line[7])) { + InterpretArg(line+8, arg); + return CTRL_INCLUDE; + } + return CTRL_UNKNOWN; +} + +static int userok; + +int +AllowUsers(struct cmdargs const *arg) +{ + int f; + char *user; + + userok = 0; + user = getlogin(); + if (user && *user) + for (f = 0; f < arg->argc; f++) + if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) { + userok = 1; + break; + } + + 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; + + 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, "%s: Invalid mode\n", arg->argv[f]); + } + + modeok = (mode | allowed) == allowed ? 1 : 0; + return 0; +} + +static int +ReadSystem(const char *name, const char *file, int doexec) +{ + FILE *fp; + char *cp, *wp; + int n, len; + u_char olauth; + char line[LINE_LEN]; + char filename[200]; + int linenum; + int argc; + char **argv; + int allowcmd; + + if (*file == '/') + snprintf(filename, sizeof filename, "%s", file); + else + 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); + return (-1); + } + LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); + + linenum = 0; + while (fgets(line, sizeof(line), fp)) { + linenum++; + cp = line; + switch (*cp) { + case '#': /* comment */ + break; + case ' ': + case '\t': + break; + default: + wp = strpbrk(cp, ":\n"); + if (wp == NULL) { + LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", + filename, linenum); + ServerClose(); + exit(1); + } + *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(LogCOMMAND, "%s: %s: Invalid command\n", name, cp); + break; + } + } 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) + 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); + } + break; + } + } + fclose(fp); + return -1; +} + +int +ValidSystem(const char *name) +{ + if (ID0realuid() == 0) + return userok = modeok = 1; + userok = 0; + modeok = 1; + ReadSystem("default", CONFFILE, 0); + if (name != NULL) + ReadSystem(name, CONFFILE, 0); + return userok && modeok; +} + +int +SelectSystem(const char *name, const char *file) +{ + 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: 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; +} diff --git a/usr.sbin/ppp/systems.h b/usr.sbin/ppp/systems.h new file mode 100644 index 00000000000..cf75015f987 --- /dev/null +++ b/usr.sbin/ppp/systems.h @@ -0,0 +1,31 @@ +/* + * 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: systems.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + * + */ + +extern int SelectSystem(const char *, const char *); +extern int ValidSystem(const char *); +extern FILE *OpenSecret(const char *); +extern void CloseSecret(FILE *); +extern int AllowUsers(struct cmdargs const *); +extern int AllowModes(struct cmdargs const *); +extern int LoadCommand(struct cmdargs const *); +extern int SaveCommand(struct cmdargs const *); diff --git a/usr.sbin/ppp/throughput.c b/usr.sbin/ppp/throughput.c new file mode 100644 index 00000000000..da0311fb2d9 --- /dev/null +++ b/usr.sbin/ppp/throughput.c @@ -0,0 +1,127 @@ +/* + * $Id: throughput.c,v 1.1 1997/11/23 20:27:37 brian Exp $ + */ + +#include <sys/param.h> + +#include <stdio.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" + +void +throughput_init(struct pppThroughput *t) +{ + int f; + + t->OctetsIn = t->OctetsOut = 0; + for (f = 0; f < SAMPLE_PERIOD; f++) + t->SampleOctets[f] = 0; + t->OctetsPerSecond = t->BestOctetsPerSecond = t->nSample = 0; + throughput_stop(t); +} + +void +throughput_disp(struct pppThroughput *t, FILE *f) +{ + int secs_up; + + secs_up = time(NULL) - t->uptime; + fprintf(f, "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); + } else + fprintf(f, "Overall %ld bytes/sec\n", (t->OctetsIn+t->OctetsOut)/secs_up); +} + + +void +throughput_log(struct pppThroughput *t, int level, const char *title) +{ + if (t->uptime) { + int secs_up; + + secs_up = time(NULL) - t->uptime; + if (title) + LogPrintf(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", + 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); + else + LogPrintf(level, " total %ld bytes/sec\n", + (t->OctetsIn+t->OctetsOut)/secs_up); + } +} + +static void +throughput_sampler(void *v) +{ + struct pppThroughput *t = (struct pppThroughput *)v; + u_long old; + + StopTimer(&t->Timer); + t->Timer.state = TIMER_STOPPED; + + 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) + t->BestOctetsPerSecond = t->OctetsPerSecond; + if (++t->nSample == SAMPLE_PERIOD) + t->nSample = 0; + + StartTimer(&t->Timer); +} + +void +throughput_start(struct pppThroughput *t) +{ + throughput_init(t); + time(&t->uptime); + if (Enabled(ConfThroughput)) { + t->Timer.state = TIMER_STOPPED; + t->Timer.load = SECTICKS; + t->Timer.func = throughput_sampler; + t->Timer.arg = t; + StartTimer(&t->Timer); + } +} + +void +throughput_stop(struct pppThroughput *t) +{ + if (Enabled(ConfThroughput)) + StopTimer(&t->Timer); +} + +void +throughput_addin(struct pppThroughput *t, int n) +{ + t->OctetsIn += n; +} + +void +throughput_addout(struct pppThroughput *t, int n) +{ + t->OctetsOut += n; +} diff --git a/usr.sbin/ppp/throughput.h b/usr.sbin/ppp/throughput.h new file mode 100644 index 00000000000..d255c15bcbe --- /dev/null +++ b/usr.sbin/ppp/throughput.h @@ -0,0 +1,24 @@ +/* + * $Id: throughput.h,v 1.1 1997/11/23 20:27:37 brian Exp $ + */ + +#define SAMPLE_PERIOD 5 + +struct pppThroughput { + time_t uptime; + u_long OctetsIn; + u_long OctetsOut; + u_long SampleOctets[SAMPLE_PERIOD]; + int OctetsPerSecond; + int BestOctetsPerSecond; + int nSample; + struct pppTimer Timer; +}; + +extern void throughput_init(struct pppThroughput *); +extern void throughput_disp(struct pppThroughput *, FILE *); +extern void throughput_log(struct pppThroughput *, int, const char *); +extern void throughput_start(struct pppThroughput *); +extern void throughput_stop(struct pppThroughput *); +extern void throughput_addin(struct pppThroughput *, int); +extern void throughput_addout(struct pppThroughput *, int); diff --git a/usr.sbin/ppp/timer.c b/usr.sbin/ppp/timer.c new file mode 100644 index 00000000000..ebb4cd4453b --- /dev/null +++ b/usr.sbin/ppp/timer.c @@ -0,0 +1,296 @@ +/* + * PPP Timer 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: timer.c,v 1.1 1997/11/23 20:27:36 brian Exp $ + * + * TODO: + */ + +#include <signal.h> +#ifdef SIGALRM +#include <errno.h> +#endif +#include <sys/time.h> +#include <stdio.h> +#include <unistd.h> + +#include "command.h" +#include "mbuf.h" +#include "log.h" +#include "defs.h" +#include "sig.h" +#include "timer.h" + +struct pppTimer *TimerList = NULL; + +static void StopTimerNoBlock(struct pppTimer *); +static void InitTimerService(void); + +void +StopTimer(struct pppTimer * tp) +{ +#ifdef SIGALRM + int omask; + + omask = sigblock(sigmask(SIGALRM)); +#endif + StopTimerNoBlock(tp); +#ifdef SIGALRM + sigsetmask(omask); +#endif +} + +void +StartTimer(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) { + StopTimerNoBlock(tp); + } + if (tp->load == 0) { + LogPrintf(LogDEBUG, "timer %x has 0 load!\n", 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; + pt = t; + } + + tp->state = TIMER_RUNNING; + tp->rest = tp->load - ticks; + LogPrintf(LogDEBUG, "StartTimer: Inserting %x before %x, rest = %d\n", + tp, t, tp->rest); + /* Insert given *tp just before *t */ + tp->next = t; + if (pt) { + pt->next = tp; + } else { + InitTimerService(); + TimerList = tp; + } + if (t) + t->rest -= tp->rest; + +#ifdef SIGALRM + sigsetmask(omask); +#endif +} + +static void +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) + */ + 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; + return; + } + pt = NULL; + for (t = TimerList; t != tp && t != NULL; t = t->next) + pt = t; + if (t) { + if (pt) { + pt->next = t->next; + } else { + TimerList = t->next; + if (TimerList == NULL) /* Last one ? */ + TermTimerService(); /* Terminate Timer Service */ + } + if (t->next) + t->next->rest += tp->rest; + } else + LogPrintf(LogERROR, "Oops, timer not found!!\n"); + + tp->next = NULL; + tp->state = TIMER_STOPPED; +} + +void +TimerService() +{ + struct pppTimer *tp, *exp, *wt; + + if (LogIsKept(LogDEBUG)) + ShowTimers(); + tp = TimerList; + if (tp) { + tp->rest--; + if (tp->rest == 0) { + + /* + * Multiple timers may expires at once. Create list of expired timers. + */ + exp = NULL; + do { + tp->state = TIMER_EXPIRED; + 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); + + /* + * Process all expired timers. + */ + while (exp) { +#ifdef notdef + StopTimer(exp); +#endif + if (exp->func) + (*exp->func) (exp->arg); + + /* + * Just Removing each item from expired list And exp->enext will be + * intialized at next expire in this funtion. + */ + exp = exp->enext; + } + } + } +} + +void +ShowTimers() +{ + 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 +u_int +nointr_sleep(u_int sec) +{ + struct timeval to, st, et; + long sld, nwd, std; + + gettimeofday(&st, NULL); + to.tv_sec = sec; + to.tv_usec = 0; + std = st.tv_sec * 1000000 + st.tv_usec; + for (;;) { + if (select(0, NULL, NULL, NULL, &to) == 0 || + errno != EINTR) { + break; + } else { + gettimeofday(&et, NULL); + sld = to.tv_sec * 1000000 + to.tv_sec; + nwd = et.tv_sec * 1000000 + et.tv_usec - std; + if (sld > nwd) + sld -= nwd; + else + sld = 1; /* Avoid both tv_sec/usec is 0 */ + + /* Calculate timeout value for select */ + to.tv_sec = sld / 1000000; + to.tv_usec = sld % 1000000; + } + } + return (0L); +} + +void +nointr_usleep(u_int usec) +{ + struct timeval to, st, et; + long sld, nwd, std; + + gettimeofday(&st, NULL); + to.tv_sec = 0; + to.tv_usec = usec; + std = st.tv_sec * 1000000 + st.tv_usec; + for (;;) { + if (select(0, NULL, NULL, NULL, &to) == 0 || + errno != EINTR) { + break; + } else { + gettimeofday(&et, NULL); + sld = to.tv_sec * 1000000 + to.tv_sec; + nwd = et.tv_sec * 1000000 + et.tv_usec - std; + if (sld > nwd) + sld -= nwd; + else + sld = 1; /* Avoid both tv_sec/usec is 0 */ + + /* Calculate timeout value for select */ + to.tv_sec = sld / 1000000; + to.tv_usec = sld % 1000000; + + } + } +} + +static void +InitTimerService() +{ + struct itimerval itimer; + + pending_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"); +} + +void +TermTimerService(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); +} + +#endif diff --git a/usr.sbin/ppp/timer.h b/usr.sbin/ppp/timer.h new file mode 100644 index 00000000000..cf11adbe104 --- /dev/null +++ b/usr.sbin/ppp/timer.h @@ -0,0 +1,51 @@ +/* + * 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: timer.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + * + * TODO: + */ + +#define TICKUNIT 100000 /* Unit in usec */ +#define SECTICKS (1000000/TICKUNIT) + +struct pppTimer { + int state; + u_long rest; /* Ticks to expire */ + u_long load; /* Initial load value */ + void (*func)(void *); /* Function called when timer is expired */ + void *arg; /* Argument passed to timeout function */ + struct pppTimer *next; /* Link to next timer */ + struct pppTimer *enext; /* Link to next expired timer */ +}; + +#define TIMER_STOPPED 0 +#define TIMER_RUNNING 1 +#define TIMER_EXPIRED 2 + +extern struct pppTimer *TimerList; + +extern void StartTimer(struct pppTimer *); +extern void StopTimer(struct pppTimer *); +extern void TimerService(void); +extern void TermTimerService(void); +extern void ShowTimers(void); + +#ifdef SIGALRM +extern u_int nointr_sleep(u_int); +extern void nointr_usleep(u_int); +#endif diff --git a/usr.sbin/ppp/tun.c b/usr.sbin/ppp/tun.c new file mode 100644 index 00000000000..2cf21ca4dd1 --- /dev/null +++ b/usr.sbin/ppp/tun.c @@ -0,0 +1,46 @@ +/* + * $Id: tun.c,v 1.1 1997/11/23 20:27:37 brian Exp $ + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <net/if.h> +#ifdef __FreeBSD__ +#include <net/if_var.h> +#endif +#include <net/if_tun.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 "hdlc.h" +#include "defs.h" +#include "loadalias.h" +#include "vars.h" +#include "tun.h" + +void +tun_configure(int mtu, int speed) +{ + struct tuninfo info; + + info.type = 23; + info.mtu = mtu; + if (VarPrefMTU != 0 && VarPrefMTU < mtu) + info.mtu = VarPrefMTU; + info.baudrate = 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", + strerror(errno)); +} diff --git a/usr.sbin/ppp/tun.h b/usr.sbin/ppp/tun.h new file mode 100644 index 00000000000..ca31c8f66d6 --- /dev/null +++ b/usr.sbin/ppp/tun.h @@ -0,0 +1,20 @@ +/* + * $Id: tun.h,v 1.1 1997/11/23 20:27:36 brian Exp $ + */ + +struct tun_data { +#ifdef __OpenBSD__ + struct tunnel_header head; +#endif + u_char data[MAX_MRU]; +}; + +#ifdef __OpenBSD__ +#define tun_fill_header(f,proto) do { (f).head.tun_af = (proto); } while (0) +#define tun_check_header(f,proto) ((f).head.tun_af == (proto)) +#else +#define tun_fill_header(f,proto) do { } while (0) +#define tun_check_header(f,proto) (1) +#endif + +extern void tun_configure(int, int); diff --git a/usr.sbin/ppp/vars.c b/usr.sbin/ppp/vars.c new file mode 100644 index 00000000000..b7d6fcc88ea --- /dev/null +++ b/usr.sbin/ppp/vars.c @@ -0,0 +1,194 @@ +/* + * 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.1 1997/11/23 20:27:36 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.5"; +char VarLocalVersion[] = "$Date: 1997/11/23 20:27:36 $"; +int Utmp = 0; +int ipInOctets = 0; +int ipOutOctets = 0; +int ipKeepAlive = 0; +int ipConnectSecs = 0; +int ipIdleSecs = 0; +int reconnectState = RECON_UNKNOWN; +int reconnectCount = 0; + +/* + * Order of conf option is important. See vars.h. + */ +struct confdesc pppConfs[] = { + {"vjcomp", CONF_ENABLE, CONF_ACCEPT}, + {"lqr", CONF_DISABLE, CONF_ACCEPT}, + {"chap", CONF_DISABLE, CONF_ACCEPT}, + {"pap", CONF_DISABLE, CONF_ACCEPT}, + {"acfcomp", CONF_ENABLE, CONF_ACCEPT}, + {"protocomp", CONF_ENABLE, CONF_ACCEPT}, + {"pred1", CONF_ENABLE, CONF_ACCEPT}, + {"proxy", CONF_DISABLE, CONF_NONE}, + {"msext", CONF_DISABLE, CONF_NONE}, + {"passwdauth", CONF_DISABLE, CONF_NONE}, + {"utmp", CONF_ENABLE, CONF_NONE}, + {"throughput", CONF_DISABLE, 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, + OPEN_ACTIVE, 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 new file mode 100644 index 00000000000..018be321b2f --- /dev/null +++ b/usr.sbin/ppp/vars.h @@ -0,0 +1,204 @@ +/* + * 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.1 1997/11/23 20:27:37 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 ConfVjcomp 0 +#define ConfLqr 1 +#define ConfChap 2 +#define ConfPap 3 +#define ConfAcfcomp 4 +#define ConfProtocomp 5 +#define ConfPred1 6 +#define ConfProxy 7 +#define ConfMSExt 8 +#define ConfPasswdAuth 9 +#define ConfUtmp 10 +#define ConfThroughput 11 +#define MAXCONFS 12 + +#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_long var_mru; /* Initial MRU value */ + u_long 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_dev[40]; /* Name of device / host:port */ + const char *base_modem_dev; /* Pointer to base of modem_dev */ + int open_mode; /* LCP open mode */ +#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 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 ipInOctets; +extern int ipOutOctets; +extern int ipKeepAlive; +extern int ipConnectSecs; +extern int ipIdleSecs; +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/ppp/vjcomp.c b/usr.sbin/ppp/vjcomp.c new file mode 100644 index 00000000000..cf476040fc6 --- /dev/null +++ b/usr.sbin/ppp/vjcomp.c @@ -0,0 +1,155 @@ +/* + * Input/Output VJ Compressed packets + * + * 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: vjcomp.c,v 1.1 1997/11/23 20:27:37 brian Exp $ + * + * TODO: + */ +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.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 "slcompress.h" +#include "hdlc.h" +#include "ipcp.h" +#include "vjcomp.h" + +#define MAX_VJHEADER 16 /* Maximum size of compressed header */ + +struct slcompress cslc; + +void +VjInit(int max_state) +{ + sl_compress_init(&cslc, max_state); +} + +void +SendPppFrame(struct mbuf * bp) +{ + int type; + int proto; + int cproto = IpcpInfo.his_compproto >> 16; + + LogPrintf(LogDEBUG, "SendPppFrame: proto = %x\n", IpcpInfo.his_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); + switch (type) { + case TYPE_IP: + proto = PROTO_IP; + break; + case TYPE_UNCOMPRESSED_TCP: + proto = PROTO_VJUNCOMP; + break; + case TYPE_COMPRESSED_TCP: + proto = PROTO_VJCOMP; + break; + default: + LogPrintf(LogERROR, "Unknown frame type %x\n", type); + pfree(bp); + return; + } + } else + proto = PROTO_IP; + HdlcOutput(PRI_NORMAL, proto, bp); +} + +static struct mbuf * +VjUncompressTcp(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); + if (type == TYPE_UNCOMPRESSED_TCP) { + + /* + * Uncompressed packet does NOT change its size, so that we can use mbuf + * space for uncompression job. + */ + bufp = MBUF_CTOP(bp); + len = sl_uncompress_tcp(&bufp, len, type, &cslc); + if (len <= 0) { + pfree(bp); + bp = NULLBUFF; + } + return (bp); + } + + /* + * Handle compressed packet. 1) Read upto MAX_VJHEADER bytes into work + * space. 2) Try to uncompress it. 3) Compute amount of necesary space. 4) + * Copy unread data info there. + */ + if (len > MAX_VJHEADER) + len = MAX_VJHEADER; + rlen = len; + bufp = work + MAX_HDR; + bp = mbread(bp, bufp, rlen); + len = sl_uncompress_tcp(&bufp, olen, type, &cslc); + if (len <= 0) { + pfree(bp); + return NULLBUFF; + } + len -= olen; + len += rlen; + nbp = mballoc(len, MB_VJCOMP); + memcpy(MBUF_CTOP(nbp), bufp, len); + nbp->next = bp; + return (nbp); +} + +struct mbuf * +VjCompInput(struct mbuf * bp, int proto) +{ + u_char type; + + LogPrintf(LogDEBUG, "VjCompInput: proto %02x\n", proto); + LogDumpBp(LogDEBUG, "Raw packet info:", bp); + + switch (proto) { + case PROTO_VJCOMP: + type = TYPE_COMPRESSED_TCP; + break; + case PROTO_VJUNCOMP: + type = TYPE_UNCOMPRESSED_TCP; + break; + default: + LogPrintf(LogERROR, "VjCompInput...???\n"); + return (bp); + } + bp = VjUncompressTcp(bp, type); + return (bp); +} diff --git a/usr.sbin/ppp/vjcomp.h b/usr.sbin/ppp/vjcomp.h new file mode 100644 index 00000000000..4cc27aaf593 --- /dev/null +++ b/usr.sbin/ppp/vjcomp.h @@ -0,0 +1,7 @@ +/* + * $Id: vjcomp.h,v 1.1 1997/11/23 20:27:37 brian Exp $ + */ + +extern void VjInit(int); +extern void SendPppFrame(struct mbuf *); +extern struct mbuf *VjCompInput(struct mbuf *, int); |