slirp-1.0.17/0000755000175000017500000000000010433144545012010 5ustar roverroverslirp-1.0.17/CONTRIB0000644000175000017500000000073010115527015013025 0ustar roverroverThis specific build is a merge of two separate SLiRP updates-- Slirp 1.0c-KK ============= * Modified Feb 5 1998 by Karl Krueger * with instructions from Philip C. Tsao Slirp 1.0g ========== * See changelog. Numerous fixes. The merging was done by me, Dan Kaminsky(effugas@best.com). Any comments / fixes can be forwarded to either myself or Kelly Price(tygris+slirp@erols.com). Look for SLiRP on Freshmeat (http://www.freshmeat.net). slirp-1.0.17/COPYRIGHT0000644000175000017500000000570410115527015013303 0ustar roverroverSlirp was written by Danny Gasparovski. Copyright (c), 1995,1996 All Rights Reserved. Slirp is maintained by Kelly Price Slirp is free software; "free" as in you don't have to pay for it, and you are free to do whatever you want with it. I do not accept any donations, monetary or otherwise, for Slirp. Instead, I would ask you to pass this potential donation to your favorite charity. In fact, I encourage *everyone* who finds Slirp useful to make a small donation to their favorite charity (for example, GreenPeace). This is not a requirement, but a suggestion from someone who highly values the service they provide. The copyright terms and conditions: ---BEGIN--- Copyright (c) 1995,1996 Danny Gasparovski. 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 acknowledgment: This product includes software developed by Danny Gasparovski. THIS SOFTWARE IS PROVIDED ``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 DANNY GASPAROVSKI 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. ---END--- This basically means you can do anything you want with the software, except 1) call it your own, and 2) claim warranty on it. There is no warranty for this software. None. Nada. If you lose a million dollars while using Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. If these conditions cannot be met due to legal restrictions (E.g. where it is against the law to give out Software without warranty), you must cease using the software and delete all copies you have. Slirp uses code that is copyrighted by the following people/organizations: Juha Pirkola. Gregory M. Christy. The Regents of the University of California. Carnegie Mellon University. The Australian National University. RSA Data Security, Inc. Please read the top of each source file for the details on the various copyrights. slirp-1.0.17/ChangeLog0000644000175000017500000007053310117222431013560 0ustar roverroverVersion 1.0.16 RELEASE Sept 7, 2004 (RWP) From 1.0.14pre1 - Changes for operation under Cygwin - Added patch for Cygwin I_PUSH by Michael Wetherell - dns is now transferred to peer, (If compiled with -DUSE_MS_DNS) (Ripped off from hacked pppd version 2.2.0f) - Two dns options can be specified on command line, (Only the first is used internally, but both will get transferred to peer) - Has a hack for connecting to a MS direct cable connect (If compiled with -DMS_DCC) Only works when PPP (-P option) is chosen, but gives effectively a nat'ed direct cable connect. (A chat script option would be nicer) - Fix to exit code that incorrectly iterated list of tty's attached - Fixes to terminal restore code, No longer closes stdin on exit - If stdout, or stderr are redirected, it wont close them (so you can debug using fprintf(stderr...) - No longer removes 0's, 1's from incoming data stream - New Option nozeros to not look at strings of 0's, 1's to cause exit/suspend (See docs/CONFIG) - Can specify alternate tty on command line using "tty ttydevice" (Overrides SLIRP_TTY environment variable) (see docs/CONFIG) - Debug builds log raw incoming data, and ppp checksum fault packets - Minor documentation updates - Does not close all file handles, (Pain when trying to debug) - Can manually turn on early debugging in main() - Most of Tims security fixes in place, (It is still insecure...) Probably snprintf will make slirp less portable. (Sorry Tim, I don't like strncpy, so replaced them with a strncpy2) Version 1.0.13 RELEASE Sept 30, 2000 - Added a patch posted on SourceForge to use any arbitrary tty as a port instead of the console. - Fixed above patch to restore normal functionality by making the tty /dev/tty - Fixed the above fix by saving and restoring the tty state. * Anyone know about Secure sockets? Version 1.0.12 RELEASE August 30, 2000 - Fixed my patch to sync with Debian's version of Slirp. - Promised again not to "pull a Linus" -- aka releasing it and not testing it to make sure it was good. :P - Added ShengHuo ZHU's patches. RSH emulation added. Solaris 2.x should work in compiling. Version 1.0.11 RELEASE August 20, 2000 - Added a patch to sync with Debian's version of Slirp. - Fixed a typo with README.NEXT Version 1.0.10 RELASE May 27, 2000 - Moved the whole mess to SourceForge. The URL is slirp.sourceforge.net now. Updated docs. Version 1.0.9 RELEASE Feb 22, 2000 - Added some #ifdefs to fix bad compilation on Solaris i86 boxes. May also fix a few things with others. We'll find out soon. - Rearranged documentation - Added some warnings to the configure.in script about not using GCC for compiling anything. Seriously, folks, why don't you have GCC on your system? I've compiled it myself, and it's too eazy not to mess up. - Version numbering changed to be more Linux Kernelish. Version 1.0.8 (aka 1.0h) RELEASE (22/10/1999) - Switched from commenting out to the much saner #ifdefs. - Edited some of the documentation to point to new maintainer (me) Version 1.0g-dk1 BETA (18/10/99) - Merged in logwtmp, tcp connection closing fixes from "Slirp 1.0c-KK". Slirp compiles once again on Linux boxen. Version 1.0g RELEASE (13/08/99) - Cleanup of the ICMP code. No ICMP packets are generated on receipt of an ICMP packet with an error, except if the type is {0,8,[13-18]}. See RFC 1122. - Local host ping -f crash solved. Version 1.0f RELEASE (19/01/99) - UDP sorecvfrom(so) code: the timeout for domain name lookup (port 53) is not reset if recvfrom() returns an error. Zero size UDP packets are forwarded. Version 1.0e RELEASE (05/12/98) - Corrected a bug in the udp sorecvfrom(so) code. UDP packets were sent with udp_output() to the client even if the packet was received with an error. ICMP packets are generated in this case. - Debugged the EMU_CMD handling in tcp_input(). A telnet to the config port, default 10.0.2.0, could not be closed from the client side (only by typing quit at the prompt). The connection remained open and re-telnetting gave the message "Already connected". The tcp finite state machine went into the CLOSE WAIT state and waited forever for the non-existing remote socket to close. Solution : If a FIN is received and the socket is EMU_CTL, then the fsm goes directly to the LAST ACK state and sends an ACK + FIN (one packet). Version 1.0d RELEASE (19/8/98) - Fixed core dumping while reassembling ip packets found a bug in ip.h, ipasfrag.ipf_mff found an error in mbuf.c, dtom() - Added limited ICMP support. ICMP packets are generated when a bad IP packet is received (full support) an ICMP packet can not be imitated as a UDP packet sent to port 7 a UDP packet can not be sent, "Network is unreachable" a UDP packet is received with an error, usually "Port unreachable" a TCP connection can not be made, "Network is unreachable" Version 1.0c RELEASE (15/1/96) - Fixed a problem with chmod()ing Slirp's tty. - Fixed a problem with --disable-ppp. - Added the ability to have ranges in the "escape" command. So, for example, now you can use the command "escape 0-1f,ff" instead of "escape 0,1,2,3,...,1f,ff". - Added patches for HPUX for slirp.ftpd thanks to Jeff Thieleke . It's in slirp.ftpd-b.tar.gz in the "extra" directory at the usual Slirp ftp sites. - Added an updates man page, thanks to George Ferguson . It's in src/slirp.man. Version 1.0b RELEASE (4/1/96) - Fixed a few minor problems with compilation on some hosts. - Added a few more FAQs to the documentation (slirp.doc). - Fixed for systems without FIONBIO. - Fixed a small bug in add emu, thanks to gentile@netcom.com. - Changed the default baudrate to 115200. - Added the option "keepalive" and "keepalive S" which enables TCP keep-alives. This makes Slirp probe each TCP connection every minute or so, or if given an argument, every S seconds. - When load-balancing over multiple modems, you can now specify the password in the environmental variable SLIRP_PASSWORD, then give Slirp the arguements "-l x,host:port,-". This is for systems where the password is still seen in a "ps x" even though Slirp tries to hide it, like Solaris. - Add some performance enhancments to the load-balancing code, which includes the addition of the "towrite_max N" option, and updated the documentation accordingly. - Fixed for systems without fchmod(). - Added the option "ppp_exit" which will force Slirp to exit when PPP goes down. This way, if you type "exec slirp" from your shell prompt, when you kill your PPP software you will be logged out. Version 1.0a RELEASE (25/12/95) - Finally released version 1.0. Yipee! Please read the section "Thanks" in the file slirp.doc for a list of people I want to thank. - Revamped the documentation. All the README.* files have been removed and put into slirp.doc, with many other additions. Please read it. - Turned on Talk emulation by default. What the heck, why not? - Added IDENT emulation. Now incoming connections can be properly identified if your software uses the IDENT protocol. Thanks to TheGit for his help with this. Note: this is not complete yet. You can send queries, but the reply, while correct, won't be the right format for most programs. - Added emulation for RealAudio 2.0 thanks to Juha Pirkola. - Added the ability to load-balance over multiple hosts/accounts. - Fixed detection of SIGHUP on a unit other than 0. - Fixed a bug in fork_exec, thanks to Theodore Hope . - Lots of other minor fixes. Version 0.95j BETA (19/11/95) - Fixed a problem with --disable-ppp, thanks to Lynn Larrow . - Ooops! Forgot to uncomment a peice of code used in rlogin emulation. Rlogin should work properly now. - Added emulation for "ping". Pinging the remote host will work properly all the time (if slirp is actually working), but pinging other hosts may not work even if the host is up. This is because slirp uses UDP to "emulate" ping, not real ICMP ECHO-REQUEST packets which ping uses. - Lots of minor fixes thanks to Juha Pirkola. Version 0.95i BETA (16/11/95) - "Fixed" a problem with WNOHANG not being defined on OSF/1 systems, although it's not really fixed, thanks to Jeff Skone . - Fixed a redefinition error when net/if.h was #included, thanks to gruppo progetto -cds . - Fixed compilation on NeXT systems, thanks to Tomas Hurka . - Made chap and upap files ~/.chap-secrets and ~/.pap-secrets respectivaly. - Fixed a problem with sending a window of 0 on a SYN-ACK packet, which would cause problems with some TCP/IP stacks with certain programs (eg: Trumpet Winsock and mIRC) Thanks to Bjorn Eng for helping me find this problem. - Updated to ppp-2.2-RELEASE PPP code. - Added preliminary patches for better load-balancing support when the modems are not connected at the same speed. These will be finished when I am able to get access to a second modem/ph. line. #define FULL_BOLT in config.h if you wish to test it. - Added support for rlogin. (rsh and rexec may come soon) - Hopefully fixed the small-packet-syndrome once and for all! - Lots of other minor fixes. I hope this will be the last release before version 1.0. Version 0.95h BETA (10/9/95) - Fixed a rather nasty memory leak when BSD-compression was used. Thanks to Valtteri Vuorikoski for pointing it out, and Blake "Wacko" Wright for helping me fix it (again). - Fixed another rather nasty bug where urgent data could kill the connection. Thanks to Blake "spam me!" Wright for helping me fix it. - Fixed a third rather nasty bug which would corrupt uploads in certain situations (usually uploading large files). Thanks again to Blake "woody" Wright for helping find the problem. - Fixed the "password" option when placed in the ~/.slirprc file. - Fixed ./configure to recognise Unix sockets, thanks to Chris Metcalf. - Maybe fixed a PPP problem, thanks to Steve Kneizys . Version 0.95g ***BETA*** (26/8/95) - Fixed the baudrate bug in 0.95f. - Added a few more Motorola fixes. PLEASE NOTE: This is still *BETA* software. If you don't *need* to upgrade, *don't*! It *will* fail. Infact, I guarantee there are bugs in 0.95g. I know, I put them there! :) If you rely on slirp for your Internet connectivitiy, *wait* for a stable version. The most stable version so far is 0.9p (but it does lack a lot of features in the 0.95x releases). Version 0.95f BETA (24/8/95) - Fixed ./configure wrt unix-domain sockets. - Fixed DCC CHAT wrt mIRC (and possibly others) (thanks to Shawn Hecker for finding this problem). - "add emu" will now mark allready-connected sockets to be emulated. - Added a password to telnet 10.0.2.0. See the "password" option to set the password. (before entering any commands, you must enter "pass PASSWORD"). - Hopefully fixed OOB data ("Urgent data"). - Fixed a bug in if_input (thanks to Robert Smathers for helping find the problem). - Fixed a bug in main_loop() which should fix the problem with SCO's. (thanks to "Jamie C. Hellstrom" for helping find this problem) - Fixed an error with the baudrate calculation. Telnet should be more responsive now. (Thanks to Antti Toivonen for pointing this out). - Cleaned up a few things so it'll compile on more systems. - Fixed BSD compression to work with VJ compression, thanks to Juha Pirkola. - Made 2 fixes to get it to compile on Motorola SVR4, thanks to Mark Scott . - Fixed load-balancing on SunOS. - A few other changes and fixes. Version 0.95e BETA (2/8/95) - Fixed compression autodetection in SLIP. - Put the "compress" command back in. Please, do NOT use it unless slirp does not autodetect CSLIP for you (shouldn't happen... anymore :) - Fixed a stupid mistake I made for talk emulation. - Made slirp compile on systems without unix-domain sockets. However, without unix-domain sockets, you will not be able to restart nor use load-balancing. - Added more spellink paches from Chris Metcalf. Version 0.95d BETA (27/7/95) - Added more patches from Chris Metcalf, including OSF/1 patches. It should work on OSF/1 with gcc now. - Fixed a bug WRT multiple modems. You'd only be affected if your modems are not all the same speed. This may also improve single-modem performance, but I doubt it :) - Added talk/ytalk emulation thanks to Juha Pirkola. Note: it will only work for *outgoing* requests. Also, you need to enable it by editing config.h and defining EMULATE_TALK, since a rogue user *may* make slirp malloc() too much data. - Added emulation for RealAudio and CuSeeMe, thanks (again :) to Juha Pirkola. - Added the client program "supload" which acts a little like "tupload" in term. Read the file README.supload in the client/supload directory for instructions. - Fixed some configuration stuff, including mtu/mru to be recognised when PPP is not compiled into slirp. - Fixed a bug in (surprise!) SunOS, which would not terminate slirp upon loss of carrier. - Other stuff. Version 0.95c BETA (22/7/95) - Added patches for 64-bit systems from Chris Metcalf. - Made "redir" more flexible. Now you can use a service name instead of port to redirect to, and the (host's) port may be omitted, in which case a 0 is assumed. For example "redir ftp" is the same as the old "redir 0 21". You can also use the service name with "add exec", eg: "add exec nntpd:nntp". Version 0.95b BETA (21/7/95) - Added the command "wait" from Chris Metcalf, among other fixes (including a fatal SunOS bug... surprise, surprise) - Added patches from Wilson Cheung for BSDI. - Fixed the Slirp> prompt. - A few other things, I forget. Version 0.95a BETA (19/7/95) - Finished the load-balancing support as started in 0.9n. Read the file README.load-balancing for instructions on how to use it. Big thanks goes to Blake Wright bmwright@xmission.com for his patience in testing the code, since I only have one modem. As a result of the load-balancing support, the restart code has been "generalised", and changed. Please read the file README.restart to see how it has changed. - Revamped the header files. - Added the perl script mkpro, which automatically extracts prototypes from C source. - Revamped Makefile.in, configure.in, etc. - Revamped the README files and documentation. They still suck tho :) - Fixed a bug in slirp which would cause TCP/IP stacks with small receive windows (less than 8192) to lock up. This was only really seen in Trumpet Winsock because Linux/FreeBSD/etc. usually have a default window size >= 8192. - Changed the copyright of ppp.c (with Juha's permission), so now there is no more GPL'd code in the slirp package. - Updated portions of the TCP/IP code to FreeBSD 2.0.5. Most of the changes in 2.0.5 relate to T/TCP and hash lookup of the TCP/UDP control blocks. These updates are not all that beneficial to slirp, so I won't incorporate them yet. - Updated slirp's PPP code to use ppp-2.2b2. This fixes some PPP bugs and also adds niceties like compression, etc. provided your PPP software supports it. Note: the compression code does not work yet. It has been disabled by default, if you want to enable it, edit ppp/ppp-comp.h and change the #define of DO_BSD_COMPRESS to 1. Be aware that code in bsd-comp.c is covered by patents in the states and other countries (not Australia), so don't enable it if this bothers you. - Added link, tty, vj statistics. - Changed all the "ptr += ..." stuff to use lprint(). - Fixed a problem with slirp not choosing an optimal send and receive buffer, which would result in slirp sending different sized packets. - Fixed a bug in PPP which would sometimes bomb on uploads, thanks to Juha Pirkola. - Added the ability to emulate any service on any port ("add emu"). - Added more commands: "show X", "unit", "stats tty", "stats alltty", "stats vj", "dns", "log stats", "log start", "socket", among others. - Added 10.0.2.3 as an alias for your DNS (both UDP and TCP). Only use this if slirp guesses the correct DNS at the start, or you give it a "dns" command. - Made slirp chmod the tty device so that it will not receive talk/biff/etc. messages which would corrupt packets. - Added Chris Metcalf's regular per-release patches *before* releasing it. Clever, eh? :) Also thanks to Juha Pirkola for some pre-release bugfixes. - Added a "quit" command and a prompt to slirp's command-line. - Slirp's title has changed from "a (C)SLIP/PPP emulator" to the more descriptive "a TCP/IP emulator over the (C)SLIP/PPP link-level protocols". So there. :) - "redir X" has changed. You can now tell it which port to start looking for X redirections, and tell it to redirect to a specific X server. - Made the DISPLAY variable be automatically set, provided you use slirp.telnetd-b.tar.gz (at usual slirp sites, in the "extra" directory). Note that if you don't use slirp.telnetd-b.tar.gz you will NOT get DISPLAY set automatically, period. One thing you might try is set your LOCAL DISPLAY variable to the one suggested by slirp and let your telnet and the remote telnetd to negotiate the proper DISPLAY to set (if they both support it) - Added a very extensive "help" command. When you telnet to 10.0.2.0 and type "help" you get a list of commands guaranteed to be up-to-date, and typing "help COMMAND" will show it's usage and a brief description. You can do this from the command-line too: -h COMMAND or "help [COMMAND]" and slirp will exit after showing you the help. - Fixed PPP for systems without CID compression. This will also help error-prone links. - Added an option to ./configure, --disable-ppp, which will not compile in PPP. Use this if you only use (C)SLIP, it'll make a much smaller executable. - Added the following to the file COPYRIGHT: If you find this software useful, please consider making a $10 (or more) donation to your favorite charity organisation (GreenPeace, World Vision, Salvation Army, etc). If you make a donation above $20, I'll send you a personally signed copy of slirp (well, PGP signed :). I, and the lucky charity organisation, thank you. - *Lots* of minor, and *major* changes and improvements. If you don't believe me, check the diff (it's about 700k) :) Note that there are MANY changes in this version, so only use it if you're prepared for horrible things that may go wrong. You probably should stick to 0.9o with the 2 patches mentioned in my WWW page applied. Special thanks goes to Chris Metcalf for bashing slirp for the last week or so and sending lots of clean-up patches and additions to make it more "systems-and-compilers-I-don't-have-access-to" friendly (And for showing me how silly C can really be :) Version 0.9o (5/6/95) - This is just another fix-for-the-sunos release. It's not the first, and won't be the last. Thanks to Juha Pirkola and Wilson Cheung (wcheung@netcom.com) for taking the time to look into this. Thanks guys! - Fixed X redirection. - Fixed stats in a telnet session. - Other (minor) misc fixes. Version 0.9n (2/6/95) - Added load-balancing support. Now, people with 2 (or more) modems can effectively double (or more) their throughput. Load-balancing support is NOT needed on your local machine, but it must be able to handle more than one SLIP/PPP interface (you cannot use vj compression). (not working yet) - Completely overhauled the configuration of slirp. It's much more flexible now. Please read the file docs/CONFIG (not written yet) for details (NOTE: ~/.ppprc is not read anymore... you can "cat ~/.ppprc >> ~/.slirprc" to get it working again). - Removed slirp.ftpd and slirp.telnetd from the main distribution. You can get them separately from the usual slirp ftp sites. - Fixed a stupid change I made to 0.9m which would severely slow the link down when 2 or more connections were sending data, and vj compression was used. The change was actually done to make it a tiny bit faster... go figure :) - Made some fixes to make sure packets are aligned on a 4 byte boundary, which should fix some crashes on some systems (I hope). - Fixed the memmove problem (I hope). - Many minor (and major) fixes. (Many patches that were submitted to me were not included in this release because this was a rushed release (largely due to stupid bugs). They'll make it in the next release, promise. Note also that the MTU/MRU is pretty messy, and has now defaulted to 1500. It too will be fixed in the next release. For now, make sure you tell slirp both the new MTU and MRU and make sure they're the same) Version 0.9m (22/5/95) - Added slirp.ftpd. This is similar to slirp.telnetd, but for ftp; that is, you can ftp 10.0.2.1 to ftp to the remote-host, there's no need to login, no syslog()'s will be done, other users can't see what you're ftping when they do a ps (unless you want them to), no getting refused a connection because there are too many people ftp logged in via ftp already, etc. (the original ftpd sources were taken from the FreeBSD-current) - Fixed a bug in ppp_encap which would create lots of Incorrect Version Number errors, hence loss of packets, hence bad throughput. - Fixed a bug in sl_compress_tcp which *might* fix the spontaneously-combusting connections. *crosses-fingers* - Added more patches from Tom May for slirp.telnetd. - Added patches from Chris Metcalf which restarts a slirp session if the connection was broken. To restart, run slirp with "-r". You can have "-r" specified all the time so that scripts will automatically resume a lost connection, if one exists. #define DO_RESTART in config.h if you want this capability. It's really neat! Thanks Chris! :) (Note that connections which use the address 10.0.2.1 will close after reconnection, since they are run under user privilege, real telnet/ftp connections shouldn't be affected though) - Added more patches from Chris Metcalf to make PPP compile on more systems, and finally get rid of the evil -DANSI. - Lots of minor fixes. Version 0.9l (11/5/95) - Added PPP support, thanks to Juha Pirkola . It isn't "fully" integrated into slirp yet (eg: you can only give PPP options on the command line), and there's a lot of fat-cutting to be done, but I have tested it and it works like a charm! Thanks Juha! :) (Note that this version might not (won't) compile on all OS's, so if version 0.9k worked for you, stick with it until it becomes more integrated) - More spelling corrections and patches to patch.solaris from Chris Metcalf. - Reversed sunos.patch patches, and renamed the "new" sunos.patch to solaris.patch.alt, as an alternative to solaris.patch. Use whichever works for you. - Added emulation for DCC MOVE, thanks to Daniel J. O'Connor . Version 0.9k (07/5/95) - Added more 64bit fixes from Kai Makisara. It should work on Alphas now. - Added more patches from Chris Metcalf, including spelling fixes, krshd support, etc. - Fixed X redirection from ~/.slirprc. - Fixed some UDP redirection bugs, thanks to Jay Cotton . - Hopefully fixed the zombie processes problem for good, thanks to William Greathouse. - Fixed an MTU bug thanks to Jay Cotton . MTU's other than the default should work now. - Renamed the file ALPHA!!! to ALPHA!!, since it looks like slirp might finally be stabilising :) - Lots of other minor fixes. Version 0.9j (02/5/95) - IMPORTANT: The default special address has changed from 192.0.2.0 to 10.0.2.0. Read the file 00_README.NOW for details. - Made some preliminary changes so it will work on 64-bit machines, thanks to Kai Makisara . It probably won't work properly yet, but should in the next few releases. - Fixed a bug that may solve the Trumpet Winsock Blues (or at least one verse), thanks to Juha Pirkola . - Added patches from William Greathouse to allow the PASV command to work on incoming ftp connections. - Fixed X redirection from ~/.slirprc. - Added patches from Chris Metcalf to be more K&R friendly, among other things. - Lots of minor fixes. Version 0.9i (19/04/95) - Made ptyexec work in the command-line. - Made "redir X" work in command-line and ~/.slirprc. - Added support for PASV mode on incoming ftp connections. - Argh! Had port 20 (ftp-data) same priority as telnet etc. Should get better response times in telnet sessions now. - Cleaned up the autoconfig a bit. - Added better documentation of the commands in ~/.slirprc and the command-line. - Made many changes so it compiles with no warnings when using the -Wall flags (well, 2 warnings, but they don't really exist :) - Added more patches from William Greathouse. Changes from SLiRP 0.9g -> 0.9h (16/04/95) - Changed the exec/ptyexec commands so that an address may be specified too. (but the address must be of the form 10.0.2.xxx) - Added strdup for the systems that don't have it. - Fixed X redirection. Now you must specify your home IP address. - Added more stuff in TODO. If you want to help, read this file and do one of the things listed. - Added anti-idle mechanisms (must have at least one TCP connections active to have idle-prevention!) - Added more ANSIfying. - We have Autoconf! *ALL* compiling troubles have now been solved, period. (yeah, right! :) - Added do_wait() to eat defunct child processes, thanks to Joe Rumsey - Lots of minor fixes/enhancements. Changes from SLiRP 0.9f -> 0.9g (07/04/95) - Fixed a strerror declaration. - Hopefully (FINALLY!) fixed ftp. If anyone sends me e-mail that ftp doesn't work, they'll be shot. - Fixed the Makefile for SCO. - Added README.NOW. Please READ it... NOW! :) Changes from SLiRP 0.9e -> 0.9f (06/04/95) - Tried to fix ftp once more. - Fixed some more embarrassing bugs. Changes from SLiRP 0.9d -> 0.9e (05/04/95) - I think I finally fixed the non-connecting problem, but it's ugly. Thanks to William Greathouse who found it. It still won't fix the fact that a connection attempt to a port with no process will either hang or connect then disconnect. (it works fine in Solaris, as usual) - Made changes to tcp_timers so that Uni of Canberra users won't get spontaneous resets of a connection, though it could help others too. - Hopefully fixed ftp for some users. Thanks to rossi@cs.unibo.it (Davide Rossi) for pointing this out. - Added patches by nlewis@is.net (Nate Lewis) to get slirp.telnetd to compile on SunOS. - Added an extra check in main.c which shouldn't be needed (it should be taken care of by so_state) but crashes some systems. *sigh* Changes from SLiRP 0.9c -> SLiRP 0.9d (04/04/95) - *groan* SunOS still refuses to connect to non-localhosts. Changed the connection-detection code again. - Fixed a stoopid, stoopid mistake, which I won't tell you about, it's too embarrassing :) Changes from SLiRP 0.9b -> SLiRP 0.9c (03/04/95) - Changed the code to detect when a non-blocking connection failed. Still trying to find the ideal combination that will work for all OSs. - Ported to HPUX, bsdi. - Removed the PORT_ANY code. Now, if you don't care which port you get when redirecting, use port 0. Changes from SLuRP 0.9a -> SLiRP 0.9b (30/03/95) - Changed the name from SLuRP to SLiRP (slurp already exists) - Added telnetd to the source tree, which, if compiled, will be used so that arbitrary commands can be executed by SLiRP (eg: by default, if you telnet to 10.0.2.1, you'll automatically get a shell instead of a login prompt) - Completely removed the old way of "address encoding" to dynamically configure SLiRP, now you telnet to 10.0.2.0 and you get a "command-line" interface to configure SLiRP on-the-fly, as well as many other commands. - Added the ability to execute a program on connection to a certain address/port. - Changed if_output and if_start to be much smarter. It's quite clever now :) No single session can hog the link, and if one interactive session gets greedy, it gets "downgraded" to the same priority as bulk data. - Ported to SunOS, SCO, AIX. - Way, way too many small changes to list... (I've forgotten them anyway) [Thanks also go to the following people for patches, ports, etc.: Tom May (sunos), jonas@cs.rochester.edu (man page), Chris Moustakis (sco),] slirp-1.0.17/README0000644000175000017500000000333410117223533012665 0ustar roverroverHOWLS!!! Thank you for pulling this latest release of Slirp. The new maintainer for Slirp is Kelly "STrRedWolf" Price The homepage is now http://slirp.sourceforge.net Now, this is a new release with new numbering similar to the Linux kernel, so if you see a x.even.x release, it's a stable release, while x.odd.x is a developmental release. Do read the README.NEXT file located here fully. I(Kelly) am getting alot of bug reports that don't have alot of stuff to go on. Also contained in that file is info on the mailing list. Read it if you want to mess around with it, there's alot to do inside!!! One last thing. For the arbitrary tty, set the enviroment varible SLIRP_TTY to where you need to connect. I use SLIRP_TTY=/dev/pilot slirp for my Palm Pilot. --Kelly Update by Roger Plant You can now use something like "tty /dev/ttyS0" on the command line to set up an alternate tty. For use under CYGWIN You will need to supply a "dns YourDnsIP" option slirp will not find it's DNS's under windows. Alternatively you could possibly create and fill in a /etc/resolv.conf file (Not tested...) Modify the Makefile to have the -MS_DCC option enabled, It will allow a direct cable connect into Slirp, PPP mode only. (This option works on other platforms too, but is most likely to be useful for windows) Also if it compiles, but doesn't work, try backing off the optimizer. eg. -O1 instead of -O2, or even delete the option completely. This applies to all platforms. Thanks Arnold Shulz SECURITY SLIRP remains insecure. Most though not all of the buffer overflow issues indicated by Tim have been addressed. Slirp is a User program. Anyone using slirp via a PPP connection, has or can obtain the privileges that slirp is running at. slirp-1.0.17/README.NEXT0000644000175000017500000001520610117222422013437 0ustar roverrover********************************************************************** ***** PLEAESE READ THIS WHOLE FILE BEFORE CONTINUING ANY FURTHER ***** ********************************************************************** What is Slirp? ============== Slirp is a TCP/IP emulator which turns an ordinary shell account into a (C)SLIP/PPP account. This allows shell users to use all the funky Internet applications like Netscape, Mosaic, CUSeeMe, etc. Unpacking and Compiling Slirp ============================= To unpack Slirp type the following command at your shell prompt: gzip -dc slirp-VERSION.tar.gz | tar xvf - Of course, if you have the latest GNU tar... tar xfvz slirp-VERSION.tar.gz Where VERSION is the version of Slirp you are unpacking. This will unpack the Slirp package into a directory called slirp-VERSION. To compile Slirp type the following commands at your shell prompt: cd slirp-VERSION/src ./configure make Notes: if you do not intend to use PPP you can give ./configure the flag "--disable-ppp". This will make a somewhat smaller executable. if you wish to disable the MS type DNS transfer for PPP, or enable MS DCC functionality, you will need to edit the created Makefile and add/remove the options. By default USE_MS_DNS is enabled, MS_DCC is disabled. That's all there is to it. If the compilation failed, read "Getting Help" below for information on how to get help. You should be left with a file called "slirp", this is the Slirp executable. After compilation, you can type: strip slirp to make the Slirp executable smaller, but this will also remove any debugging information from the executable. Here are some common ./configure/compiler/pre-processor/etc. problems and suggestions for fixing them: * "configure: error: can not run test program while cross compiling" (or similar errors about cross compiling). This almost always happens due to an error in the setup of the compiler. Look in the file config.log for clues as to why it failed, or send it to your sysadmin for help. * "gcc: xxxxxxx.p: No such file or directory.": This can be completely ignored when running the pre-processor, and can probably be ignored in the actual compilation. The .p files only contain the function prototypes. * "gcc: warning: no previous prototype for XXX'": Again, you can ignore this. * "RUN_MAKE_AGAIN: not found ... *** Error code 1": This is normal. As suggested, simply run "make" again. Running and Quitting Slirp ========================== Once you have compiled Slirp you can delete everything except the file called "slirp", this is the Slirp executable. I suggest you also keep all the files in the "docs" directory, this is where all the documentation is kept. Copy the Slirp executable somewhere in your home directory (E.g.: ~/bin) then to run Slirp, you simply type: ~/bin/slirp or ~/bin/slirp -P (for PPP operation) (or whatever the full path to "slirp" is). That's it. Now you activate your SLIP/PPP software, and start your applications. All you have to remember is this: Once you run Slirp, your shell account now looks exactly like a SLIP/PPP account (with some limitations of course). Any documentation that you have telling you how to connect to a SLIP/PPP account is completely valid for Slirp as well. To quit Slirp you simply kill your SLIP/PPP software and type five 0's (zeroes), with a 1 second gap between each zero. Slirp will then exit and you will be back at your shell prompt. You can also "disconnect" Slirp by typing five 1's (one's), with a 1 second gap between each. This will disconnect Slirp from your shell's terminal and put Slirp in the background. Later, you can type "slirp -l 0" to "reconnect" Slirp again. Please read Section 10, "Load-balancing" and Section 11, "Link-resumption" of the Slirp manual for more information. Slirp has lots of options available, so while this will mostly get you up and running in the first instance, reading the manual is worthwhile. Files in the Slirp package ========================== Here are the list of files you'll find within the slirp package: COPYRIGHT Conditions of the Copyright on Slirp. Please read this. ChangeLog Descriptions of changes made to slirp from version to version. Also details all contributors, and their contributions. IMPORTANT Information about who's the latest maintainer. (Hint, it's not Danny) README What was this file. README.NEXT This file. Really! docs/CONFIG List of configuration options (probably out of date) docs/alt.dcom.slip-emulators.FAQ This is the FAQ (Frequently Asked Questions) from the newsgroup alt.dcom.slip-emulators. docs/slirp.doc The Slirp manual. src/* The source code to Slirp. Getting Help ============ There are several sources of help. First, read the Slirp manual called slirp.doc in the "docs" directory of the Slirp package, especially Section 13, "Troubleshooting" and Section 14, "Answers to Frequently Asked Questions (FAQs)". There is also a Newsgroup dedicated to SLIP-emulators called alt.dcom.slip-emulators. You will find lots of discussion about Slirp and other "SLIP-emulators". The FAQ (Frequently Asked Questions) for alt.dcom.slip-emulators is included in the "docs" directory, I would suggest reading this as well. The Slirp website (http://slirp.sourceforge.net) has some information too. Go there! A mailing list for Slirp development is hosted by SourceForge. If you are intrested in pitching in, go ahead and subscribe. If all else fails, send Kelly, the new maintainer, an e-mail with the following information: * Output of the command "uname -a" on the remote system; * Operating System name and version you run on your PC; * If it's Linux, the name of which distribution you are running and which version. * What compiler and which version you're compiling with. HINT: If it's not GCC, then I will be tempted to have you switch to it and try it again. Seriously, GCC is much better! * Version of Slirp you are using (IMPORTANT!!!); HINT: If it's a 1.0g or less, you really need to upgrade first. This is what I'll say first -- Upgrade and try it again. * If you managed to get Slirp running, run Slirp as "slirp -S" then try whatever failed. When you exit Slirp, you should have a file called "slirp_stats". Send me this file; and * Anything else you consider relevant. Don't send me core dumps. I can't handle 'em, and they may be for an different system than what I have!!! *PLEASE* include all the above information. If you do not, I may simply press "d". I can't guarantee a response, but I will try my best. Kelly Price and the Slirp Development team. (Thanks go out to Dan, the previous developer.) slirp-1.0.17/TODO0000644000175000017500000000023710115527015012474 0ustar roverroverWhee!!! another TODO file! To do: * Clean up the code so it has some resemblance to ANSI C. * Replace functions which just return 1 to actually do something. slirp-1.0.17/TODO.old0000644000175000017500000000252510115527015013253 0ustar roverroverLong(er) term: Add Predictor-1 compression "r"-commands Short term (BETA): fix memmove... fix the NEED for memmove give args to exec make "exec" accept arguments Update man page Have all pending packets purged when a REXMIT is needed on a session? Move comp_s to struct ttys? [not needed, since compression won't work on >1 ttys] Have the last used ttyp at the head of the list? [cache?] if the mtu changes, call msize_init()? "add exec" for UDP slirp.resolvd - emulate DNS packets make debugging work BEFORE option parsing? have m->m_data += if_maxlinkhdr in m_get()? remove schedtime from pppdfcns.c Change sosendto -> udp_sendto and soread -> tcp_read etc. and do general cleaning up warn for ports above 65535. add "baudrate 0" [make FULL_BOLT == baudrate 0 ?] have stats socket print udp[REDIRECT] remove OOBINLINE check all setsockopt/ioctl for opt=1 remove \n from ~/.slirprc FIX FULL_BOLT Fix sbreserve... there are STILL smaller packets being sent! put "escape xx" in CFG_TELNET? add identd emulation [half done] make "towrite" an option only update towrite when all modems are towrite < 0 ? put ftp sites in documentation if uid=0, bind priveladged port when source port is < 1024 add "add emu" crap to docs asyncmap ffffffff escape 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f escape 10,11,12,13,14,15,16,17,18,19,1a,1b,1c,1d,1e,1f slirp-1.0.17/cygwin.patch0000644000175000017500000000111710115527015014323 0ustar roverrover--- /home/mike/slirp-1.0.14pre1/src/misc.c Sat Sep 9 18:48:43 2000 +++ misc.c Wed Aug 14 01:00:58 2002 @@ -227,10 +227,13 @@ return -1; } - if ((slave = open(ptr, O_RDWR)) < 0 || - ioctl(slave, I_PUSH, "ptem") < 0 || - ioctl(slave, I_PUSH, "ldterm") < 0 || - ioctl(slave, I_PUSH, "ttcompat") < 0) { + if ((slave = open(ptr, O_RDWR)) < 0 +#ifdef I_PUSH + || ioctl(slave, I_PUSH, "ptem") < 0 + || ioctl(slave, I_PUSH, "ldterm") < 0 + || ioctl(slave, I_PUSH, "ttcompat") < 0 +#endif + ) { close(master); close(slave); return -1; slirp-1.0.17/docs/0000755000175000017500000000000010117224177012737 5ustar roverroverslirp-1.0.17/docs/CONFIG0000644000175000017500000002676110115527004013634 0ustar roverroverKey: all options within [] are optional usable: refers to where it can be used, ie: "command-line/config-file", "telnet", or "anywhere" (which means it can appear in either command-line/config-file or telnet). command-line: gives the command-line equivalent XXX etc. redir X [start RDISP] [ADDR][:DISPLAY[.SCREEN]] redirect a port for use with X usable: anywhere command-line: -X options: start RDISP tell slirp to start looking for free ports starting from N. eg: if N = 2, slirp will try to grab port 6002 then 6003 etc. this is useful for sites which sometimes run their own X server and you don't want to nab their port 6000, which they would naturally expect. ADDR our home ip address, or the address where the x server is (if you have a LAN at home to connect more than one machine to the net) (default 10.0.2.15 when in ~/.slirprc, the source IP address when in command-line) DISPLAY which display to redirect to (default :0) SCREEN which screen to redirect to (default .0) Example: redir X 10.0.2.15:0.0 Note: this will print the command needed to enter into each shell from where you launch your X apps See also: show X show X show the command that needs to be given to your shell for any X port that has been redirected (in case you forget). usable: telnet command-line: NONE options: NONE Example: show X Note: this is useful if you forget the command to give to your shell for X redirection. See also: redir X, log start redir [once|time] [udp|tcp] PORT [to] [ADDRESS:]LPORT redirect host port to local port using a selected protocol. usable: anywhere command-line: NONE Options: once only allow one redirection [TCP only] time allow redirection to time out [UDP only] udp redirect a UDP port tcp redirect a TCP port [default] PORT port to use on host system ADDRESS address of your home machine [default 10.0.2.15] LPORT port to redirect host port to on local system Example: redir tcp 5021 to 21 allow users to ftp to your local machine using your host's port 21. (ftp your.hosts.name 5021) Note: if this command is in your .slirprc file and no address is specified, it will assume that your local IP address is 10.0.2.15. If you enter the command from the slirp control telnet IP it will use the IP address you are accessing with. baudrate N controls the allocation of time to communications across your serial link. Higher values generally use more of the available bandwidth to your modem. This is _only_ an internal control value and does _not_ change the physical settings for the host port or modem. usable: anywhere command-line: -b Options: N change baudrate to N Example: baudrate 14400 Note: higher numbers generally allow better transfer rates for ftp sessions, but interactive sessions could become less responsive. the optimum value is *JUST* when ftp sessions reach maximum throughput, but this can be hard to find (especially on compressing modems) so you should choose the maximum throughput you would expect from your modem. special|control|host addr ADDRESS set ip address aliases and others for slirp. usable: anywhere command-line: none Options: special address set the network ip alias for slirp control address only allow access to slirp control address from ADDRESS. host address tell slirp the IP address of the host it's running on. use this only if slirp can't properly find the host's IP address Example: special address 10.0.3.0 Note: the ADDRESS for special must end in 0 (zero) and other addresses are classed from this. The default special address is 10.0.2.0 giving the following defined IP's 10.0.2.0 slirp control telnet IP 10.0.2.1 slirp exec IP 10.0.2.2 slirp host alias 10.0.2.x add [pty]exec optional address add [pty]exec PROGRAM:[ADDRESS:]PORT Set program to execute on host when local machine attempts to connect to ADDRESS at port PORT. usable: anywhere command-line: none Options: exec establish binary connection to program in the style of inetd. ptyexec establish telnet connection to program using telnetd helper application under a pseudo-terminal PROGRAM program to exec ADDRESS optional address PORT port Example: add ptyexec csh:55 A telnet connection to the slirp exec IP (default 10.0.2.1) will start and connect you directly to the csh program on the host. (telnet 10.0.2.1 55) add exec nntpd:10.0.2.3:119 A program that attempts to open port 119 at address 10.0.2.3 will be connected to the nntpd program. Note: the use of the ptyexec form requires the slirp.telnetd helper application be available on your path. also note that ADDRESS must be of the form SPECIAL_ADDRESS.xx (10.0.2.xx by default) [no]compress force startup mode for slirp to SLIP or CSLIP. This overrides the default automatic mode determination. Command: nocompress start in SLIP mode compress start in CSLIP mode Options: NONE Note: the default method of operation generally performs well. You should only have to use this command if you find that your host and local system are failing synchronize the connection type. mtu N controls the size of the IP packets sent across the serial IP link. Valid values are <= 1500. Options: NONE Example: mtu 1500 set the mtu to its largest allowable size. Note: larger values generally improve the performance of graphics web browsers and ftp transfers across the serial link, at the expense of interactive performance. The default value of 552 seems to be a reasonable compromise for connections at 14400 baud. shell PROGRAM set program to execute on EXEC IP default telnet port (23). It is the same as add ptyexec PROGRAM:23 Options: NONE Note: by default slirp connects /bin/sh to the exec IP telnet port. help [COMMAND] show a brief list of available commands, or more information on the named command remove [pty]exec PROGRAM:[ADDRESS/]PORT reverse the effect of "add [pty]exec". see "add [pty]exec" for the options etc. Note: you must enter the options exactly as you entered it in add [pty]exec. XXX incomplete echo [on|off] turn echo on or off, depending on how your client behaves. "echo" by itself will show whether echo is currently on or off. kill N kill the session which has a Socket no. of N. to find the Socket no. of a particular session, use the "stats socket" commands. see "stats" below. Note: it is recommended you use "close N" instead, as this merely wipes out the session, whereas "close N" closes it properly, as a good little tcpip-emulator should :) "kill -1" shouldn't be used, it will kill the first session it finds with -1, which usually is the command-line connection. close N close the session which has a Socket no. of N. same as "kill N", but closes it session gracefully. see "kill N" stats [ip | socket | tcp | vj | udp | mbuf | tty | alltty | others? ] show statistics on the given argument Options: ip show ip statistics socket show statistics on the currently active sockets. use this to find out which sessions to close/kill as it will also show the FD of the session tcp show tcp statistics (packets sent/received/etc) udp same as tcp but for udp mbuf show how many mbufs were allocated, are in use, etc. if the modem is idle, and there are more than 1 mbufs on the used list, it suggests an mbuf leak [pty]exec PROGRAM this will execute PROGRAM, and the current command-line session will cease to exist, taken over by the PROGRAM. ie: when the program exits, you will not get the command-line back, the session will (should) close. socket [PORT,PASSWORD] create a Unix-domain socket and listen() for more interfaces to connect. This is also needed for restarting. Give the arguments PORT,PASSWORD if you wish to use Internet-domain sockets instead of UNIX-domain sockets. log start log all the startup output to the file .slirp_start. add emu SERVICE[:TYPE_OF_SERVICE] [lport:]fport Tell slirp to emulate SERVICE when on port lport/fport. service can be: ftp, ksh, irc, none type_of_service can be: throughput, lowdelay lport can be given if that service needs emulation for, say, servers. examples: if you wish to ftp to somewhere on port 8021, do: add emu ftp 8021 if your home ftp server is on port 8021, do: add emu ftp 8021:0 [NOTE: this does NOT mean if you redirect port 8021 for your ftp daemon, it refers the the port AT HOME at which ftpd is listening to] if you telnet somewhere on port 8000, and you wish those packets to go on the fastq (ie: so they have a higher priority than, say, ftp packets), do: add emu none:lowdelay 8000 this tells slirp that any packets destined for port 8000 will not have any emulation, but it will be set IPTOS_LOWDELAY. dns DNS_IP Give this to slirp if you want to use 10.0.2.3 as an alias for DNS, AND slirp guesses wrong for the DNS on startup. You can give this command twice. This is only used when dns is to be transferred to the peer, (PPP mode) then 2 DNS's will be sent to the peer. tty DEVICE eg. slirp -P "tty /dev/ttyS0" Only available on the COMMAND LINE, causes slirp to open the specified device, rather than stdin for data transfer. This option overrides the SLIRP_TTY environment variable which is also used for this purpose. Note: This option is 'special' and is processed prior to the other options. (It may be anywhere on the command line, but is ignored in the config file) nozeros Give this to slirp if you do not want it to check for 5 consecutive 0's or 1's to exit/disconnect the link. May be an issue on a slow link, and fast PC, where some numeric data could conceivably look like 5 individual 0's or 1's and cause slirp to exit. debug Level -d level Turns on debugging, to specified level. eg. "debug -1" or -d -1 turns on all debugging (Except ppp debugging) Writes to file slirp_debug Note: Some debug items may not be present if not compiled with the -DDEBUG option. debugppp -dppp Turns on ppp debugging. Writes to file slirp_pppdebug Note: Some debug items may not be present if not compiled with the -DDEBUG option. MS_DCC This isn't an option, its a compile time choice, and its a hack. If enabled, when slirp is run and PPP is selected, while the PPP link is down, SLIRP will respond to an incoming word of "CLIENT" with the reply "CLIENTSERVER" This will allow a MS windows PC to connect to slirp using direct cable connect (Over the serial port at least). It has 1 major advantage over using a normal DCC, and that is that the IP address of the connecting host is masqueraded. (Which windows won't do normally) slirp-1.0.17/docs/alt.dcom.slip-emulators.FAQ0000644000175000017500000016257710115527004017763 0ustar roverroverFrom stevew@netcom.com Wed Aug 16 01:33:24 1995 Return-Path: stevew@netcom.com Received: from netcom21.netcom.com (stevew@netcom21.netcom.com [192.100.81.135]) by blitzen.canberra.edu.au (8.6.10/8.6.9) with ESMTP id BAA17220 for ; Wed, 16 Aug 1995 01:32:14 +1000 Received: by netcom21.netcom.com (8.6.12/Netcom) id IAA29646; Tue, 15 Aug 1995 08:25:30 -0700 From: stevew@netcom.com (Steve Wilson) Message-Id: <199508151525.IAA29646@netcom21.netcom.com> Subject: Latest FAQ To: danjo@BLITZEN.CANBERRA.EDU.AU Date: Tue, 15 Aug 1995 08:25:30 -0700 (PDT) X-Mailer: ELM [version 2.4 PL23] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Length: 57991 Status: RO X-Status: Alt.dcom.slip-emulators FAQ V1.5 Aug 10, 1995 This has been completely re-organized, i.e. there is a some what logical organization now with some of the descriptions you'd asked for! There is also some meat to the questions relevant to Windows 95, etc. Steve Wilson ------------------------------------------------------------------- Questions: 1.0 What is a Slip Emulator anyway? 1. What is a Slip/PPP emulator? 2. Is Slirp better using SLIP or PPP? 2.0 Where to get Slip Emulator Software?: 1. Is Slirp Free to Use? Will I be charged long distance fees for using this because it uses my modem? 2. Where can I get slirp? 3. Where are there precompiled binaries for Slirp for... ? 4. Where can I get precompiled binaries for TIA? 5. Where on Netcom is a pre-compiled version of slirp? (Need to add stuff about twinsock...anyone want to write this section?) 3.0 Emulator Configuration, i.e. How do I make this stuff work? 1. Slirp starts up ok except doesn't display the DNS so I told it what the DNS was. However, it won't load my local homepage? 2. What should my network configuration look like for trumpet winsock for netcom? 3. How do I use slirp to telnet into my linux box? 4. What do the configuration files need to look like for linux? 5. Is it possible to send mail from my Linux box to/thru Netcom while 6. How do I set up slirp for an X connection? 7. What are the new formats for the .slirprc commands in the .95x release of slirp? What are the new control port commands? 8. I'm trying to get shell via telnet on slirp, without logging in again. What is the configuration? 9. Does anyone have instructions/hints as to how to use Windows 95 with slirp? 4.0 Emulator Performance 1. Tia/Slirp Benchmark (This is slirp .9o vs TAI 1.0 I think..) 5.0 Miscilaneous Problems/solutions... 1. The posted solution from Dan(Author of SLIRP) for the .9o lockup problem(RWIN adjustments, etc.) 2. 32 bit Netscape on Win95 has DNS problems. Why? 3. Using OS/2 my baud rate say it's 1200. How do I make this faster for slirp? 4. How do you login using the slirp.telnetd? 5. Slirp says it's running 9600 baud. How do I make ir run at 14.4? 6. Where can I find nntpd for netcom? How do I configure it for Netcom? 7. TCPman launches when I try to run Netscape..but netscape never comes up? 8. I start up a connection under Win95 and I only get a PPP connection? How do I configure it for slip? 9. Why is using the telnetd better than just logging in twice? 10. Why doesnt' FTP-PM work with slirp? 11. Will TIA 2.0 support PPP and CSLIP? Why don't they support ICMP? I'd love to see automagic port redirection as well? 12. Why does rlogin work from the port master I'm dialing into, but telnet doesn't for setting up slirp between then end points? 13. Address 10.0.2.0 doesn't work under InterSlip from my Mac. Why not? 14. How do I setup POP mail using slirp? (note - I'm still not completely happy with this organization... but it's a start and it's all I've got time for at this point. Next release...) ---------------------------------------------------------------------------- 1.0 What is a Slip Emulator anyway? Question 1.1 What is a SLIP Emulator? A slip emulator is a piece of software that runs on the host machine that you call into. This software accepts the bits you throw it's way using SLIP and then submits these bits to the host computer for transmission on the internet. When bits are received from the internet for the remote system, the emulator packages them up into the SLIP protocol and send them along to your remote system. Boy...that was terse and to the point ;-) Another way of putting this is that the SLIP emulator acts as a middleman between the internet and your remote system. Your remote system speaks SLIP at the middleman, and he interprets it into the language used by the internet. These two languages aren't really that different, and actually, SLIP is the same language as used on the internet plus some extra packaging to send it over your phone line. You need to use SLIP (or PPP..explained later) over the phone line because you are transferring binary information instead of just text. If you've used zmodem or xmodem or kermit...you are using these protocols for the same reason as you are using SLIP or PPP. The primary difference between these protocols and SLIP is that SLIP corresponds(as just mentioned) to the language of the internet (TCP/IP...Transport Control Protocol/Internet Protocol... a real mouthful even as TCP/IP ;-) ---------------------------------------------------------------------------- Question 1.2 Leo Perez y Perez (perez@csulb.edu) wrote: : Is SLiRP better as SLIP or PPP? : or, what is the difference between them anyway? : : Leo Perez y Perez : perez@csulb.edu There are really three protocols available with slirp. They are SLIP, CSLIP, and PPP. The protocols have the following properties... Slip is merely raw IP frames sent in between two Flag characters, one indicating start, and the other indicating end of packet. There is an escaping method when either of the two flags appears inside the actual IP datagram. CSLIP is sent via the same basic mechanism over the physical medium(your phone line) but an added level of compression is applied to the header of the IP datagram itself such that the IP header is reduced in sized from something like 40 bytes to something like 7 bytes. This savings happens on EVERY packet. This is a style of compression that is beyond the V.42bis compression algorithm used by your modem. Estimates give about a 20% increase in performance(give or take 10%). PPP (or Point-to-Point Protocol) really might be classified more like a byte oriented HDLC. That means that it takes the IP datagram and puts inside yet another encapsulating packet. This packet has a CRC across it so bad packets can be detected at the lowest level. There are also security features built into this protocol. Basically, it is a far more robust protocol than Slip or CSLIP. PPP also has the added property that the Slirp implementation can escape several control characters, so you are more likely to get a successful link up on a line that isn't 8 bit clean. (aka a serial line that has some sort of input processing occuring.) >From previous performance measurements, people have found that CSLIP is fastest when using Slirp. Some folks(like me) wind up using PPP over CSLIP because of the need for the escaping feature. In my case this allows me to do ftp sessions that don't work under CSLIP. Now, that is probably more than you ever wanted to know ;-) Steve Wilson ---------------------------------------------------------------------------- 2.0 Where to get Slip Emulator Software?: Question 2.1 In article , waddell@HERCULES.CS.UREGINA.CA says... > >Is SLiRP free to use (ie. will I be charged long distance fees for using >this because it uses my modem> or does it use the University's (or Unix >server's modem>? > Yes. SLiRP is a free copyrighted software. SLiRP runs on your UNIX shell account and let's you connect to the internet. You need a client PC with a TCP stack like Trumpet Winsock which uses your modem to access your shell account. If there is a long distance charge to access your university's computer, then you will have to pay those charges, as well as, any usage fees that you are now paying. Otherwise, you don't have to pay for accessing the internet. Hope this helps, Lynn Larrow llarrow@netcom.com Pacific Grove, CA http://www.webcom.com/~llarrow/tiarefg.html (SLiRP/TIA/Trumpet Setup) [Editor's note: The above is a VERY useful home page, and is packed with more info than you'll find here!!] ---------------------------------------------------------------------------- Question 2.2 In article , lucasa@postes.gaylord.org says... >Could someone please inform me of a FTP site for the >updates to slirp? > >Lucas ftp://peace.wit.com/danjo/slirp/ or ftp://blitzen.canberra.edu.au/pub/slirp/ or ftp://ibc.wustl.edu/pub/slirp_bin/ Lynn Larrow "When the shoe fits, the foot is forgotten" llarrow@netcom.com Pacific Grove, CA ---------------------------------------------------------------------------- Question 2.3 In article <3s35j8$eab@gulfa.kuwait.net>, kcc94td1@access.kuwait.net says... >Anyone know where there are pre-compiled SLiRP binaries? This would be >very helpful and highly appreciated :-D > >Khaled al-Feeli Try ftp://ibc.wustl.edu/pub/slirp_bin/USE_AT_OWN_RISK/ I also have some other links to slirp binary sites at this URL: http://www.webcom.com/~llarrow/tiafaqs.html Hopefully they are all still active :) Lynn Larrow llarrow@netcom.com Pacific Grove, CA ---------------------------------------------------------------------------- Question 2.4 > Where can I get precompiled binaries for TIA? You can get TIA by : ftp: //marketplace.com/tia There is also shareware for different systems under: ftp: //marketplace.com/tia/shareware ---------------------------------------------------------------------------- Question 2.5 In article , >stew1117@netcom.com (stewart coulter) wrote: >I am trying to locate the latest version of slirp, the one site that I >tried I was unable to locate it any directories, please help me. I need >the FTP site and directory. Respond via email. Folks on Netcom can get the release files and a few other doo-dads from my directory: ~ldobbs/slirp The modified source for tcp_input.c (see other threads) is there, along with some simple (and undocumented) scripts to build the binary. Lee Dobbs Milpitas CA Voice: 408-946-7860 ldobbs@netcom.com USA Fax: 408-262-9392 ---------------------------------------------------------------------------- 3.0 Emulator Configuration, i.e. How do I make this stuff work? Question 3.1 In article , lkhan@winnie.fit.edu says... >I have installed the latest version of slirp on the Unix machine. It >conplied properly (although I had to erase some files so it won't go over >disc quota). Using Trumpet Winsock, I ran it using the command line: >"slirp -m 552 -c" (I set all the configurations as stated on the slirp home >page.) It shows all the messages at the beginning expect for the dns ip >address. So I used the "I.P. address of slirp" for the dns. > >When running Mosiac (ver. 2beta4), it wouldn't load the homepage. The >messages at the bottom stop at "Waiting..." and sticks there forever, the >little Mosaic "earth" still moves. > >What can be wrong?? > >On the same machine, I can still run twinsock properly (it works.) My best guesses would be one of two things. The first is that using the IP address of the machine slirp is running on as your DNS isn't working. In many university situations, they will have one or two machines which serve as nothing more than DNS servers. You need to find out the address of these machines. The best idea here would be to ask the sysadmin at your site. The second good possibility is that a terminal server is interfering. Using SLIP/CSLIP requires an absolutely clean 8-bit line, something that most terminal servers in a university setting have trouble with. Try to find out if your terminal server has a 'terminal download' option, or something similar to set the connection to 8-bit clean. Alternatively, try using SLiRPs PPP mode as you can escape control characters which may help the problem. BTW, this would explain why twinsock works as it defaults to a 6-bit mode, which means it can run over almost any connection. It also makes it dog slow. Hope this helps. Matt mnm@goodnet.com matt.moore@asu.edu ---------------------------------------------------------------------------- Question 3.2 In article , sfb@netcom.com (sfb) wrote: >I currently have a Netcom Shell Account and am using TIA to emulate slip. > ... >What should my settings be under Network Configuration? I have tried >tons of various settings, such as 192.0.2.2 (works for Eudora) and >netcom.com First, I suggest adding these to the end of your hosts file in the Trumpet directory: (Editor's note - Should probably change the 192.0.2.x stuff to 10.0.2.x in the table below ... see the linux configuration info for what I mean..) 192.100.81.101 netcomsv netcomsv.netcom.com 192.100.81.105 ns.netcom.com 192.100.81.254 netcomgw netcomgw.netcom.com 192.0.2.1 local-pc 192.0.2.2 mail.netcom.com smtp-server pop-server 192.0.2.3 netcom.com news.netcom.com nntp-server Then, in any winsock app that needs a POP or SMTP server (such as the Host and Relay Host for Pegasus), use mail.netcom.com -- for a news (NNTP) server, use netcom.com . By the way, in my Trumpet File;Setup Nameserver setting, I've been using 192.100.81.101 192.100.81.254 192.100.81.105 and I get very few name lookup delays. Lee Dobbs Milpitas CA Voice: 408-946-7860 ldobbs@netcom.com USA Fax: 408-262-9392 ________________________________________________________________________ Question 3.3 In article frank@netcom.com (frank) writes: >Hi, Slirpers: > >How do I telnet into my linux box? I redir the port 8888 to 192.0.2.0:23 >I am using SLiRP 0.9o. But when I login to netcom and use >telnet netcom8(or whatever).netcom.com 8888, nothing happened. >Do I need to set my IP to 192.0.2.0 instead of 10.0.2.15? Any help >will be greatly appreciated. > >frank@netcom.com Why don't you try redirecting it to 10.0.2.15:23 ??? ________________________________________________________________________ Question 3.4 What do the configuration files need to look like for linux for basic tcp/ip connetions to work with a slip emulator? These files are configured for netcom..but hopefully will serve as an example as to how to set things up.... /etc/hosts ---- 127.0.0.1 localhost 10.0.2.15 darkstar local-pc 192.100.81.101 netcomsv netcomsv.netcom.com 192.100.81.105 ns.netcom.com 192.100.81.254 netcomgw netcomgw.netcom.com 10.0.2.2 mail.netcom.com smtp-server pop-server 10.0.2.3 netcom.com news.netcom.com nntp-server /etc/resolv.conf ---- domain netcom.com nameserver 192.100.81.108 (Editor's note - You might want to have several entries on this line so if one nameserver is down, there are alternatives locally.) /etc/host.conf ----- order hosts, bind multi on I'm not going to try and explain how to use dip here...that's a bit much. ________________________________________________________________________ Question 3.5 In article , ekbond@netcom.com (E. Kelly Bond) wrote: > Is it possible to send mail from my Linux box to/through Netcom > while connected via TIA? > > Any help will be appreciated. > > Kelly > ekbond@netcom.com Yes, I am doing it. You have to configure your domain name to netcom.com and use sendmail with the smtp-only script in /usr/src/sendmail/cf, and all will be great. There are readmes in the sendmail directory how to use m4. It's a one liner. Use sendmail -q to bump the queue into action when you connect, or as part of your ppp-on script. Oh, actually I am doing it with SLiRP, not TIA, but same thing... Cheers, -- Grant Bowman ________________________________________________________________________ Question 3.6 In article <3vn7vg$8s@seagoon.newcastle.edu.au> you wrote: : Hi all! : I'm currently trying to get an xterm window from the host machine : to my computer. I've tried the -X option and setting the DISPLAY : environment. When I type "xterm", I just get the I/O error 32. Broken : pipe or something like that on X server. Does anyone know what I'm doing : wrong? : : | Edmund Lai | Okay...lets review what you have to do. First, in the .slirprc you have something like redir X IP (where IP is the number of the system you are typing at, ie whatever your fake IP address is. Slirp uses 10.0.2.15 by default. That is as good a choice as any unless you have other reasons to change it.) Okay...next. IS YOUR X SERVER UP and ALLOWING REMOTE CONNECTIONS on your home system? If you are running linux at home, you need to say "xhost +" to allow all hosts to access your screen. Note - this IS potentially a security problem! This opens your system wide up to intrusion. On the other hand...do people know you have X and slirp running? Finally, you need to telnet over to the remote host and type what slirp told you to type in its' log on banner. Something like "setenv DISPLAY HOSTIP:offset" where HOSTIP is the host's IP number and offset is the X socket offset from port 6000 that slirp grabbed(see below). Why do you have to do this you might ask...why isn't this number you home system's IP instead? Good question, and one I asked the author before I stared at the code myself, and learned about unix sockets;-) What slirp does with ANY port redirection is open up a unix socket, and start listening for traffic on that socket. So when you say redir X IP, what you are saying is listen on port 6000(or 6000+ some number if 6000 is busy), and any connections you see on that number forward over the SLIP link to the IP address I gave you. That means that you need to tell X clients to look for the X server at a specific machine IP address:socket number to connect to your server that is on the other end of the phone line! You do this by typeing "setenv DISPLAY HOSTIP:offset" which is a variable, DISPLAY, that all X clients are sensitive too. Notice the offset. This might be a little confusing also. Slirp tries to grab socket 6000, but if the socket is already in use, it'll increment the socket it's trying to listen too until it finds a free one. So you might get 6007 as an example, if 6000-6006 are already in use. To set the display variable correctly you need to set the address to HOSTIP:7. The X client is already smart enough to add the 6000 base address. Summary. 1) Set the redir X HOMEIP in slirprc 2) Make sure that connecting hosts can access your server by getting the security right. 3) Telnet to the host and do a setenv DISPLAY HOSTIP:offset corresponding to the slirp banner. That should get you up and running X! Good Luck, Steve Wilson ________________________________________________________________________ Question 3.7 : What is the new format for .slirprc commands? What commands : are available on the control port? Note that versions of SLIRP after version "O" have many changes. They require you to use a different, new format for [pty]exec in the "$HOME/.slirprc" file. Here is the new format: SLIRP95c Usage: add ptyexec | ptyexec PROGRAM:[ADDRESS:]PORT The new formats, the use of the $HOME/.slirprc-0 file (executed _before_ $HOME/.slirprc), and many other NEW features are clearly described in the docs/CONFIG file, which is included with the SLIRP95c package. There is a new HELP menu, with many options, here is what it looks like: --= SLIRP 95c help menu =-- SLiRP command-line ready (type "help" for help). Valid commands: prompt redir X show X redir baudrate special addr control addr host addr add exec add ptyexec add emu shell debug socket log stats config log start dns help -h echo exec ptyexec unit wait quit ppp -all -ac -am asyncmap debugppp -ip -mn -mru -pc +ua +pap -pap +chap -chap -vj -vjccomp vj-max-slots escape domain mru mtu initiate-options name user usehostname remotename auth proxyarp login lcp-echo-failure lcp-echo-interval lcp-restart lcp-max-terminate lcp-max-configure lcp-max-failure ipcp-restart ipcp-max-terminate ipcp-max-configure ipcp-max-failure pap-restart pap-max-authreq pap-timeout chap-restart chap-max-challenge chap-interval ipcp-accept-local ipcp-accept-remote bsdcomp -bsdcomp papcrypt For more help type "help COMMAND" where command is either one of the above commands or a portion of a command. (Editors Note - This comes from the slirp .95c change log I believe) ________________________________________________________________________ Question 3.8 in article says >i'm trying to get shell via telnet on slirp, without logging in again. 1.a) Get the file: ftp://blitzen.canberra.edu.au/pub/slirp/extra/slirp.telnetd-b.tar.g 1.b) extract and compile it like you did with Slirp 1.c) place the binary into a directory that is in your path [ Note: [ Can anyone explain in detail what function slirp.telnetd [ adds to slirp? Does it provide the 'telnet protocol'? [ If so, what is contained in the telnet protocol - local echo? [ Xon/Xoff flow control? 2) Add the following line to your .slirprc file (you may wish to pick another shell). I use: shell /usr/local/bin/tcsh 3) Add a line to your hosts file so you can telnet to your shell without having to use the IP number, if you like. For example, my hosts file includes: # # Host file for use on winsock pc running TIA or SLiRP on shell account # # -- SLIP emulator names -- 10.0.2.15 PC-name 10.0.2.2 emulator-host 10.0.2.2 pop-server 10.0.2.1 shell <<<=== Add this line here 10.0.2.1 smtp-server 10.0.2.1 nntp-server news-server (Above is just an example - you may wish to call your services by other names.) [ For you TIA users wondering how to use tia with slirp IP numbers... [ my .tiarc: [ [-n10.0.2.2 [-r10.0.2.15:21 [-p10.0.2.1:25 mailit [-p10.0.2.1:119 nntpd.xover 4) If running Windows, setup an icon that passess the argument "shell" to your favorite telnet application. Double-clicking that icon will connect you to the host and run a shell program. I use: c:\winsock\ewan\ewan.exe shell 5) Running another shell will not execute the commands in your .login file. So, on your shell, move the commands alias, set, path, (everything non-login environment related) from .login to .cshrc (or whatever shell rc file you are using) so when you start up a new shell you will have things the way you are used to them. You could also just put a 'source .login' in your .cshrc if you like. [ I'm don't really understand UNIX enough to know what [ gets passed in to child processes in UNIX - [ anyone what to jump in here? And I think you should be in business. I hope I haven't forgotten anything. Bill moseley@netcom.com ________________________________________________________________________ Question 3.9 Alex Clamann (aclamann@vcu.edu) wrote: : Does anyone have instructions/hints as to how to use Windows 95 : with SLiRP? Works great! 1) Install TCP/IP under network in the control panel 2) The numbers 10.0.2.0 is the default gateway under IP settings in the control panel 3) The number of the local address is 10.0.2.115 4) Set the DNS server to whatever slirp gives you, (the second and third on netcom as the first seems to change) 5) under the win config the very last box needs to be checked. (note: this is second hand from a friend, and he can't remember what the box is called. :( ) 6) create a dialup network account, (it's an option in the dialup network program group) 7) make sure to set the modem setup box and select , (that lets you log in and start slirp. 8) then set server type to PPP 9) use the connect button and when the dialog box comes up, type in your name and password. 10) run slirp with the -P switch (this tells slirp to use PPP) 11) then press continue and win95 should tell you that you are connected. once the connection is running you can use the win/95 utils or the win/95 version of the web browsers. Note: Netscape 32bit is at www.netscape.com jtessin@netcom.com (Editors Note - Another VERY detailed response to this question is found below - I'd love to get feedback as to which I should keep!!!!) >Are there instructions available on how to configure win95,slirp,Free >Agent, and Netscape? And if so would someone post it or its address? Note: The instructions below now accomodate multiple dial-ups by localizing the IP addresses to each dial-up entry, rather than making them global throughout the system. Revisions have also been made for better clarity. The following are comprehensive instructions on getting Win95 to network over a dial-up using SLIP/PPP, with consideration for TIA & SLiRP. These are specific to the CD release version (950r6) of Win95. These assume that you have a modem, a phone line, and have an Internet account with an ISP (Internet Service Provider). Info needed: Your IP address (if static IP); your ISP's name, domain names, and IP addresses. Components needed: Dial-Up Networking; DSCRIPT; TCP/IP. **Always select OK to close a settings screen and not the Close (X) button, or otherwise the changes you made will be ignored. ---------- ADDING NEEDED COMPONENTS: To add Dial-Up Networking, Open Start | Settings | Control Panel | Network | Add | Adapter | Microsoft | Dial-Up Adapter. Click OK. The Dial-Up Adapter should now be present in the Network window. Win95 will ask to restart system, don't restart just yet. Delete all other entries in the window (aside from the Dial-Up Adapter), by selecting them and clicking Remove. To add DSCRIPT, Open Start | Settings | Control Panel | Add/Remove Programs | Windows Setup | Have Disk. Enter [CD drive]:\ADMIN\APPTOOLS\DSCRIPT and press OK. [Note: DSCRIPT may not be present in the Win95 floppy disk version.] To add TCP/IP, Open Start | Settings | Control Panel | Network | Add | Protocol | Add | Microsoft | TCP/IP. Click OK. You should now have the Dial-Up Adapter and TCP/IP icons in the Network window. Win95 will ask to restart system. Press No to keep on going. Select TCP/IP, and click on 'Properties'. Select 'Gateway' tab. Enter 1.0.0.1, and press the Add button. Press OK's until you've closed the Network screen. After rebuilding its driver database, Win95 will again prompt you to restart the system. Select No to keep on going. ---------- MAKING A DIAL-UP ENTRY: Open Start | Programs | Accessories | Dial-Up Networking. Win95 will activate the Make New Connection wizard. Press Cancel for now. Select Connections (in the Dial-Up Networking folder menu) | Settings. Enable 'Redial' (retry = 99, 0 min 1 sec between retries). Select 'Don't prompt to use Dial-Up Networking'. Press OK. Double-click on the Make New Connection icon. Enter name of the ISP for the top box (ex: Eskimo North). Select your modem from the list, or let Win95 autoselect your modem (if modem is not already set up). Select 'Configure' (modem) [General] Select max speed (I use 57600 for 28.8K, for typical 2:1 compression ratio). Click OK. [Connection] Enable 'Cancel the call if not connected within _60_ secs' Enable 'Disconnect a call if idle for more than _15_ mins' Click Next; enter the ISP's telephone access number when prompted (no area code, unless it is a long-distance call.) Click Next; enter a name for the dial-up entry (ex: Eskimo). Click Finish. A connect icon for the ISP will appear in the folder. Right-click on the connect icon. Select Properties | Server Type. Select SLIP, CSLIP, or PPP (use this for SLiRP or TIA 2.x) from the drop-down menu. Disable 'Log on to network'. Disable 'NetBEUI' and 'IPX/SPX Compatible'. [If you select SLIP or CSLIP, these will already be greyed out.] Click on 'TCP/IP Settings'. Select 'Specify name server address'. Enter the IP address(es) of the various domains of the ISP. (Ex: for Eskimo, enter 204.122.16.13 for main server, 204.122.16.40 for tia server) If dynamic IP address, select 'Server assigned IP address'. If static IP address, select 'Specify an IP address' and enter your IP address, as provided to you by your ISP. If TIA or SLiRP, select 'Specify an IP address' and enter 192.0.2.1 (anything you want, really) for IP address. You can drag the ISP icon you've just made out onto the desktop for quicker access. Repeat this section for any additional dial-up entry you want to create. ---------- MAKING A LOGIN SCRIPT: You've made a dialing connection icon for the ISP, but you need a script to get past the login and start SLIP/PPP/TIA. DSCRIPT will handle this chore. Open Start | Programs | Accessories | Dial-Up Scripting Tool The dialing connection you've just made should be presented as an entry inside the Connections window. Since it's the only entry, it should already be highlighted. Click on 'Browse', and select one of the sample script (SCP) files for modification. Then click on 'Edit' to modify the file to fit your ISP login. Below is a sample script for Eskimo North: ; Eskimo North login script proc main transmit "^M" waitfor "Selection ==>" transmit "4^M" waitfor "login:" transmit "YourName^M" ; replace with your login name waitfor "Password:" transmit "YourPasswd^M" ; replace with your password waitfor "bash$" ; replace with your prompt transmit "tia -ppp^M" ; use this for TIA 2.x ;transmit "slirp -b 57600 -P^M" ; use this for SLiRP ;set ipaddr getip 2 ; use this for dynamic IP address endproc Save the script. Enable 'Start terminal screen minimized'. [For script debugging purposes, you can elect to disable the 'Start terminal screen minimized' option and/or enable the 'Step through Script' option.] Restart Win95. Note: Accessing the SCRIPTER.HLP file may be problematic, as it has no accompanying .CNT (contents listing) file. I wasn't able to access its Topics List, which means no access to the command syntax listing. I ran the help file through an ASCII filter, and reconstructed the syntax listing after some reformatting. If there is sufficient interest, I'll repost it as an addendum. [The Plus! pack's "Internet Option" has the identical Dial-Up Scripting Tool as included in the base Win95 CD, but it has an accompanying SCRIPT.DOC which has the command syntax in it.] ---------- TESTING THE SETUP: Double-click on the dialing-connection icon for the ISP, and click Connect. (You don't have to enter your name/passwd, since you've already hardcoded it into the script file. Be aware, however, that the scripts are saved in plain ASCII which may pose a security problem for multi-user setups). If everything goes smoothly, you will get a Connect message. (I've noted that with SLiRP, it takes as long as half a minute for the TCP/IP connect to be made after the SLiRP command is given to the host shell.) After the Connect message, minimize the window onto the TaskBar, and open up a DOS box. Enter 'telnet [ISP domain name]' (ex: telnet eskimo.com) to connect to your ISP. If telnet is successful, then the setup is good, and you are in business. Win95 also has some other command-line TCP/IP utils, the most important of which is FTP.EXE. Between) telnet and ftp, you have the tools to acquire other winsock apps from the net to add to your stable. hpham@eskimo.com (Hoang Pham) ________________________________________________________________________ 4.0 Emulator Performance Question 4.1 SLiRP has become stable and the lock-up bug was finally fixed(?). I think it's time for new benchmark test on TIA and SLiRP. (*** Well, seems like I will have to do another test in 2 weeks. TIA 2.0 beta will be released in next month. I just got new TIA news.) Anyway, I performed a small benchmark test using ws_ftp. The method used is mostly the same as the previous test I did and posted here few month ago. I transferred file between UNIX host and local PC over serial line three times in each direction and averaged the speed (in Kbps). This time I could use the same Trumpet setting for both TIA and SLiRP, which means you can compare data of the two directly. Also, I used both compressed and non-compressed files in the tests. Let's show you the result first. WS_FTP.EXE (150944 byte, a binary executable) ============================================= TIA SLiRP SLIP SLIP CSLIP PPP --------------------------------------------- Downld 18.06 17.31 18.53 18.45 (Kbps) Upload 18.94 18.88 19.35 19.30 ============================================= WS_FTP.ZIP (117641 byte, ZIP compressed) ============================================= TIA SLiRP SLIP SLIP CSLIP PPP --------------------------------------------- Downld 15.87 14.97 16.24 16.14 (Kbps) Upload 16.36 16.32 16.70 16.66 ============================================= What do you think? It's interesting, isn't it? * Actually, the result is not much different from the previous test. In the previous test, I used MTU of 552 for Slirp and I thought it made Slirp slower than TIA. However, Slirp is still slower than the TIA in SLIP. Slirp gave me *really* good result in CSLIP and PPP. CSLIP is slightly faster than PPP but I think the difference has become small. (Acutually, I lost the old result. ^^; Am I telling you the truth?) * As a result of tcp_input.c fix, Slirp now works even if you don't use Passive mode in ws_ftp. However, you should always get faster transfer if you use Passive mode. This applies to TIA, too. ##### Here's hardware and software information: UNIX -- SparcSun-4/280. SunOS-4.1.3 PC -- Toshiba T3400, i486SX-33MHz, 4MBram, Windows for Workgroups. Modem -- US Robotics WorldPort 14.4K PCMCIA Fax/Modem. WS-FTP version 95.06.11 Recv Bytes 4096 Send Bytes 1500 *Passive Mode* is used in all transferres. Trumpet Winsock version 2.1b MTU 1500, RWIN 4096, MSS 1460. Baudrate 38400 TIA version 1.04c (beta) Slirp version 0.9o (tcp_input.c fixed) [.slirprc] SLIP CSLIP PPP ************** ************** ***************** Baudrate 38400 Baudrate 38400 Baudrate 38400 mtu 1500 compress ppp mru 1500 mtu 1500 mtu 1500 mru 1500 mru 1500 asyncmap 00000000 ************** ************** ***************** *** All Data *** ## TIA ## [SLIP] ws-ftp.exe ws-ftp.zip -------------------------------------- ------------------------------ Down Up Down Up (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) -------------------------------------- ------------------------------ 1. 81.8 18.08 78.0 18.95 72.6 15.88 70.4 16.37 2. 82.0 18.04 78.1 18.94 72.9 15.82 70.5 16.35 3. 81.8 18.08 78.2 18.92 72.5 15.90 70.4 16.37 -------------------------------------- ------------------------------ Ave. 81.9 18.06 78.1 18.94 72.7 15.87 70.4 16.36 -------------------------------------- ------------------------------ ## SLiRP ## [SLIP] ws-ftp.exe ws-ftp.zip -------------------------------------- ------------------------------ Down Up Down Up (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) -------------------------------------- ------------------------------ 1. 85.6 17.28 78.4 18.88 77.3 14.92 70.7 16.31 2. 85.5 17.31 78.5 18.84 77.0 14.98 70.6 16.32 3. 85.4 17.33 78.2 18.91 76.8 15.02 70.6 16.32 -------------------------------------- ------------------------------ Ave. 85.5 17.31 78.4 18.88 77.0 14.97 70.6 16.32 -------------------------------------- ------------------------------ ## SLiRP ## [CSLIP] ws-ftp.exe ws-ftp.zip -------------------------------------- ------------------------------ Down Up Down Up (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) -------------------------------------- ------------------------------ 1. 79.8 18.53 76.4 19.36 71.0 16.24 69.0 16.70 2. 79.8 18.53 76.5 19.33 71.0 16.24 69.0 16.70 3. 79.8 18.53 76.4 19.36 71.0 16.24 69.0 16.70 -------------------------------------- ------------------------------ Ave. 79.8 18.53 76.4 19.35 71.0 16.24 69.0 16.70 -------------------------------------- ------------------------------ ## SLiRP ## [PPP] ws-ftp.exe ws-ftp.zip -------------------------------------- ------------------------------ Down Up Down Up (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) (Sec) (Kbps) -------------------------------------- ------------------------------ 1. 80.1 18.46 76.6 19.30 71.5 16.12 69.2 16.66 2. 80.3 18.42 76.6 19.30 71.4 16.15 69.2 16.66 3. 80.1 18.46 76.7 19.29 71.3 16.16 69.2 16.66 -------------------------------------- ------------------------------ Ave. 80.2 18.45 76.6 19.30 71.4 16.14 69.2 16.66 -------------------------------------- ------------------------------ That's all. (Hope I didn't make any stupid mistake.) Thanks. --- Masa. [Editors' note: I think this one gets the best post of the week award!] ---------------------------------------------------------------------------- 5.0 Miscellaneous Problems/Solutions Question 5.1 > LATEST INFORMATION > -------------------------------------- > > * (21/6/94) I think I finally fixed the "locking-up" problem. Edit the > file tcp_input.c and uncomment the lines: > /* if (so->so_snd.sb_cc) > * (void) tcp_output(tp); > */ > This means you can use a low RWIN again, and still have it work (I > hope). > * (5/6/94) Get version 0.9o, it should fix the nasty SunOS problem, as > well as others. This will be the last release for around a month or > two (provided I find no major bugs (again)), since a) I have tests > coming up, and b) I'm planning big changes/additions to slirp for the > next release (It'll probably be a BETA release, finally). > > [Back To SLiRP Home Page] [Features] [danjo@blitzen.canberra.edu.au] > > Copyright ©1995 Phase One WWW Publishing I tried out the code change and it seems to be working fine for me. I am now able to reduce my RWIN in trumpet back to 4 times my MTU and I have no lockups. o _____ ||Jose Barandiaran | |joseb@twisto.compaq.com | ---------------------------------------------------------------------------- Question 5.2 >sterns@rahul.net (Steven Stern) wrote: >Hi, > I'm running Win95 (build 484) and just tried to run the 32 bit >version of Netscape with no luck. I can't get DNS lookup to work. > >Is this combination possible or will it not work because Trumpet is >not a 32 bit application ? > >BTW the 16 bit version works just fine ! > >Steve > ~~~ > (o o) > ----------------------------------------------------------ooO--U--Ooo----- > Steven Stern email: sterns@rahul.net It seems that the 32-bit version of Netscape cannot communicate with a 16-bit TCP/IP stack. However, you don't need to use Trumpet anymore. Just use SLiRP with the -P or ppp option (for Point-to-Point Protocol). On the Windows 95 end, you'll need to go into Dial-Up Networking in My Computer and define dialer "objects" for each of the numbers you wish to call on your server. The default protocol is PPP and is set under Server Type. You'll then need to set up a dummy IP address in either Network under Control Panel or on the object itself, if your build of Windows 95 supports that (which I think 484 does). There are a few other things, such as Name Servers and Gateways, but since you've already set up Trumpet, you'll know what to put in there. You'll want to specify that Windows 95 bring up the terminal window after dialing so that you can enter your login information. This can be done in Server Type as well. Don't worry about the login name and password in the dialer object; it can't be resolved anyway and you'll connect just fine when you enter it in your terminal window. After entering your user ID and password and finally the SLiRP command line, you simply press F7 (Continue) and you're all set. All of your winsock apps will work, 32-bit and 16-bit. If you have any trouble setting this up, let me know. Maybe I can help. Just short on time at the moment. mailto:davidb@mordor.com ---------------------------------------------------------------------------- Question 5.3 whoa@netcom.com (arlene agcongay) wrote: > >hi, i just got SLiRP working for me the other day, but i have a >question. I'm using OS/2 Warp with SLIRP, and when i start it up, >it tells me that my baud rate is 1200. I would like to configure >this part to a higher baud rate, but i don't know which file to >edit. What i've been doing is opening up another comm software like >ZOC and have it initialize my modem to 38400. but there has to be >an easier way! i'm a newbie to this, so please help me.. =) > >thanks in advance!! > > >-arlene > > slirp -b 38400 will tell SLiRP to send and receive data from your provider's modem at 38,400 bits per second. To receive the data at the fastest possible rate, you'll need to call a number that supports the highest transmission rate possible with your modem and be sure you are connecting at that speed. What concerns me is that SLiRP defaults to 9600 "baud" and should not be reporting 1200 unless you have explicitly requested it with the -b switch. Maybe you are misreading one of the other parameters, such as MTU? db ---------------------------------------------------------------------------- Qeustion 5.4 [ Editors' note: I screwed up the request below...so added the one line to get the context of the original question back.. Sorry 'bout that.] >How does one get to a >unix shell using slirp.telnetd .. no one can answer this for me, it seems >and I haven't been able to find any documentation on the subject.. it's >rather frustrating. Thanks. E-Mail Please. > >-- > ______ >( ____ \ rampage@ccnet.com http://www.ccnet.com/~rampage net-geek Simple, in your .slirprc you have a line such as is mine for tcsh: shell /usr/local/bin/tcsh Then (if 10.0.2.0 is your SPECIAL address as it is for me) you telnet from your local machine to 10.0.2.1 to get a 'shell' on your remote machine. In my case I put a lines in /etc/hosts such as: 10.0.2.0 slirp 10.0.2.1 remote so that I can 'telnet remote' to get a shell or 'telnet slirp' to talk to SLiRP's command line. rdt mailto:rdt@realm.net or mailto:rdt@kaiwan.com ---------------------------------------------------------------------------- Question 5.5 On Sun, 25 Jun 1995 08:34:57 GMT Steven Stern (sterns@rahul.net) wrote in alt.dcom.slip-emulators: : I'm running Win95 CSLIP with Slirp at the other end. After I start : Slirp I get the following msg: : SLiRP Ready ... (autodetect SLIP/CSLIP, MTU 552, 9600 baud) : I'm using a 14.4 modem. Does the message above really says I'm only : connected at 9600 ? : Before Win95 Cslip, I always got 14.4 connections with Trumpet ! : Please help ! You need to specify the baud rate on the command you use to start slirp, like: slirp -b 14400 -c Ahmad -- Ahmad Al-Nusif | E-Mail: morpheus@kuwait.net | ----------------------------------------------------------------------------- Question 5.6 stew1117@netcom.com (stewart coulter) wrote: >Hello, I am using Slirp version O, everything is running fine except the >news. I have a netcom account and was told I need the file NNTPD, where >can I find this file and what type configuring do I have to do to the >slirp O program? Please respond via email >From a directory in your path (probably either your home directory or ~/bin), do ln -s ~seligman/bin/nntpd Or, if you want your own copy (just in case), do cp -p ~seligman/bin/nntpd . This version, written by Scott Seligman, supports XOVER. The TIA version will also work with either TIA or Slirp. Find it at ~barryn/pub/nntpd These are on Netcom, of course, since they're only needed to emulate a normal NNTP server with Netcom's disk-based equivalent. To use this with Slirp, add the following line to your .slirprc file: add exec nntpd 10.0.2.1:119 unless you use the TIA-style addresses, in which case you'd add add exec nntpd 192.0.2.3:119 Lee Dobbs Milpitas CA Voice: 408-946-7860 ldobbs@netcom.com USA Fax: 408-262-9392 ----------------------------------------------------------------------------- Question 5.7 D. Henry (marbling@apk.net) wrote: : In article <3sj8cs$j3e@metz.une.edu.au>, jzhou1@metz.une.edu.au (JUN ZHOU) says: : > : >Hello, : > : >I am trying to run Netscape and Eudora on a PC with a modem. I have installed : >the Trumpet winsock and can loging manually from TCPMAN widows. However, when : >I try to run the wisock applications, the Tcpman is lunched and minimized but : >the Netscape windows never pop up. : > : >Any help is highly appreciated He-he. I used to make the same mistake when I just installed Trumpet Winsock. Here's the catch. If you select 'Manual Login' option from the Trumpet Winsock's Dialler menu, SLIP is automatically disabled. After you manually log in and start your SLIP emulation, don't forget to press the 'ESC' key. It will enable SLIP, and Trumpet Winsock will start talking to your SLIP emulator. If you don't do so, Netscape window will never pop up... I hope this helps. Regards, Stan ---------------------------------------------------------------------------- Question 5.8 In article <3t278g$46r@newsbf02.news.aol.com>, rmpshaker2@aol.com (RmpShaker2) wrote: >Hey guys, When I setup my network settings, my only server type is PPP. I >don't have a PPP connection, I have a slip. I tried configuring the damn >thing, but I found NO option for slip anywheres. I went through all the >help and found jack. Does anyone know how to setup a SLIP? > >Thanks, Chris Unfortunately Win95 does not automatically set-up SLIP protocol, but it's quite easy. Go into control panel, then add/remove software, then Windows Setup, the Have disk, now browse for a file named RNAPLUS.INF, it's on the cd, in think in admin\apptools\slip, and that's it. Now when you set up server you should have cslip and slip options ---------------------------------------------------------------------------- Question 5.9 browe@netcom.com (Bill Rowe) wrote: >In article , stevew@netcom.com (Steve Wilson) >wrote: >>When you start up a shell, you tie-up a certain amount of memory >>with local defines...like the path you use to search for commands, >>any special "environment variables," etc. If you fork off another >>shell via telnetd, it will inherit this same environment...what >>Lee is saying is that you probably just get a link to this stuff >>instead of taking up X amount of more memory... > >Are you saying with telnetd the path to my home directory is not >available? If it is available, how could it not be taking memory? If it >isn't available, this seems to me a good reason not to use telnetd to >access my shell account. > >Usually, if I telnet to my shell it is because I want to manipulate one or >more files there. Lack of access variables which are defined at login such >as $PATH would seem to make it significantly more difficult to do the >usual things with a shell account. All the environment variables that were set by your login shell process *are* available to any subprocess. If the subprocess happens to be another shell, any reference to an unmodified environment variable just points back to the memory block attached to your login process. So, things like your path, term, prompt, shell, etc., don't have to be recopied -- they're already available. The situation is different, however, when you start up a shell from an intermediate process like telnetd. telnetd doesn't pass the environment variables to the shell, so it starts up with just the default subshell parameters. You have to tell it to do something extra. If your shell is one of the csh derivatives, you need to tell it to execute your .login file in addition to the usual .cshrc file. One way to do this is exec csh -l which replaces the original telnet shell process with another one, but this time reading the .login file first. There are equivalents for the Bourne derivatives so that it executes your .profile first, but I don't remember what those are right now. By the way, the shell variables are only part of the environment memory usage. There is some environment memory dedicated by your host to keep track of your login process and all your subprocesses. This includes space for: All the open files Access rights to files and processes The working directory The file creation mask Values of resource limits Signals to be ignored by the parent Signals not to be ignored by the parent That's why it's still better for the host if you use a subshell through telnetd and then set your PATH, etc., than if you start a completely new login session. Does this help? Are we having fun yet? :) Lee Dobbs Milpitas CA Voice: 408-946-7860 ldobbs@netcom.com USA Fax: 408-262-9392 ---------------------------------------------------------------------------- Question 5.10 wmcbrine@clark.net (William McBrine): > FTP-PM never connects when I use it under SLiRP. Pretty much everything > else works fine, including FTP and NcFTP, except of course ping. What's > the problem, and is there a fix? Well... You actually stated the problem yourself. Ping soesn't work, and FTPPM uses PING. You can tell the IAK that PING is not available by remarking the line starting with "icmp" in the file "protocol" thats the fix). /Jonas Jonas Eckerman FSDB jpe@algonet.se www.algonet.se/~jpe/ ---------------------------------------------------------------------------- Question 5.11 Editors' Note: This question is slightly out of date. Tia 2.0 is available now...but the discussion is still relevant. In article , Mike Russo wrote: >At least, that's how I got TIA to work. I hope either TIA 2.0 or the >next SLiRP will support this protocol, along with PPP (and maybe automatic >port redirection? in my dreams?) =) PPP is in TIA 2.0 (as is CSLIP). It is working even as I type this, but we've not released TIA 2.0 yet, so I can't say more at this time. The others are tough nuts to crack, so let me address them one at a time. The ICMP protocol is simple and easily implemented. However, there is one minor problem (or major depending on who you are): root access. ping must be run by root to work (or be setuid uid 0). TIA or SLiRP would need to be installed setuid, which violates one of the prime assumptions that at least TIA has: No extra ordinary privs should be required to use TIA. So ICMP could be implemented for the link, but not forwarded to other machines. TIA 1.x doesn't choose to do this. TIA 2.0 likely won't either. Creative solutions to this problem may be possible, but I've not had time to fully investigate my ideas, so I'll not speculate on them just now. Automatic port redirection is also hard. When the TIA client[*] has a program that wants to listen on a port, nothing happens over the wire. Sure, buffer space gets allocated, the TCP stack's internal data structures are setup, but no packets are sent over the link. Since no data flows accross the link, TIA (and SLiRP) have no way of knowing that you desire to have a server or do port redirection. Also, if TIA or SLiRP were to try to do this, how could it inform you of the ports that it chose for the servers you wish to run? How would you know you needed to connect to port 8456 to connect to your FTP server? That's why you need to tell TIA (and SLiRP) how to redirect the ports. I wish I could have told you that TIA 2.0 solves all the hard problems that exist in your dream product, but I can't because some of them are very hard nuts to crack. [*] A TIA client is the machine at the end of the point to point link that isn't running TIA. Warner Losh "VMS Forever" home: imp@village.org Cyberspace Development, Inc work: imp@marketplace.com ---------------------------------------------------------------------------- Question 5.12 In article <3tqam6$lsv$1@mhafm.production.compuserve.com>, Jeff Morganstern <102174.225@CompuServe.COM> wrote: > Can someone explain to me why (from an annex type server) I can use > rlogin to my unix account and slirp works fine, but if I telnet > there, it does not? I'm able to get into my (free but far away) > unix account through a local gopher server, but it can only telnet > there. In order to use the rlogin protocol, I need to dial up > directly (expensive). Is there any way around this? > > Thanks. > > Jeff The reason is that rlogin is a much simpler program than telnet, and is therefore more "transparent" in terms of not mucking about with the characters that go through. For SLiRP to work, you need a relatively "clean" 8-bit connection. Telnet may do any or all of the following. 1. Strip out the eighth bit, leaving a 7-bit link. 2. Intercept certain characters, and translate them into telnet escape sequences. 3. Break the link if it receives certain characters. That is not to say that it is impossible to get telnet to work. Depending on the version of telnet you may be able to get an eightbit link by either specifying it as an option (telnet -8), or by careful settings on the machine you are telnetting from, for example, stty -parenb ; no parity, 8-bit characters stty crtscts ; hardware flow-control stty -ixon ; no XON stty -istrip ; don't strip off eighth bit ; what else?? mdmbuf? You may also need to use PPP so that you can "escape" the characters that would telnet would intercept. There may be other things that need to be done. I've been able to get a connection established with slirp through a telnet link, but have not gotten it to work satisfactorily, whereas rlogin works fine. Your results may differ. --------------------------------------------------------------------- Question 5.13 In article <1995Jul13.110622@acad.drake.edu>, jms015@acad.drake.edu (Pilfered Publishing TM) wrote: > I login with ZTerm and quit without hanging up and then start InterSLIP > on my Mac. I load up telnet 2.6 and try the default as stated in the Home > page "10.0.2.0". I was never able to get the special "telnet 10.0.2.0" to work form my mac using interslip, but it works using macppp. At any rate, all the other internet functions worked fine with both setups, although I highly recommend macppp, as it is much faster. -- Marshall Levin ------------------------------------------------------------------- Question 5.14 Daniel Ptacnik - BBMD/F94 (dptacnik@acs.ryerson.ca) wrote: : : I just got slirp to work properly. But I don't know what my pop mail (smtp) : server is, is there a unix command that can tell you this info. Or : another other way of determining this. Any help is gladly appreciated. : Everthing else works fine like netscape, ftp, and irc. BTW I am using : slirp v.9o. Thanx again : First, are you sure that your service provider supports POP at all? The POP server would have to run on the same machine as your mailbox in order to work (not quite true, it could run on a machine that NFS mounts your mailboxes too). Since your email address is: dptacnik@acs.ryerson.ca you would find out where your mail is delivered by looking for the DNS MX record for that address: dig acs.ryerson.ca mx ;; ANSWERS: acs.ryerson.ca. 843 MX 10 hopper.acs.ryerson.ca. Next, find out if there is a POP server running on this host by telneting to port 110 (POP3) or port 109 (POP2) and see what you get: telnet hopper.acs.ryerson.ca 110 Trying 141.117.101.8... Connected to hopper.acs.ryerson.ca. Escape character is '^]'. +OK hopper.acs.ryerson.ca POP3 3.3(18) w/IMAP2 client (Comments to MRC@CAC.Washington.EDU) at Thu, 13 Jul 1995 15:10:16 -0400 (EDT) You're in luck, your MX host has a POP3 server running (looks like the POP server that comes with Pine, since it mentions IMAP too). Close this connection by pressing control-backbracket and entering "close" at the telnet prompt, don't just break the connection, it isn't nice. Now you are ready to enter this information into your POP client: POP host: hopper.acs.ryerson.ca SMTP host: hopper.acs.ryerson.ca Have fun. -- | John Lucas jlucas@uvi.edu | slirp-1.0.17/docs/slirp.doc0000644000175000017500000014702710117224161014563 0ustar roverrover Slirp Manual Copyright (c) 1995 Danny Gasparovski All Rights Reserved. Updated 18/12/95 =============================================================================== Contents 0. Introduction - What is Slirp?.............................................. 1. Slirp Copyright............................................................ 2. Slirp Features............................................................. 2.1 Advantages of real SLIP/PPP over Slirp 2.2 Advantages of Slirp over real SLIP/PPP 3. Unpacking and Compiling Slirp.............................................. 4. Running and Quitting Slirp................................................. 5. Slirp Special Addresses.................................................... 6. Configuring Slirp.......................................................... 6.1 Slirp Commands 7. Port Redirection........................................................... 7.1 What is Port Redirection? 7.2 How do I Redirect a Port? 7.3 Common Port Redirections 8. Setting the "baudrate" Option.............................................. 9. Connecting a LAN over Slirp................................................ 10. Load-balancing............................................................. 10.1 What is Load-balancing? 10.2 Compiling Slirp for Load-balancing 10.3 Setting up your Configuration Files 10.4 Connecting More Modems 10.5 Load-balancing Notes 10.6 Tuning the Connection 11. Link-resumption............................................................ 11.1 What is Link-resumption? 11.2 How do I use Link-resumption? 12. Technical Information about Slirp.......................................... 8.1 Which programs do not work over Slirp? 13. Troubleshooting............................................................ 13.1 Other Troubleshooting Hints 14. Answers to Frequently Asked Questions (FAQs)............................... 15. Getting Help............................................................... 9.1 Contacting the Author 16. Thanks..................................................................... 0. Introduction - What is Slirp? =============================================================================== Slirp is a TCP/IP emulator which turns an ordinary shell account into a (C)SLIP/PPP account. This allows shell users to use all the funky Internet applications like Netscape, Mosaic, CUSeeMe, etc. 1. Slirp Copyright =============================================================================== Slirp was written by Danny Gasparovski. Copyright (c) 1995 Danny Gasparovski. All Rights Reserved. Slirp is free software; "free" as in you don't have to pay for it, and you are free to do whatever you want with it. I do not accept any donations, monetary or otherwise, for Slirp. Instead, I would ask you to pass this potential donation to your favorite charity. In fact, I encourage *everyone* who finds Slirp useful to make a small donation to their favorite charity (for example, GreenPeace). This is not a requirement, but a suggestion from someone who highly values the service they provide. The copyright terms and conditions: ---BEGIN--- Copyright (c) 1995 Danny Gasparovski. 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 acknowledgment: This product includes software developed by Danny Gasparovski. THIS SOFTWARE IS PROVIDED ``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 DANNY GASPAROVSKI 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. ---END--- This basically means you can do anything you want with the software, except 1) call it your own, and 2) claim warranty on it. There is no warranty for this software. None. Nada. If you lose a million dollars while using Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. If these conditions cannot be met due to legal restrictions (E.g. where it is against the law to give out Software without warranty), you must cease using the software and delete all copies you have. Slirp uses code that is copyrighted by the following people/organizations: Juha Pirkola. Gregory M. Christy. The Regents of the University of California. Carnegie Mellon University. The Australian National University. RSA Data Security, Inc. Please read the top of each source file for the details on the various copyrights. 2. Slirp Features =============================================================================== * Freedom. It's free, in every sense of the word. * Source code. Slirp comes with *all* source code. * Portability. Slirp should compile on most Unix compatible Operating Systems, thanks mainly to the GNU Autoconf package. * Flexibility. You can use *any* Operating System on your home PC provided you can get SLIP/PPP software for it. * 4.4BSD TCP/IP code base. The TCP/IP code is based on 4.4BSD which is widely regarded as a very stable and complete implementation. This means it does all the things expected of TCP implementations. E.g: slow start, congestion avoidance, exponential back-off, round-trip-time calculation, delayed ACKs, Nagle algorithm, incoming and outgoing IP fragments, etc. The TCP/IP code was actually taken from the excellent FreeBSD 2.0 sources. In fact, I went out of my way to do as little modification to it as possible. Most things that I regarded as unnecessary (E.g.: the rfc1323 performance enhancements) were simply commented out, so if you want to experiment with them, you can. * PPP-2.2 code. Slirp uses code from the wonderful PPP-2.2 package, so you get all the funky PPP-2.2 bonuses like BSD-compression (if your PC supports it). * Port redirection. This is used to make your PC look more like it was really connected to the Internet, hence allowing others to access services on your PC, etc. * Program execution. Slirp can execute a program on connection to a certain address/port so you can use things like nntpd if your remote host does not have an nntp server installed. * Load-balancing. You can use multiple modems and Slirp will "balance" the load on each modem. So, for example, if you load-balance two 28.8K modems your throughput will be as if you had one 57.6K modem. There is no inherent limit as to how many modems you can load-balance, if you have the modems and phone lines, Slirp will slurp them all up! * Link-resumption. If your modem dies, or the connection is somehow lost, you can log back in, restart Slirp and all your connections will continue as if nothing happened. * Command mode. Telnet to 10.0.2.0 and you can control Slirp using an on-the-fly command mode. Here, you can change certain parameters, close connections, gather statistics, execute programs, get extensive on-line help, etc. * LAN connection. If you have a LAN (Local Area Network) at home, you can connect *all* the PC's connected to the LAN onto the Internet, through Slirp. * And more ... 2.1 Advantages of real SLIP/PPP over Slirp ------------------------------------------ * Compatibility. Every TCP/IP application will work, whereas in Slirp a small subset of applications need emulation to work properly. * Addressability. Since you have a real IP address, anyone on the Internet can contact you or a service you're running directly instead of going through a redirected port as in Slirp. 2.2 Advantages of Slirp over real SLIP/PPP ------------------------------------------ * Security. You control the amount of access others have to your PC via port redirection. Also, you can't be hit by nasty things like the TCP sequence attack, "ICMP bombs", etc. Your PC is effectively firewall-ed from the Internet. * Convenience. You have all the easy, fast access and convenience of a shell account with the option to load up Slirp anytime you want. * Speed. Slirp will usually be faster than real SLIP/PPP especially if the remote host has a fast connection to the Internet, so the remote host will do a lot more buffering. This is highly dependent on your situation though. * Functionality. Because Slirp comes with source, you can easily add new functionality. For example BSD-compression is available in Slirp, whereas few SLIP/PPP accounts have it. Also, all the points mentioned in the Section 2, "Slirp Features" including Link-resumption, Load-balancing, LAN connection, etc. 3. Unpacking and Compiling Slirp =============================================================================== To unpack Slirp type the following command at your shell prompt: gzip -dc slirp-VERSION.tar.gz | tar xvf - Where VERSION is the version of Slirp you are unpacking. This will unpack the Slirp package into a directory called slirp-VERSION. To compile Slirp type the following commands at your shell prompt: cd slirp-VERSION/src ./configure make Notes: if you do not intend to use PPP you can give ./configure the flag "--disable-ppp". This will make a somewhat smaller executable. if you wish to disable the MS type DNS transfer for PPP, or enable MS DCC functionality, you will need to edit the created Makefile and add/remove the options. By default USE_MS_DNS is enabled, MS_DCC is disabled. That's all there is to it. If the compilation failed, read Section 15, "Getting Help" in how to get help. You should be left with a file called "slirp", this is the Slirp executable. After compilation, you can type: strip slirp to make the Slirp executable smaller, but this will also remove any debugging information from the executable. Here are some common ./configure/compiler/pre-processor/etc. problems and suggestions for fixing them: * "configure: error: can not run test program while cross compiling" (or similar errors about cross compiling). This almost always happens due to an error in the setup of the compiler. Look in the file config.log for clues as to why it failed, or send it to your sysadmin for help. * "gcc: xxxxxxx.p: No such file or directory.": This can be completely ignored when running the pre-processor, and can probably be ignored in the actual compilation. The .p files only contain the function prototypes. * "gcc: warning: no previous prototype for XXX'": Again, you can ignore this. * "RUN_MAKE_AGAIN: not found ... *** Error code 1": This is normal. As suggested, simply run "make" again. 4. Running and Quitting Slirp =============================================================================== Once you have compiled Slirp you can delete everything except the file called "slirp", this is the Slirp executable. I suggest you also keep all the files in the "docs" directory, this is where all the documentation is kept. Copy the Slirp executable somewhere in your home directory (E.g.: ~/bin) then to run Slirp, you simply type: ~/bin/slirp ~/bin/slirp -P (for PPP) (or whatever the full path to "slirp" is). That's it. Now you activate your SLIP/PPP software, and start your applications. All you have to remember is this: Once you run Slirp, your shell account now looks exactly like a SLIP/PPP account (with some limitations of course). Any documentation that you have telling you how to connect to a SLIP/PPP account is completely valid for Slirp as well. To quit Slirp you simply kill your SLIP/PPP software and type five 0's (zeroes), with a 1 second gap between each zero. Slirp will then exit and you will be back at your shell prompt. You can also "disconnect" Slirp by typing five 1's (one's), with a 1 second gap between each. This will disconnect Slirp from your shell's terminal and put Slirp in the background. Later, you can type "slirp -l 0" to "reconnect" Slirp again. Please read Section 10, "Load-balancing" and Section 11, "Link-resumption" for more information. 5. Slirp Special Addresses =============================================================================== All addresses of the form 10.0.2.xxx are special to Slirp (this can be changed with the "special addr" command). The following is a description of what each of the addresses mean: 10.0.2.0 This is the Slirp "on-line" configuration address. When you telnet to 10.0.2.0 you can close connections, configure Slirp, redirect ports, etc. all while Slirp is running. Please read Section 6, "Configuring Slirp" for details on how to use this. 10.0.2.1 This is the address used by Slirp to execute programs. For example, if you give Slirp the command "add exec /bin/ls:23", when a connection is made to 10.0.2.1 on port 23, Slirp will execute /bin/ls and redirect the output to that connection. E.g., with "add exec /bin/ls:23", if you telnet to 10.0.2.1 (telnet uses port 23) you will get a list of files in the directory Slirp was started. Another example could be "add exec /path/to/nntpd:119". Now you can tell your News reader to use 10.0.2.1 as the News host and it will actually connect to the running program "nntpd". 10.0.2.2 This is an alias for the remote host. When you connect to 10.0.2.2 you will actually connect to the host Slirp is running on. This is useful if your shell account can be on different hosts, 10.0.2.2 will always mean the host Slirp is running on. 10.0.2.3 This is an alias for your DNS. Slirp will try to figure out your DNS address and all data sent to 10.0.2.3 will be redirected to your DNS address, so you can tell your TCP/IP software to use 10.0.2.3 as your DNS. This can also be useful if your run Slirp from multiple hosts; you don't need to change your DNS for each host. 10.0.2.15 This is the address recommended by Slirp to be used on your PC. However this is merely a suggestion, Slirp does not care what address you use. 6. Configuring Slirp =============================================================================== Slirp can be configured in 3 different ways: the command line, the configuration files, and "on-the-fly" configuration by telnet-ing to 10.0.2.0 and entering the commands there. The configuration file is located in your home directory (~) and is called ".slirprc", hence the path to your configuration file is ~/.slirprc. Options which can appear in a configuration file can also be given on the command line. E.g., If your .slirprc file looks like the following: redir 5022 21 redir X you can achieve the same thing by running Slirp as: slirp "redir 5022 21" "redir X" (Notice the quotes, they ARE significant). The reverse is also true. E.g., if you run slirp as: slirp -P -b 14400 you can create your .slirprc file too look like the following: -P -b 14400 (Notice that only ONE command per line is allowed in configuration files). The 2 types of options can also be mixed. E.g.: In .slirprc: -P -b 14400 redir 5022 21 command line: slirp -P -b 14400 "redir 5022 21" Note that on the command line, any command/option that does not begin with a '-' or '+', and has spaces in it, MUST be enclosed in quotes. E.g., The following are all legal: slirp -P "redir udp 5022 25" -vj -b 14400 slirp "ppp" "baudrate 14400" slirp ppp "baudrate 14400" (Notice that even though "ppp" does not begin with a '-' or '+', it does not need to be enclosed in quotes because it has no spaces in it) The following are NOT legal: slirp baudrate 14400 slirp "-b 14400" (Because "-b" starts with a '-' you must NOT enclose it in quotes) Easy, eh? Note: Whenever Slirp expects an IP address as an argument (E.g., in the command "redir") and the IP address argument is not given, then the default used is different depending on where the command appeared; if it was in ~/.slirprc then the default is 10.0.2.15; if it was in a telnet 10.0.2.0, then the IP address used is the IP address from where the telnet 10.0.2.0 connection was made. For example, if you have a LAN at home and telnet to 10.0.2.0 from one of the hosts and issue a "redir" command, Slirp will use the IP address of the host from where you made the telnet 10.0.2.0 connection. Also, if you use an IP address on your PC other than 10.0.2.15, you should include it as an argument whenever Slirp expects it, for example with the redir command: redir 5555 your.ip.address:5555 A few notes on configuration: * You should have "ppp" or "-P" before any PPP options (because when Slirp parses -P or ppp, it will initialize all related fields, hence clearing anything that was parsed before it). * Upon startup, the configuration is done in this order: 1) ~/.slirprc-N (if using Load-balancing or Link-resumption) 2) ~/.slirprc 3) command-line options This is important because, for example, if you have "initiate-options" (a PPP option) in ~/.slirprc-0, and you run slirp with -P, "initiate-options" will not be valid, because -P will clear the fact that you want options initiated by Slirp (remember, -P should always come before any PPP options). 6.1 Slirp Commands ------------------ Slirp includes an "online-help" facility. To get a list of commands accepted by Slirp give it the command "help". I.e, you can either run Slirp from your shell prompt as: slirp "help" or once Slirp is running, telnet to 10.0.2.0 and type: help To get a brief description of each command simply type "help COMMAND". E.g.: slirp "help baudrate" or help baudrate in telnet 10.0.2.0 will print out the following: Command: "baudrate" Usage: baudrate BAUDRATE Command-line: -b Available: command-line, config-file, telnet change the baudrate Usage tells you the arguments the command accepts, command-line tells you the command line ("dash") equivalent, Availability tells you where the command can be executed from, and the final line tells you exactly what the command does. Also, take a look at the file CONFIG in the "docs" directory in the Slirp distribution. It has a more detailed explanation of the Slirp commands, but is most probably out of date. 7. Port redirection =============================================================================== 7.1 What is Port redirection? ----------------------------- Port redirection is an important concept in TCP/IP emulators because it allows other people to connect to your PC, as well as allowing some programs to work which normally would not work. 7.2 How do I Redirect a Port? ----------------------------- First you need to realize that under Slirp, nobody on the Internet can address your PC directly, since you do NOT have an IP address that anybody else can see. The ONLY way they can contact you is through the remote host (where Slirp is running). What has this got to do with Port redirection? Lots. For other people on the Internet to be able to connect to your PC, Slirp needs to listen for connections on a specific port on the remote host, then "redirect" this connection and have it connect back to your PC. For example, say you are running an FTP server on your PC and you want others to be able to connect to it, get files, upload files, etc. What you need to do is pick a port number, any port number above 1024 (for security reasons), and tell Slirp that any connections on that port are really connections to your FTP server. You do this with the "redir" command. For this example, say you choose 5555 as the port to redirect (this can be ANY number, provided nobody else is using it). You simply give Slirp the command: redir 5555 21 The second argument, 21, is the port that is used by FTP. You could have also used the command: redir 5555 ftp and Slirp will figure out that "ftp" means 21. This command is basically telling Slirp "any connections to this host (where Slirp is running) on port 5555 are really connections to the home PC on port 21 (the port used by the FTP server)". Now you simply tell others to connect to the Remote Host (where Slirp is running), which IS visible on the Internet, on port 5555 and they will be connected to your FTP server. This same technique is used when a program uses a specific port for communication, for example Kali, an IPX emulator over TCP/IP allowing users to run IPX games over the Internet. Kali uses UDP port 2213 for communication so for others to be able to send a packet to your PC on UDP port 2213 you need to do the following: redir udp 2213 2213 All packets now destined for the Remote Host on UDP port 2213 will be sent to your PC on port 2213. 7.3 Common Port Redirections ---------------------------- Here is a list of programs which need a port redirection to work. YOUR_PC_ADDRESS refers to the IP address you assigned to your PC. If it is not supplied, 10.0.2.15 is assumed. Kali redir udp 2213 YOUR_PC_ADDRESS:2213 (Note: you MUST also set your PC's IP address to the same IP address as the Remote Host (where Slirp is running)) IPhone redir udp 22555 YOUR_PC_ADDRESS:22555 StreamWorks redir udp 8000 YOUR_PC_ADDRESS:8000 (the 8000 is configurable) PowWow redir tcp 13223 YOUR_PC_ADDRESS:13223 WebPhone redir tcp 21845 YOUR_PC_ADDRESS:21845 redir udp 21845 YOUR_PC_ADDRESS:21845 (Note: WebPhone uses BOTH tcp and udp port 21845. In addition, you probably need to set your PC's address to the same IP address as the RemoteHost in order to get full functionality) [Please let me know of other programs which require redirection like the above. See Section 15, "Getting Help" for details on how to contact me] 8. Setting the "baudrate" Option =============================================================================== Slirp's "baudrate" option has caused some confusion. This section will explain exactly what it's for and how to use it. When sending data over the modem to your PC, Slirp needs to know how much data it can send over without "saturating" the link. If Slirp was to send as much data as it could, the Operating System would buffer a LOT of it - 20k is not uncommon. This could severely "lag" any telnet connections if you happen to be FTP-ing a file at the same time. This is because when you type a character, you will not see that character on the screen until the the other end sends you the "echo", so if there is 20k worth of data buffered you will need to wait until 20k of data is received before you see that character on your screen. To counter this, Slirp uses the "baudrate" option to limit the amount of data it sends over the link to prevent the Operating System from buffering too much of it. So if you give Slirp a "baudrate" of 14400, Slirp will send data at a rate of 14400 Baud modem (with no compression). In general, the baud rate at which the connection was made should be the "baudrate" you give to Slirp. So, for example, if you connected at 14400 Baud, you should give Slirp the option "baudrate 14400". However, since most modems today do compression (v.42bis), it is very difficult for Slirp know how much data to send to keep the link "full", yet prevent too much buffering by the Operating system. Therefore you should choose a "baudrate" appropriate to your needs: if you use telnet a lot while downloading compressed files, you should set your "baudrate" to the same as the CONNECT speed of your modem. Downloading compressed files should not suffer, and telnet sessions will be far more responsive. However, sending text over the modem will not be as fast, because your modem will compress the data and send it faster than Slirp expects. Giving a "baudrate" the same as the CONNECT speed will effectively turn off modem compression. If you do not use telnet very much, you should set your "baudrate" to the maximum theoretical speed your modem can do. For example, if you connect at 14400 and use v.42bis compression, which can compress up to 4x, you should set your "baudrate" to 14400*4 = 57600. This will ensure any compressible data will get compressed, and a maximum throughput will be attained, at the expense of telnet sessions which will be almost unusable if you happen to be downloading files at the same time. Note however that you can change the "baudrate" setting at any time. Simply telnet to 10.0.2.0 and enter "baudrate XXX" and Slirp will change the rate at which data is sent. This can be useful for example if you're downloading a lot of compressed files, but in the middle of the download you want to read mail. Simply change the "baudrate" to the CONNECT speed, and when you're finished, change it back to the maximum theoretical speed. Also, keep in mind that the "baudrate" is also used for other calculations. For example, if there are many connections, Slirp will try to be fair and send one packet per connection in a round-robin fashion. This makes all connections "smooth" instead of sending a bunch of packets for one connection, then a bunch of packets for another connection, etc. But if the "baudrate" is too high, the is exactly what will happen. Packet priority selection also uses the "baudrate"; I.e., if there are packets queued ready for sending from both an FTP connection and a telnet connection, the telnet packets will be sent first. But again, this will only work if the "baudrate" reflects the amount of data Slirp can send, and generally won't work if you set it to the maximum theoretical connection speed. So here are my tips: * If you download a lot of compressed files and occasionally use telnet, or other "interactive" programs, set your "baudrate" to your CONNECT speed (because already compressed files won't compress any more with the modem compression, so you're unlikely to get faster download's as a result of modem compression); * If you mainly use telnet, or other "interactive" programs, and you occasionally download some compressed files, set your "baudrate" to the maximum theoretical speed (because telnet sessions are usually text, which compresses very well, hence screen updates will be faster. Only when downloading compressed files will you experience severe lag); * If you mainly browse the Web (E.g., using Netscape, etc.), then you should set your "baudrate" to the theoretical maximum speed (because there's lots of text in Web documents which is very compressible, and there's no telnet sessions so lag will not be a problem); I personally have by baudrate set at 14400, the speed at which my modem connects, even though the modems do v.42bis compression. Compressed file downloads are just as fast, and telnet sessions during FTP downloads are surprisingly responsive. Try it yourself, there's a world of difference. 9. Connecting a LAN over Slirp =============================================================================== From the very beginning, Slirp was designed to allow more than one host access the 'Net at once. And doing so is *very* easy. First, you need to setup the LAN (Local Area Network) as if it was really going to connect to the Internet. That is, you must give them each a unique IP (unique relative to each other, not globally unique. E.g., you could give them all an IP address in the 10.0.2.xxx class of addresses). You also must tell each host on the LAN to route it's IP packets to the host that is connected to the Internet via Slirp. Here's a diagram: [Ethernet] ------------------------------------------------- | | | | | [Host A] [Host B] [Host C] [Host D] [Host E] | | | | | <- Slirp link | <- SLIP link | | | | [Remote Host] [Another LAN] | ... to the Internet Now, in this diagram, Host A is the Slirp-connected host. Host's B through to E can also access the 'Net by simply using Host A as the gateway. Host A also must be told to "forward" IP packets (using Remote Host as the gateway) so that it will send any IP packets not destined for itself to Slirp, and vice versa (route all packets sent by Slirp, not destined for itself, back to their respective host's IP). In other words, the Slirp link is just like a real SLIP/PPP link, which is what I've been telling you all this time! :) Note that it is possible to hook up many LAN's to the 'Net by simply following the normal Internet conventions, and route the packets properly. In this case "Another LAN" would use Host E as a gateway to the 'Net, Host E, provided it can forward IP packets, will send them to it's gateway, Host A, which will send it over Slirp, etc. In theory, you could connect another whole Global Internet to the current Internet with no IP address clashes. Not recommended though :) 10. Load Balancing =============================================================================== 10.1 What is Load-balancing? ---------------------------- Load-balancing is the ability to use more than one network interface (modem) at the same time, and sending traffic over both in such a way as to effectively double the throughput (actually, it will "concatenate" the number of modems to one). So, for example, if you have a 28.8k modem, and a 14.4k modem, your throughput will effectively be 28.8+14.4 = 43.2k. Obviously, you need more than one modem, and the same amount of phone lines. You also need a TCP/IP stack that can handle more than one interface (modems). Linux and FreeBSD have no troubles here, but stacks like Trumpet Winsock I don't believe would work, since they can only use one modem at a time. Slirp is flexible enough to be able to load-balance over multiple hosts. For example, you could have two accounts with two different ISP's (Internet Service Providers) and still load-balance over them. 10.2 Compiling Slirp for Load-balancing --------------------------------------- First you must compile into Slirp the ability to have use Load-balancing. To do this, edit config.h (after running ./configure) and go to the lines: #define MAX_INTERFACES 1 #define MAX_PPP_INTERFACES 1 Change the "1" for MAX_INTERFACES to the MAXIMUM number of interfaces (modems) you expect to have at connected once. If you plan to use PPP while load-balancing, you should set MAX_PPP_INTERFACES to the same number as MAX_INTERFACES. Once you've changed these values, (re)compile Slirp. 10.3 Setting up your Configuration Files --------------------------------------- Each modem (or "unit") needs to have it's own unit number, and it's own configuration file called ~/.slirprc-N, where N is it's unit number. When Slirp is run for just one modem, it is assigned unit number 0, so the first time you run Slirp (or if you plan to use link-resumption as per Section 11, "Link-resumption") it will read the file ~/slirprc-0. This file must hold modem/SLIP/PPP-specific configuration (except MTU and MRU!). You shouldn't have any general commands in there like "redir" or "add exec", they go in ~/.slirprc. You must also put the "socket" command in your ~/.slirprc file. If all connections are on the same host with the same account, you should simply put "socket" in your ~/.slirprc file. If on the other hand you have different account, possibly on different hosts, you should put the following in your ~/slirprc file: socket PORT,PASSWORD where PORT is an arbitrary port number for Slirp to listen to (must be greater than 1024), and PASSWORD is the password to use when connecting. This is explained in Section 10.4, "Connecting More Modems". E.g., if your ~/.slirprc currently looks like: redir 5000 21 baudrate 57600 ppp socket ipcp-accept-remote mtu 552 mru 552 Then you should make your config files look like the following: ~/.slirprc: redir 5000 21 socket mtu 552 mru 552 ~/.slirprc-0 baudrate 57600 ppp ipcp-accept-remote (Note: mtu and mru go into ~/.slirprc even though it is a modem-specific command, they are the only exceptions to the rule) 10.4 Connecting More Modems --------------------------- Once you have the config files and interfaces ready, you connect all your modems to the same shell account as the same user. The first Slirp that you run should be run normally, as "slirp" (this is unit 0, the "main" Slirp). If all connections are from the same host and the same account (you have "socket" in your ~/.slirprc file), then for each other connection, you run subsequent Slirp's as "slirp -l UNIT", where UNIT corresponds to that connection's ~/.slirprc-UNIT file. If in the other hand you are connecting from multiple accounts and/or multiple hosts (I.e. you used a command of the form "socket PORT,PASSWORD" in your ~/.slirprc file) then you run subsequent Slirp's as "slirp -l UNIT,HOST:PORT,PASSWORD", where UNIT corresponds to that connection's ~/.slirprc-UNIT file, HOST is the address where the main Slirp (unit 0, as described above) is running, and PORT and PASSWORD correspond to those used in the "socket" command. The reason for a password is so that others who connect to this port are not allowed to send anything to Slirp, which would be a major security hole. Note that you can also pass Slirp the password using the environmental variable SLIRP_PASSWORD (this is for hosts which do not properly delete the password from the argument list). In this case, simply use "slirp -l UNIT,HOST:PORT,-" instead. The "-" tells Slirp the password is in the environmental variable. The -l option MUST be the only command given to all subsequent Slirp's. If there are other commands after it, they will be ignored. If there are other commands before it, it will not work. If it succeeds, you should get a message like "Connected: Attached as unit N on device D". Once you get this message, you can tell your local SLIP/PPP software to make the connection (you should make all interfaces have the same IP address). You can attach and detach modems as you wish. For example, you could be running Slirp as unit 0 as usual, then when you feel like it, you dial-in with your second modem and attach it while all the connections are still active. They will all continue as normal. You can also detach each unit as you wish, by typing 5 ones ('1') into the unit you wish to be disconnected (remember, sending 5 zeroes ('0') will kill ALL the unit's and all running Slirp's). When all unit's are disconnected, Slirp will sit in the background and wait. If you do not re-attach a new unit in 10 minutes, Slirp will exit. 10.5 Load-balancing Notes ------------------------- * There are no limits to how many modems you can attach to one running Slirp. If you have 12 modems, Slirp will slurp them all up! (lucky you! :) * You MUST use the same MTU/MRU on all interfaces (and hence MTU/MRU should only be in ~/.slirprc). This is the only *real* limitation when using load-balancing. It is needed because of the way Slirp allocates data (mbufs) and the fact that at the TCP/UDP layer, Slirp does not yet know over which interface it is going to send the data, and so it can't tell how big the packet is allowed to be. I suppose I *could* lift this restriction, but I don't wanna :) (I don't think the extra code justifies the *small* gain). You should also try and keep both MTU and MRU the same. * Because SLIP is dumb, you should be careful when attaching a new SLIP unit. As soon as you attach the new unit, Slirp will start sending data over it. Try and attach it quickly, and keep traffic to a minimum when attaching. PPP on the other hand does not suffer from this, since it will not be active until the two ends negotiate all options etc. and mark the interface as "up". * Do NOT use vj compression any ANY of the interfaces when using more than one link. It will not work, period. * You can mix SLIP/PPP interfaces in whatever way you wish. E.g.: have 2 modems using PPP and 1 modem using SLIP. * The load balancing is implemented before the network, ip, layer: tty1 -- slip unwrap -\ + icmp ---- udp emulation +---- ip processing ----+ udp ---- udp socket tty2 -- ppp unwrap -/ + tcp ---- tcp socket As a result, the maximum datalink layer frame length, MTU/MRU, for all connections must be the same and no compression of any kind is possible. 10.6 Tuning the Connection -------------------------- The two variables Slirp uses to determine the ratio of data which should go to each unit is the "baudrate" and "towrite_max", as given to it via the ~/.slirprc* files (baudrate is per-unit, towrite_max is the same for all units). The "baudrate" should be the maximum theoretical throughput on that modem, and, more importantly, each unit should be given a baudrate which is reflective of it's performance relative to the other units. I.e., the ratio of any 2 "baudrate"'s on any 2 units should be the same as the ratio of the 2 modems actual baudrate. E.g.: if you have 2 modems that are the same speed, the "baudrate" should also be the same. Or, if one modem is twice as fast as the other, then the baudrate should also be twice as fast as the other, etc. Note: play around with the baudrates to get the best results. Sometimes, depending on the type of data, setting the baudrates to the actual CONNECT speed can improve performance. The "towrite_max" option tells Slirp the minimum number of bytes it will write to each modem before it "backs off" and starts baudrate calculations. Why is this important? Resolution. If towrite_max is only 1, then each modem will be either "ready" or "not ready" with nothing in between; nothing to determine which modem has been written to the most recently. Conversly, if you have towrite_max at 20k and you have a 2400 baud and a 28.8k baud modem, then Slirp will write 20k to each modem before "backing off" and doing any calculation. This means the 2400 baud modem will have 20k of data sent over it, no matter what the situation, which is obviously wrong (consider sending a 40k file; the load will be equally shared between the two modems, which is obviously wrong). In general, "towrite_max" should be higher for faster modems. E.g., I'd recommend 2048 when load-balancing over 28.8k modems. So basically, it comes down to this: the "baudrate" determines how to share the data between the modems, the "towrite_max" determines when to start calculating the load share. There is no set formula to determine what these should be, since a lot of it is determined by the nature and type of data being sent over the modems. Use these suggestions as a guide, but there's no substitute for good'ol trial-and-error. During the initial tests, one tester regularly acheived 6.6k/sec with 2 modems connected at 31.2K. 11. Link-resumption =============================================================================== 11.1 What is Link-resumption? ----------------------------- Link-resumption is the ability to resume all connections even if the modem gets accidently (or deliberately) disconnected. 11.2 How do I use Link-resumption? ---------------------------------- To be able to resume a connection you first need to setup your configuration files similar to when using Load-balancing. See Section 10.3, "Setting up your Configuration Files [for Load-balancing]" to see how to setup your ~/.slirprc-0 file. Once the configuration files are setup, all you need to do is always run Slirp as "slirp -l 0". Do NOT include the "-l 0" in your ~/.slirprc file, it MUST be on the command line. You can run Slirp like this even if there is no link to be resumed, Slirp will run as normal in that case. Also, remember that sending 5 1's down the line will detach only the current link. This allows you to do funky things like detach the current PPP link, then re-attach it as a SLIP link, without disturbing any of the current connections. Note that if you do not resume your disconnected link within 10 minutes, Slirp will exit. 12. Technical Information about Slirp =============================================================================== 12.1 Which programs do not work over Slirp? ------------------------------------------- Any programs that bind()'s a port, then tell the other end of the connection where they should connect() to this bound port. For example, when you "get" a file during an FTP session, the FTP client bind()'s a socket, has a look at which port the socket is bound to, then tells the FTP server the address and port of this socket (with the PORT command). The FTP server then connect()'s to this address/socket pair. Now, since your machine isn't really on the Internet, this connect() request will not arrive to your host, so it will not work. Slirp emulates this by bind()ing it's own port on the server that *is* on the Internet, and tells the FTP server about *that* address/socket pair. When the server connect()'s to it, Slirp will then connect back to your machine. At present, the following programs are emulated: rlogin ftp ksh irc (for /dcc) RealAudio talk/ytalk/ntalk CUSeeMe 13. Troubleshooting =============================================================================== Symptom ------- The connection will "freeze". E.g., while downloading a picture on WWW it will stop halfway and no connections will continue. Diagnosis --------- You probably don't have an 8bit clean link. Cure ---- You should try and find out from your sysadmin which characters need to be "escaped", then tell Slirp about them using the "asyncmap" and "escape" commands. Note that you need to use PPP for this to work. (One way to test for 8bit cleanliness is to download a BINARY file with Z-Modem. If the file doesn't make it, you have a "dirty" link) One thing you might try is run Slirp as: slirp "asyncmap ffffffff" "escape ff" (quotes included!) This will tell Slirp to escape the most common "nasty characters. Symptom ------- You can connect to hosts using numerical addresses (of the form aa.bb.cc.dd) but you cannot connect to hosts when you use their hostname (E.g.: ftp.cdrom.com). It usually times out with a DNS error. Diagnosis --------- You probably did not set your DNS address properly. Cure ---- Try setting your DNS address to 10.0.2.3. This should work for most situations. If that fails, go to your shell prompt and type "nslookup". This should print the address and hostname of your DNS server. Use the numerical IP address as your DNS. Do NOT use the hostname. If you still can't find your DNS address, ask your sysadmin for it. 13.1 Other Troubleshooting Hints -------------------------------- 1. Try turning down, or off the optimizer on the compiler. 2. Try compiling with the -DDEBUG option enabled, and running with debugging, and ppp debugging enabled. eg. slirp -P -d -1 debugppp This will generate the files slirp_debug, and slirp_pppdebug which may have useful information in them. (Note: The options are parsed fairly late in the startup procedure, so some stuff which would appear to be logged isn't) ** Update ** You can now turn on debugging early, by uncommenting the line in main.c In which case you should not put the -d -1 on the command line. (It causes the file to be opened again later, overwriting all the early stuff) 3. CYGWIN There is a stacktrace.sh shell script that will give you the location slirp crashed, if it crashes. 14. Answers to Frequently Asked Questions (FAQs) =============================================================================== Q1. Can I use Slirp through Telnet or Rlogin? A1. Yes, usually. But this is highly dependent on your situation. The reason Slirp usually doesn't work through telnet is because of the ^] character is interpreted by the telnet client, and 0xff interpreted by the server. While you can tell Slirp to escape these characters while using PPP, it may not be possible to get your local PPP software to escape characters greater than ASCII 31. Rlogin also interprets the ~ character, which may interfere with PPP (especially considering ~ is ASCII 0x7e which is used by PPP as the "end of packet" character"). If your PPP software is unable to escape these characters, or you're using (C)SLIP (which must have an 8bit clean link), your best bet is to try and make the link 8bit clean. For example, on some systems you can give telnet the -8 flag to make the link 8bit, and -E to stop it from interpreting the ^] character. Similarly for rlogin; -8 to make the link 8bit, -E to stop rlogin from interpreting the ~ character. You should look at the telnet and rlogin manual pages ("man telnet" and "man rlogin" respectively) to see if your telnet/rlogin has similar options. Another possible solution is to use Slirp's ability to work over multiple hosts. See Section 10, "Load-balancing" for details on how to disconnect/reconnect Slirp sessions using Internet-domain sockets. Q2. How do I run an X program on another host and have it display on my PC? A2. Use the "redir X" command in ~/.slirprc. This will redirect a port for use with X programs. On startup, Slirp should print something like: X Redir: In sh/bash/zsh/etc. type: DISPLAY=IP.ADDRESS:X.Y; export DISPLAY X Redir: In csh/tcsh/etc. type: setenv DISPLAY IP.ADDRESS:X.Y Now, when you telnet to the host you wish to run the X programs from, you should do as Slirp suggest above; type either of the two commands, depending on which shell you are using. You could also run the X program as "xprog -display IP.ADDRESS:X.Y" as printed above. If you missed what Slirp displayed on startup, you can telnet to 10.0.2.0 and give Slirp the command "show X", and the above will be printed. Note that you also have to make sure your X server will accept the connection. See the man page for xhost and Xsecurity. Be careful with issuing commands like "xhost +", this will allow anyone to connect to your X server and do basically anything they want. Q3. When I run "talk" or "wintalk", etc. I am able to send requests to other people but they cannot send requests to me. Why? A3. You won't be able to receive talk requests, period. This is because Slirp never see's the incoming talk request; it is sent directly over the modem, most likely corrupting any incoming packet with it (which will have to be retransmitted). Slirp turns off your messages so the person who tries to talk to you should receive a "User is refusing messages" error. Q4. I can't telnet to 10.0.2.0, the Slirp control address. What's wrong? A4. Your TCP/IP stack probably has a problem with addresses ending in 0. Edit the file ctl.h in the "src" directory and change the 0 in the line: #define CTL_CMD 0 to something else, say 10. Then you "telnet 10.0.2.10" to get the Slirp command-line. Q5. I'm having a few problems with Slirp and want to try and find the problem myself. Does Slirp have any debugging facilities? A5. Yes. After you type ./configure, edit Makefile and uncomment the -DDEBUG argument in the COMMON_DEFS section. I.e. the line: COMMON_DEFS = -I. -I${srcdir} -DUSE_PPP #-DDEBUG should look like: COMMON_DEFS = -I. -I${srcdir} -DUSE_PPP -DDEBUG and recompile. Then, simply give Slirp the arguments "-d -1" and Slirp will log lots of stuff to a file called slirp_debug. Level -1 logs the most. Q6. My ISP logs me out if I idle too long. How can I get Slirp to prevent this? A6. First of all, the idle-logout mechanism is used for a reason: to prevent people from hogging a modem which is not in use. So if you're idle, logout and give others chance to use the modem. Having said that, you can make Slirp use TCP keep-alive timers to regularly probe each TCP connection. To activate this, add: keepalive to your ~/.slirprc file. This will make Slirp probe each TCP connection every minute or so. You can change this interval by giving keepalive the number of seconds: keepalive SECONDS Note that no probes will be sent if there are no TCP connections. So you need at least one active TCP connection for this to work. Q7. When I ftp to a non-standard port (like when another Slirp user is redirecting a port for their ftp server on their PC) it doesn't work. Why? A7. You need to tell Slirp about the non-standard port by issuing the command: add emu ftp PORT where PORT is the port you are ftping to. The same goes for other emulated services. 15. Getting Help =============================================================================== There are several sources of help. First, read Section 13, "Troubleshooting" and Section 14, "Answers to Frequently Asked Questions (FAQs)". If that fails, try the Slirp Home Page at: http://blitzen.canberra.edu.au/slirp There are lots of neat links there to other pages which have specific configuration information. There is also a Newsgroup dedicated to SLIP-emulators called alt.dcom.slip-emulators. You will find lots of discussion about Slirp and other "SLIP-emulators". The FAQ (Frequently Asked Questions) for alt.dcom.slip-emulators is included in the "docs" directory, I would suggest reading this as well. If all else fails, send me e-mail to danjo@blitzen.canberra.edu.au with the following information: * Output of the command "uname -a" on the remote system; * Operating System name and version you run on your PC; * Version of Slirp you are using (IMPORTANT!!!); * If you managed to get Slirp running, run Slirp as "slirp -S" then try whatever failed. When you exit Slirp, you should have a file called "slirp_stats". Send me this file; and * Anything else you consider relevant. *PLEASE* include all the above information. If you do not, I may simply press "d". I can't guarantee a response, but I will try my best. 16. Thanks =============================================================================== A big "THANK YOU!" goes to the following people for their help in creating Slirp. Juha Pirkola, Gregory M. Christy, The Regents of the University of California, Carnegie Mellon University, The Australian National University, and RSA Data Security, Inc. whose source code is used throughout Slirp. Slirp would not be without them. Thanks to all the contributors who helped with bugs, suggestions, code, etc. Read the file ChangeLog to see exactly who helped with what. A special thanks goes to Chris Metcalf and Juha Pirkola for their contributions (see ChangeLog). They put in extra effort and Slirp wouldn't be the same without their help. Thanks guys! Thanks to all the people who sent very kind and encouraging e-mail, it's sincerely appreciated. Thanks to all the admins and Head Honcho's at UCNet, the University of Canberra Computer Club ("blitzen") who gave me some real-estate on their machine (blitzen.canberra.edu.au) to work with (thanks to Tony Delroy for giving me the account originally). Hey! Why don't you check out their home page at http://blitzen.canberra.edu.au/? Thanks to Brazil for coffee (and Sepultura! :) Thanks to the laws of physics, the building blocks of the universe. The End =============================================================================== I hope you enjoy using Slirp as much as I enjoyed writing it. Dan ... slirp-1.0.17/security.patch0000644000175000017500000003151310116565102014675 0ustar roverroverdiff -NurbB slirp-1.0.14pre1/src/debug.c slirp-1.0.14pre1-new/src/debug.c --- slirp-1.0.14pre1/src/debug.c 2000-09-30 15:23:36.000000000 -0700 +++ slirp-1.0.14pre1-new/src/debug.c 2004-06-19 19:01:38.000000000 -0700 @@ -299,7 +299,8 @@ for (so = tcb.so_next; so != &tcb; so = so->so_next) { - n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + n = snprintf(buff, sizeof(buff), "tcp[%s]", + so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); while (n < 17) buff[n++] = " "; buff[17] = 0; @@ -313,7 +314,7 @@ for (so = udb.so_next; so != &udb; so = so->so_next) { - n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + n = snprintf(buff, sizeof(buff), "udp[%d sec]", (so->so_expire - curtime) / 1000); while (n < 17) buff[n++] = " "; buff[17] = 0; diff -NurbB slirp-1.0.14pre1/src/ip_icmp.c slirp-1.0.14pre1-new/src/ip_icmp.c --- slirp-1.0.14pre1/src/ip_icmp.c 1999-08-14 14:47:23.000000000 -0700 +++ slirp-1.0.14pre1-new/src/ip_icmp.c 2004-06-20 15:25:31.000000000 -0700 @@ -229,8 +229,8 @@ ip = mtod(msrc, struct ip *); #if DEBUG { char bufa[20], bufb[20]; - strcpy(bufa, inet_ntoa(ip->ip_src)); - strcpy(bufb, inet_ntoa(ip->ip_dst)); + strncpy(bufa, inet_ntoa(ip->ip_src), sizeof(bufa)); + strncpy(bufb, inet_ntoa(ip->ip_dst), sizeof(bufb)); DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); } #endif diff -NurbB slirp-1.0.14pre1/src/main.c slirp-1.0.14pre1-new/src/main.c --- slirp-1.0.14pre1/src/main.c 2001-03-25 19:38:24.000000000 -0800 +++ slirp-1.0.14pre1-new/src/main.c 2004-06-20 15:09:22.000000000 -0700 @@ -141,14 +141,14 @@ } } strcpy(buff, "/tmp/"); - strcat(buff, username); + strncat(buff, username, sizeof(buff)-6); socket_path = strdup(buff); #else if ((bptr = (char *)getenv("HOME")) == NULL) { lprint("Error: can"t find your HOME\n"); slirp_exit(1); } - strcpy(buff, bptr); + strncpy(buff, bptr, sizeof(buff)); strcat(buff, "/.slirp_socket"); socket_path = strdup(buff); #endif @@ -253,6 +253,7 @@ slirp_exit(1); } sock_un.sun_family = AF_UNIX; + /* TODO: perform length checking here */ strcpy(sock_un.sun_path, socket_path); ret = connect(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)); @@ -275,11 +276,11 @@ if (slirp_socket_passwd) { /* Internet connection */ - sprintf(buff, "%d %d %s", unit, 0, slirp_socket_passwd); + snprintf(buff, sizeof(buff), "%d %d %s", unit, 0, slirp_socket_passwd); } #ifndef NO_UNIX_SOCKETS else { - sprintf(buff, "%d %d %s", unit, (int)getpid(), ttyname(0)); + snprintf(buff, sizeof(buff), "%d %d %s", unit, (int)getpid(), ttyname(0)); } #endif write(s, buff, strlen(buff)+1); @@ -350,16 +351,21 @@ getouraddr(); if ((bptr = (char *)getenv("HOME")) != NULL) { - strcpy(buff, bptr); + strncpy(buff, bptr, sizeof(buff)); #ifdef USE_PPP path_upap = (char *)malloc(strlen(buff) + 15); + /* TODO: perform length checking */ strcpy(path_upap, buff); + /* TODO: perform length checking */ strcat(path_upap, "/.pap-secrets"); path_chap = (char *)malloc(strlen(buff) + 15); + /* TODO: perform length checking */ strcpy(path_chap, buff); + /* TODO: perform length checking */ strcat(path_chap, "/.chap-secrets"); #endif + /* TODO: perform length checking */ strcat(buff, "/.slirprc"); config(buff, ttys->unit); } @@ -963,11 +969,11 @@ #endif sprintf(buff2, "SLIP, MTU %d, MRU %d", if_mtu, if_mru); #ifndef FULL_BOLT - sprintf(buff, + snprintf(buff, sizeof(buff), "1 Attached as unit %d, device %s\r\n\r\n[talking %s, %d baud]\r\n\r\nSLiRP Ready...", unit, device?device:"(socket)", buff2, ttyp->baud); #else - sprintf(buff, + snprintf(buff, sizeof(buff), "1 Attached as unit %d, device %s\r\n\r\n[talking %s]\r\n\r\nSLiRP Ready ...", unit, device, buff2); #endif diff -NurbB slirp-1.0.14pre1/src/misc.c slirp-1.0.14pre1-new/src/misc.c --- slirp-1.0.14pre1/src/misc.c 2000-09-09 10:48:43.000000000 -0700 +++ slirp-1.0.14pre1-new/src/misc.c 2004-06-20 15:31:28.000000000 -0700 @@ -359,10 +359,10 @@ if (x_port >= 0) { #ifdef HAVE_SETENV - sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + snprintf(buff, sizeof(buff), "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else - sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + snprintf(buff, sizeof(buff), "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } @@ -392,13 +392,14 @@ } while (c); argv[i] = 0; + /* TODO: is this safe? see execlp comment below. */ execvp(argv[0], argv); /* Ooops, failed, let"s tell the user why */ { char buff[256]; - sprintf(buff, "Error: execvp of %s failed: %s\n", + snprintf(buff, sizeof(buff), "Error: execvp of %s failed: %s\n", argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } @@ -471,7 +472,7 @@ sock_in.sin_port = htons(slirp_socket_port); if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) slirp_exit(1); /* just exit...*/ - sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); + snprintf(buff, sizeof(buff), "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); write(s, buff, strlen(buff)+1); } #ifndef NO_UNIX_SOCKETS @@ -881,10 +882,10 @@ /* Set the DISPLAY */ if (x_port >= 0) { #ifdef HAVE_SETENV - sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + snprintf(buff, sizeof(buff), "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else - sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + snprintf(buff, sizeof(buff), "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } @@ -895,6 +896,10 @@ for (s = 3; s <= 255; s++) close(s); + /* TODO: This type of exec is very dangerous if this process is privileged in any way. + * A user could escalate privileges by subverting the $PATH, and having an rsh + * binary of their own making get executed. + */ execlp("rsh","rsh","-l", user, host, args, NULL); /* Ooops, failed, let"s tell the user why */ diff -NurbB slirp-1.0.14pre1/src/options.c slirp-1.0.14pre1-new/src/options.c --- slirp-1.0.14pre1/src/options.c 1998-12-05 19:30:54.000000000 -0800 +++ slirp-1.0.14pre1-new/src/options.c 2004-06-20 15:24:28.000000000 -0700 @@ -635,8 +635,8 @@ if (!buff) { buff1[0] = 0; if ((bptr = (char *)getenv("HOME")) != NULL) - strcpy(buff1, bptr); - strcat(buff1, "/.slirp_start"); + strncpy(buff1, bptr, sizeof(buff1)); + strncat(buff1, "/.slirp_start", sizeof(buff1)); lfd = fopen(buff1, "w"); bptr = buff1; } else { @@ -717,7 +717,7 @@ /* Found a match, print the help */ count++; if (cfg[i].command_line) - sprintf(str, "Command-line: %s\r\n", cfg[i].command_line); + snprintf(str, sizeof(str), "Command-line: %s\r\n", cfg[i].command_line); else str[0] = 0; if (cfg[i].type == CFG_TELNET) @@ -961,6 +961,7 @@ /* Create a new one */ sock_un.sun_family = AF_UNIX; + /* TODO: length check */ strcpy(sock_un.sun_path, socket_path); if ((bind(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) < 0) || diff -NurbB slirp-1.0.14pre1/src/ppp/auth.c slirp-1.0.14pre1-new/src/ppp/auth.c --- slirp-1.0.14pre1/src/ppp/auth.c 1999-10-22 18:33:59.000000000 -0700 +++ slirp-1.0.14pre1-new/src/ppp/auth.c 2004-06-20 15:21:37.000000000 -0700 @@ -325,8 +325,10 @@ lcp_options *ao = &lcp_allowoptions[0]; /* Default our_name to hostname, and user to our_name */ + /* TODO: check lengths */ if (our_name[0] == 0 || usehostname) strcpy(our_name, hostname); + /* TODO: check lengths */ if (user[0] == 0) strcpy(user, our_name); @@ -884,6 +886,7 @@ * Special syntax: @filename means read secret from file. */ if (word[0] == "@") { + /* TODO: check lengths */ strcpy(atfile, word+1); if ((sf = fopen(atfile, "r")) == NULL) { do_syslog(LOG_WARNING, "can"t open indirect secret file %s", @@ -899,6 +902,7 @@ } fclose(sf); } + /* TODO: check lengths */ if (secret != NULL) strcpy(secret, word); @@ -918,6 +922,7 @@ if (ap == NULL) novm("authorized addresses"); ap->next = NULL; + /* TODO: check lengths */ strcpy(ap->word, word); if (addr_list == NULL) addr_list = ap; diff -NurbB slirp-1.0.14pre1/src/ppp/chap.c slirp-1.0.14pre1-new/src/ppp/chap.c --- slirp-1.0.14pre1/src/ppp/chap.c 1995-09-17 04:26:48.000000000 -0700 +++ slirp-1.0.14pre1-new/src/ppp/chap.c 2004-06-19 19:08:59.000000000 -0700 @@ -653,7 +653,7 @@ char msg[256]; if (code == CHAP_SUCCESS) - sprintf(msg, "Welcome to %s.", hostname); + snprintf(msg, sizeof(msg), "Welcome to %s.", hostname); else sprintf(msg, "I don"t like you. Go "way."); msglen = strlen(msg); diff -NurbB slirp-1.0.14pre1/src/ppp/ipcp.c slirp-1.0.14pre1-new/src/ppp/ipcp.c --- slirp-1.0.14pre1/src/ppp/ipcp.c 1995-09-17 04:30:24.000000000 -0700 +++ slirp-1.0.14pre1-new/src/ppp/ipcp.c 2004-06-20 15:22:57.000000000 -0700 @@ -1091,9 +1091,9 @@ char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; - sprintf(strspeed, "%d", baud_rate); - strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr)); - strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr)); + snprintf(strspeed, sizeof(strspeed), "%d", baud_rate); + strncpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr), sizeof(strlocal)); + strncpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr), sizeof(strremote)); argv[0] = script; argv[1] = ifname; diff -NurbB slirp-1.0.14pre1/src/tcp_subr.c slirp-1.0.14pre1-new/src/tcp_subr.c --- slirp-1.0.14pre1/src/tcp_subr.c 2000-08-30 17:38:32.000000000 -0700 +++ slirp-1.0.14pre1-new/src/tcp_subr.c 2004-06-20 15:27:29.000000000 -0700 @@ -730,7 +730,7 @@ if (*ptr++ == 0) { n++; if (n == 2) { - sprintf(args, "rlogin -l %s %s", + snprintf(args, sizeof(args), "rlogin -l %s %s", ptr, inet_ntoa(so->so_faddr)); } else if (n == 3) { i2 = so_rcv->sb_wptr - ptr; @@ -738,9 +738,9 @@ if (ptr[i] == "/") { ptr[i] = 0; #ifdef HAVE_SETENV - sprintf(term, "%s", ptr); + snprintf(term, sizeof(term), "%s", ptr); #else - sprintf(term, "TERM=%s", ptr); + snprintf(term, sizeof(term), "TERM=%s", ptr); #endif ptr[i] = "/"; break; @@ -1012,6 +1012,7 @@ n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ + /* TODO: length check */ m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; @@ -1043,6 +1044,7 @@ n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ + /* TODO: length check */ m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); @@ -1084,6 +1086,7 @@ return 1; m->m_len = bptr - m->m_data; /* Adjust length */ + /* TODO: length check */ m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), 1); @@ -1092,6 +1095,7 @@ return 1; m->m_len = bptr - m->m_data; /* Adjust length */ + /* TODO: length check */ m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); @@ -1100,6 +1104,7 @@ return 1; m->m_len = bptr - m->m_data; /* Adjust length */ + /* TODO: length check */ m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); diff -NurbB slirp-1.0.14pre1/src/ttys.c slirp-1.0.14pre1-new/src/ttys.c --- slirp-1.0.14pre1/src/ttys.c 2001-03-25 19:40:20.000000000 -0800 +++ slirp slirp-1.0.17/slirp-1.0.16.lsm0000644000175000017500000000127110115527124014373 0ustar roverroverBegin3 Title: slirp Version: 1.0.16 Entered-date: Sept 2, 2004 Description: Slirp is a TCP/IP emulator which turns an ordinary shell account into a (C)SLIP/PPP account. This allows shell users to run ftp, netscape, CUSeeMe, etc. Keywords: slirp ip emulator Author: Danny Gasparovski, Kelly Price, et al Maintained-by: Kelly Price Primary-site: http://slirp.sourcefourge.net Original-site: Unlocatable Platforms: Any Unix that it can compile on, cygwin Copying-policy: BSD End slirp-1.0.17/src/0000755000175000017500000000000010433172432012573 5ustar roverroverslirp-1.0.17/src/Makefile.in0000755000175000017500000001244610115557437014663 0ustar roverrover # # Makefile for GNU Autoconf # version = @version@ srcdir = @srcdir@ COMMON_DEFS = @DASH_POSIX@ -I. -I${srcdir} @USE_PPP@ -DUSE_MS_DNS #-DDEBUG -DMS_DCC CC = @CC@ CPP = @CPP@ $(COMMON_DEFS) -DUSE_PPP @CFLAGS@ CFLAGS = $(COMMON_DEFS) @CFLAGS@ @CFLAGS2@ PPPCFLAGS = $(COMMON_DEFS) @PPPCFLAGS@ SHELL = /bin/sh MKPRO = @PERL@ ${srcdir}/mkpro MAKEPRO = @MAKEPRO@ PPPOBJS = auth.o bsd-comp.o ccp.o chap.o fsm.o ipcp.o lcp.o magic.o md5.o pppdfncs.o upap.o ppp.o PPPOBJ = @PPPOBJ@ OBJ = $(PPPOBJ) cksum.o debug.o if.o ip_icmp.o ip_input.o ip_output.o main.o mbuf.o\ misc.o options.o sbuf.o sl.o slcompress.o socket.o tcp_input.o\ tcp_output.o tcp_subr.o tcp_timer.o terminal.o ttys.o udp.o @LIBOBJS@ PROTO = ${srcdir}/cksum.p ${srcdir}/debug.p ${srcdir}/if.p ${srcdir}/ip_icmp.p\ ${srcdir}/ip_input.p ${srcdir}/ip_output.p ${srcdir}/main.p ${srcdir}/mbuf.p\ ${srcdir}/misc.p ${srcdir}/options.p ${srcdir}/ppp.p ${srcdir}/sbuf.p\ ${srcdir}/sl.p ${srcdir}/slcompress.p ${srcdir}/socket.p ${srcdir}/tcp_input.p\ ${srcdir}/tcp_output.p ${srcdir}/tcp_subr.p ${srcdir}/tcp_timer.p\ ${srcdir}/terminal.p ${srcdir}/ttys.p ${srcdir}/udp.p LIBS = @LIBS@ COMMON_H = config.h ${srcdir}/slirp.h BINDIR = @prefix@/bin MANDIR = @prefix@/man/man1 MANEXT = 1 all: ${srcdir}/configure Makefile config.h slirp slirp: $(PROTO) $(OBJ) $(CC) @LDFLAGS@ -o slirp $(OBJ) $(LIBS) install: slirp install.man strip slirp cp slirp $(BINDIR) install.man: cp slirp.man $(MANDIR)/slirp.$(MANEXT) objclean: rm -f $(OBJ) confclean: rm -f config.h config.log config.status\ config.cache Makefile proclean: rm -f *.p realclean: objclean confclean rm -f slirp core slirp.core core.slirp rm -f *~ clean: objclean rm -f slirp core slirp.core core.slirp ${srcdir}/configure: ${srcdir}/configure.in cd ${srcdir} && autoconf || touch ${srcdir}/configure Makefile: ${srcdir}/Makefile.in config.status ./config.status # RUN_MAKE_AGAIN config.status: ${srcdir}/configure ./config.status --recheck # This just helps me, you can ignore it release: all rm -f $(OBJ) rm -f config.h config.log config.status \ config.cache Makefile rm -f slirp core slirp.core core.slirp slirp.exe rm -f ${srcdir}/*~ ${srcdir}/ppp/*~ (cd ${srcdir}/../..; \ tar cvzf slirp-${version}.tar.gz slirp-${version};) cp -u ${srcdir}/../ChangeLog ${srcdir}/../../slirp.ChangeLog cp -u ${srcdir}/../slirp-${version}.lsm ${srcdir}/../.. # # Prototypes and .o files # .c.p: $(MAKEPRO) auth.o: $(COMMON_H) ${srcdir}/ppp/auth.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/auth.c bsd-comp.o: $(COMMON_H) ${srcdir}/ppp/bsd-comp.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/bsd-comp.c ccp.o: $(COMMON_H) ${srcdir}/ppp/ccp.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/ccp.c chap.o: $(COMMON_H) ${srcdir}/ppp/chap.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/chap.c fsm.o: $(COMMON_H) ${srcdir}/ppp/fsm.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/fsm.c ipcp.o: $(COMMON_H) ${srcdir}/ppp/ipcp.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/ipcp.c lcp.o: $(COMMON_H) ${srcdir}/ppp/lcp.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/lcp.c magic.o: $(COMMON_H) ${srcdir}/ppp/magic.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/magic.c md5.o: $(COMMON_H) ${srcdir}/ppp/md5.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/md5.c pppdfncs.o: $(COMMON_H) ${srcdir}/ppp/pppdfncs.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/pppdfncs.c upap.o: $(COMMON_H) ${srcdir}/ppp/upap.c $(CC) $(PPPCFLAGS) -c ${srcdir}/ppp/upap.c cksum.o: $(COMMON_H) ${srcdir}/cksum.c $(CC) $(CFLAGS) -c ${srcdir}/cksum.c debug.o: $(COMMON_H) ${srcdir}/debug.c $(CC) $(CFLAGS) -c ${srcdir}/debug.c if.o: $(COMMON_H) ${srcdir}/if.c $(CC) $(CFLAGS) -c ${srcdir}/if.c ip_icmp.o: ${srcdir}/ip_icmp.c $(COMMON_H) ${srcdir}/ip.h $(CC) $(CFLAGS) -c -o $@ $< ip_input.o: ${srcdir}/ip_input.c $(COMMON_H) ${srcdir}/ip.h $(CC) $(CFLAGS) -c -o $@ $< ip_output.o: ${srcdir}/ip_output.c $(COMMON_H) ${srcdir}/ip.h $(CC) $(CFLAGS) -c -o $@ $< main.o: $(COMMON_H) ${srcdir}/main.c $(CC) $(CFLAGS) -c ${srcdir}/main.c mbuf.o: $(COMMON_H) ${srcdir}/mbuf.c $(CC) $(CFLAGS) -c ${srcdir}/mbuf.c misc.o: $(COMMON_H) ${srcdir}/misc.c $(CC) $(CFLAGS) -c ${srcdir}/misc.c options.o: $(COMMON_H) ${srcdir}/options.c $(CC) $(CFLAGS) -c ${srcdir}/options.c ppp.o: $(COMMON_H) ${srcdir}/ppp.c $(CC) $(CFLAGS) -c ${srcdir}/ppp.c sbuf.o: $(COMMON_H) ${srcdir}/sbuf.c $(CC) $(CFLAGS) -c ${srcdir}/sbuf.c sl.o: $(COMMON_H) ${srcdir}/sl.c $(CC) $(CFLAGS) -c ${srcdir}/sl.c slcompress.o: $(COMMON_H) ${srcdir}/slcompress.c $(CC) $(CFLAGS) -c ${srcdir}/slcompress.c socket.o: $(COMMON_H) ${srcdir}/socket.c $(CC) $(CFLAGS) -c ${srcdir}/socket.c tcp_input.o: $(COMMON_H) ${srcdir}/tcp_input.c $(CC) $(CFLAGS) -c ${srcdir}/tcp_input.c tcp_output.o: $(COMMON_H) ${srcdir}/tcp_output.c $(CC) $(CFLAGS) -c ${srcdir}/tcp_output.c tcp_subr.o: $(COMMON_H) ${srcdir}/tcp_subr.c $(CC) $(CFLAGS) -c ${srcdir}/tcp_subr.c tcp_timer.o: $(COMMON_H) ${srcdir}/tcp_timer.c $(CC) $(CFLAGS) -c ${srcdir}/tcp_timer.c terminal.o: $(COMMON_H) ${srcdir}/terminal.c $(CC) $(CFLAGS) -c ${srcdir}/terminal.c ttys.o: $(COMMON_H) ${srcdir}/ttys.c $(CC) $(CFLAGS) -c ${srcdir}/ttys.c udp.o: $(COMMON_H) ${srcdir}/udp.c $(CC) $(CFLAGS) -c ${srcdir}/udp.c memcmp.o: ${srcdir}/memcmp.c $(CC) $(CFLAGS) -c ${srcdir}/memcmp.c strtoul.o: ${srcdir}/strtoul.c $(CC) $(CFLAGS) -c ${srcdir}/strtoul.c .c.o: $(COMMON_H) $(CC) $(CFLAGS) -c $< -o $@ slirp-1.0.17/src/cksum.c0000644000175000017500000001011210115276013014051 0ustar roverrover/* * Copyright (c) 1988, 1992, 1993 * 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. * * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp */ #include /* * Checksum routine for Internet Protocol family headers (Portable Version). * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. * * XXX Since we will never span more than 1 mbuf, we can optimise this */ #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} int cksum(m, len) register struct mbuf *m; register int len; { register u_int16_t *w; register int sum = 0; register int mlen = 0; int byte_swapped = 0; union { u_int8_t c[2]; u_int16_t s; } s_util; union { u_int16_t s[2]; u_int32_t l; } l_util; if (m->m_len == 0) goto cont; w = mtod(m, u_int16_t *); mlen = m->m_len; if (len < mlen) mlen = len; len -= mlen; /* * Force to even boundary. */ if ((1 & (long) w) && (mlen > 0)) { REDUCE; sum <<= 8; s_util.c[0] = *(u_int8_t *)w; w = (u_int16_t *)((int8_t *)w + 1); mlen--; byte_swapped = 1; } /* * Unroll the loop to make overhead from * branches &c small. */ while ((mlen -= 32) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; w += 16; } mlen += 32; while ((mlen -= 8) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; w += 4; } mlen += 8; if (mlen == 0 && byte_swapped == 0) goto cont; REDUCE; while ((mlen -= 2) >= 0) { sum += *w++; } if (byte_swapped) { REDUCE; sum <<= 8; byte_swapped = 0; if (mlen == -1) { s_util.c[1] = *(u_int8_t *)w; sum += s_util.s; mlen = 0; } else mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w; cont: #ifdef DEBUG if (len) { DEBUG_ERROR((dfd, "cksum: out of data\n")); DEBUG_ERROR((dfd, " len = %d\n", len)); } #endif if (mlen == -1) { /* The last mbuf has odd # of bytes. Follow the standard (the odd byte may be shifted left by 8 bits or not as determined by endian-ness of the machine) */ s_util.c[1] = 0; sum += s_util.s; } REDUCE; return (~sum & 0xffff); } slirp-1.0.17/src/cksum.p0000644000175000017500000000006610115325662014102 0ustar roverroverint cksum _P((register struct mbuf *, register int)); slirp-1.0.17/src/config.h.in0000644000175000017500000001047010115316532014616 0ustar roverrover/* * User definable configuration options */ /* Undefine if you don't want talk emulation */ #define EMULATE_TALK 1 /* Define if you want the connection to be probed */ /* XXX Not working yet, so ignore this for now */ #undef PROBE_CONN /* Define to 1 if you want KEEPALIVE timers */ #define DO_KEEPALIVE 0 /* Define to MAX interfaces you expect to use at once */ /* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ /* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ #define MAX_INTERFACES 1 #define MAX_PPP_INTERFACES 1 /* Define if you want slirp's socket in /tmp */ /* XXXXXX Do this in ./configure */ #undef USE_TMPSOCKET /* Define if you want slirp to use cfsetXspeed() on the terminal */ #undef DO_CFSETSPEED /* Define this if you want slirp to write to the tty as fast as it can */ /* This should only be set if you are using load-balancing, slirp does a */ /* pretty good job on single modems already, and seting this will make */ /* interactive sessions less responsive */ /* XXXXX Talk about having fast modem as unit 0 */ #undef FULL_BOLT /* * Define if you want slirp to use less CPU * You will notice a small lag in interactive sessions, but it's not that bad * Things like Netscape/ftp/etc. are completely unaffected * This is mainly for sysadmins who have many slirp users */ #undef USE_LOWCPU /* Define this if your compiler doesn't like prototypes */ #ifndef __STDC__ #define NO_PROTOTYPES #endif /*********************************************************/ /* * Autoconf defined configuration options * You shouldn't need to touch any of these */ /* Ignore this */ #undef DUMMY_PPP /* Define if you have unistd.h */ #undef HAVE_UNISTD_H /* Define if you have stdlib.h */ #undef HAVE_STDLIB_H /* Define if you have sys/ioctl.h */ #undef HAVE_SYS_IOCTL_H /* Define if you have sys/filio.h */ #undef HAVE_SYS_FILIO_H /* Define if you have strerror */ #undef HAVE_STRERROR /* Define if you have strdup() */ #undef HAVE_STRDUP /* Define according to how time.h should be included */ #undef TIME_WITH_SYS_TIME #undef HAVE_SYS_TIME_H /* Define if you have sys/bitypes.h */ #undef HAVE_SYS_BITYPES_H /* Define if the machine is big endian */ #undef WORDS_BIGENDIAN /* Define if your sprintf returns char * instead of int */ #undef BAD_SPRINTF /* Define if you have readv */ #undef HAVE_READV /* Define if iovec needs to be declared */ #undef DECLARE_IOVEC /* Define if a declaration of sprintf/fprintf is needed */ #undef DECLARE_SPRINTF /* Define if you have a POSIX.1 sys/wait.h */ #undef HAVE_SYS_WAIT_H /* Define if you have sys/select.h */ #undef HAVE_SYS_SELECT_H /* Define if you have strings.h */ #undef HAVE_STRING_H /* Define if you have arpa/inet.h */ #undef HAVE_ARPA_INET_H /* Define if you have sys/signal.h */ #undef HAVE_SYS_SIGNAL_H /* Define if you have sys/stropts.h */ #undef HAVE_SYS_STROPTS_H /* Define to whatever your compiler thinks inline should be */ #define inline inline /* Define to whatever your compiler thinks const should be */ #define const const /* Define if your compiler doesn't like prototypes */ #undef NO_PROTOTYPES /* Define if you don't have u_int32_t etc. typedef'd */ #undef NEED_TYPEDEFS /* Define to sizeof(char) */ #undef SIZEOF_CHAR /* Define to sizeof(short) */ #undef SIZEOF_SHORT /* Define to sizeof(int) */ #undef SIZEOF_INT /* Define to sizeof(char *) */ #undef SIZEOF_CHAR_P /* Define if you have random() */ #undef HAVE_RANDOM /* Define if you have srandom() */ #undef HAVE_SRANDOM /* Define if you have inet_aton */ #undef HAVE_INET_ATON /* Define if you have setenv */ #undef HAVE_SETENV /* Define if you have index() */ #undef HAVE_INDEX /* Define if you have bcmp() */ #undef HAVE_BCMP /* Define if you have drand48 */ #undef HAVE_DRAND48 /* Define if you have memmove */ #undef HAVE_MEMMOVE /* Define if you have */ #undef HAVE_TERMIOS_H /* Define if you have gethostid */ #undef HAVE_GETHOSTID /* Define if you DON'T have unix-domain sockets */ #undef NO_UNIX_SOCKETS /* Define if gettimeofday only takes one argument */ #undef GETTIMEOFDAY_ONE_ARG /* Define if you have revoke() */ #undef HAVE_REVOKE /* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ #undef HAVE_GRANTPT /* Define if you have fchmod */ #undef HAVE_FCHMOD /* Define if you have */ #undef HAVE_SYS_TYPES32_H slirp-1.0.17/src/configure0000755000175000017500000022040710115317324014505 0ustar roverrover#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --disable-ppp don't compile in ppp" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=debug.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi echo "Reminder: If you don't want PPP compiled in, run configure with the option --disable-ppp" echo $ac_n "checking version""... $ac_c" 1>&6 echo "configure:532: checking version" >&5 version=`cat ${srcdir}/version.h | sed -ne '1 s/.* \"\(.*\)\"/\1/; 1 p'` echo "$ac_t""$version" 1>&6 CROSS_ERROR="echo ;\ echo Error: could not execute test program;\ echo ;\ echo This error occurs when either:;\ echo 1\) You are cross-compiling, in which case don\'t. Slirp needs to execute;\ echo \ \ \ test programs to figure some things out\; or;\ echo 2\) There is a problem with your compiler setup, in which case you should;\ echo \ \ \ ask your sysadmin for help. You might also want to send her the;\ echo \ \ \ resulting config.log file for clues.; exit 1" # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:550: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:580: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_save_ifs" if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:631: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:663: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 674 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:679: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:705: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:710: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:738: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 if test "$ac_test_CFLAGS" = set; then CFLAGS="$ac_save_CFLAGS" elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:770: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:791: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:808: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:825: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 if test x$GCC = xyes; then CFLAGS2="-O2 -Wall -Wno-implicit -Wmissing-prototypes" else CFLAGS2="-O" echo "WARNING: Not using GCC to compile may be hazzardous to your health." echo " If you can get Slirp to compile and run w/o GCC, notify us so" echo " we can test for which compiler you're using. RedWolf recommends" echo " installing GCC anyway if you don't have it." fi if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 echo "configure:860: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes else rm -rf conftest* ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi if test x$cross_compiling = xyes; then eval $CROSS_ERROR fi # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:911: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$PERL" in /*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; ?:/*) ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_PERL="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="no" ;; esac fi PERL="$ac_cv_path_PERL" if test -n "$PERL"; then echo "$ac_t""$PERL" 1>&6 else echo "$ac_t""no" 1>&6 fi if test x$PERL = xno; then MAKEPRO='touch $@' else echo $ac_n "checking whether perl is version 5 or greater""... $ac_c" 1>&6 echo "configure:948: checking whether perl is version 5 or greater" >&5 if eval "test \"`echo '$''{'sr_cv_perl5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_perl5=check fi if test x$sr_cv_perl5 = xcheck; then eval "$PERL -e '$] < 5.000 && exit 1'" if test $? = 1; then sr_cv_perl5=no else sr_cv_perl5=yes fi fi if test x$sr_cv_perl5 = xyes; then MAKEPRO='$(CPP) $< | $(MKPRO) > $@.bak && mv -f $@.bak $@' echo "$ac_t""yes" 1>&6 else MAKEPRO='touch $@' echo "$ac_t""no - prototypes will not be dynamically extracted" 1>&6 fi fi echo $ac_n "checking whether you are compiling on NeXT""... $ac_c" 1>&6 echo "configure:974: checking whether you are compiling on NeXT" >&5 if eval "test \"`echo '$''{'sr_cv_next'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_next=check fi if test x$sr_cv_next = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_next=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_next=yes fi rm -fr conftest* fi fi echo "$ac_t""$sr_cv_next" 1>&6 if test x$sr_cv_next = xyes; then DASH_POSIX="-posix" LDFLAGS="-posix $LDFLAGS" fi echo $ac_n "checking whether sprintf returns int""... $ac_c" 1>&6 echo "configure:1018: checking whether sprintf returns int" >&5 if eval "test \"`echo '$''{'sr_cv_sprintf_int'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_sprintf_int=check fi if test x$sr_cv_sprintf_int = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext < int main () { char buff[1]; int ret; ret = (int)sprintf(buff,""); if (ret == 0) exit(1); else exit(0); } EOF if { (eval echo configure:1044: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_sprintf_int=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_sprintf_int=yes fi rm -fr conftest* fi fi if test x$sr_cv_sprintf_int = xno; then cat >> confdefs.h <<\EOF #define BAD_SPRINTF 1 EOF fi echo "$ac_t""$sr_cv_sprintf_int" 1>&6 echo $ac_n "checking whether sprintf/fprintf need to be declared""... $ac_c" 1>&6 echo "configure:1066: checking whether sprintf/fprintf need to be declared" >&5 if eval "test \"`echo '$''{'sr_cv_sprintf_declare'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_sprintf_declare=check fi if test x$sr_cv_sprintf_declare = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext < int main () { int (*tmp1)(); int (*tmp2)(); tmp1 = (int (*)())fprintf; tmp2 = (int (*)())sprintf; exit(0); } EOF if { (eval echo configure:1091: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_sprintf_declare=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_sprintf_declare=yes fi rm -fr conftest* fi fi if test x$sr_cv_sprintf_declare = xyes; then cat >> confdefs.h <<\EOF #define DECLARE_SPRINTF 1 EOF fi echo "$ac_t""$sr_cv_sprintf_declare" 1>&6 echo $ac_n "checking whether gettimeofday takes two arguments""... $ac_c" 1>&6 echo "configure:1113: checking whether gettimeofday takes two arguments" >&5 if eval "test \"`echo '$''{'sr_cv_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_gettimeofday=check fi if test x$sr_cv_gettimeofday = xcheck; then cat > conftest.$ac_ext < int main() { gettimeofday((void *)0, (void *)0); ; return 0; } EOF if { (eval echo configure:1129: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* sr_cv_gettimeofday=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* sr_cv_gettimeofday=no fi rm -f conftest* fi if test x$sr_cv_gettimeofday = xno; then cat >> confdefs.h <<\EOF #define GETTIMEOFDAY_ONE_ARG 1 EOF fi echo "$ac_t""$sr_cv_gettimeofday" 1>&6 echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 echo "configure:1149: checking for 8-bit clean memcmp" >&5 if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then ac_cv_func_memcmp_clean=no else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_memcmp_clean=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_func_memcmp_clean=no fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 echo "configure:1186: checking for main in -lnsl" >&5 ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 echo "configure:1229: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for main in -lposix""... $ac_c" 1>&6 echo "configure:1272: checking for main in -lposix" >&5 ac_lib_var=`echo posix'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lposix $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo posix | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for main in -lcrypt""... $ac_c" 1>&6 echo "configure:1315: checking for main in -lcrypt" >&5 ac_lib_var=`echo crypt'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lcrypt $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for unix-domain sockets""... $ac_c" 1>&6 echo "configure:1359: checking for unix-domain sockets" >&5 if eval "test \"`echo '$''{'sr_cv_unix_sockets'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_unix_sockets=check fi if test x$sr_cv_unix_sockets = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext < #include #include #include int main () { if (socket(AF_UNIX, SOCK_STREAM, 0) < 0) exit(1); else exit(0); } EOF if { (eval echo configure:1385: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_unix_sockets=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_unix_sockets=no fi rm -fr conftest* fi fi if test x$sr_cv_unix_sockets = xno; then cat >> confdefs.h <<\EOF #define NO_UNIX_SOCKETS 1 EOF fi echo "$ac_t""$sr_cv_unix_sockets" 1>&6 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 echo "configure:1407: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include int main() { struct tm *tp; ; return 0; } EOF if { (eval echo configure:1421: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_time=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_time" 1>&6 if test $ac_cv_header_time = yes; then cat >> confdefs.h <<\EOF #define TIME_WITH_SYS_TIME 1 EOF fi echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 echo "configure:1442: checking for sys/wait.h that is POSIX.1 compatible" >&5 if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #ifndef WEXITSTATUS #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main() { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } EOF if { (eval echo configure:1463: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_sys_wait_h=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_sys_wait_h=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 if test $ac_cv_header_sys_wait_h = yes; then cat >> confdefs.h <<\EOF #define HAVE_SYS_WAIT_H 1 EOF fi for ac_hdr in sys/ioctl.h unistd.h stdlib.h sys/filio.h sys/select.h string.h sys/signal.h sys/bitypes.h termios.h sys/stropts.h sys/types32.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1487: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1497: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 echo "configure:1524: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include int main() { #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif ; return 0; } EOF if { (eval echo configure:1542: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include int main() { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } EOF if { (eval echo configure:1557: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_bigendian=no fi rm -f conftest* else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* if test $ac_cv_c_bigendian = unknown; then if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_c_bigendian=yes fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_c_bigendian" 1>&6 if test $ac_cv_c_bigendian = yes; then cat >> confdefs.h <<\EOF #define WORDS_BIGENDIAN 1 EOF fi echo $ac_n "checking for working const""... $ac_c" 1>&6 echo "configure:1615: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if { (eval echo configure:1669: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi echo $ac_n "checking for inline""... $ac_c" 1>&6 echo "configure:1690: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* done fi echo "$ac_t""$ac_cv_c_inline" 1>&6 case "$ac_cv_c_inline" in inline | yes) ;; no) cat >> confdefs.h <<\EOF #define inline EOF ;; *) cat >> confdefs.h <&6 echo "configure:1730: checking whether u_int32_t etc. need to be typedef'd" >&5 if test x$ac_cv_header_sys_bitypes_h = xyes; then INC_BITYPES='#include ' fi if eval "test \"`echo '$''{'sr_cv_need_typedefs'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_need_typedefs=check fi if test x$sr_cv_need_typedefs = xcheck; then cat > conftest.$ac_ext < $INC_BITYPES #include int main() { u_int32_t foo = 0; ; return 0; } EOF if { (eval echo configure:1751: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* sr_cv_need_typedefs=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* sr_cv_need_typedefs=yes fi rm -f conftest* fi echo "$ac_t""$sr_cv_need_typedefs" 1>&6 if test x$sr_cv_need_typedefs = xyes; then cat >> confdefs.h <<\EOF #define NEED_TYPEDEFS 1 EOF echo $ac_n "checking size of char""... $ac_c" 1>&6 echo "configure:1769: checking size of char" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_char'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(char)); exit(0); } EOF if { (eval echo configure:1788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_char=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_char=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_char" 1>&6 cat >> confdefs.h <&6 echo "configure:1813: checking size of short" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(short)); exit(0); } EOF if { (eval echo configure:1832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_short=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_short=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_short" 1>&6 cat >> confdefs.h <&6 echo "configure:1852: checking size of int" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(int)); exit(0); } EOF if { (eval echo configure:1871: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_int=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_int=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_int" 1>&6 cat >> confdefs.h <&6 echo "configure:1892: checking size of char *" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_char_p'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(char *)); exit(0); } EOF if { (eval echo configure:1911: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_char_p=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_char_p=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_char_p" 1>&6 cat >> confdefs.h <&6 echo "configure:1934: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done for ac_func in strtoul do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1989: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:2017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" fi done echo $ac_n "checking for readv""... $ac_c" 1>&6 echo "configure:2044: checking for readv" >&5 if eval "test \"`echo '$''{'ac_cv_func_readv'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char readv(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_readv) || defined (__stub___readv) choke me #else readv(); #endif ; return 0; } EOF if { (eval echo configure:2072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_readv=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_readv=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'readv`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_READV 1 EOF else echo "$ac_t""no" 1>&6 echo $ac_n "checking whether iovec needs to be declared""... $ac_c" 1>&6 echo "configure:2093: checking whether iovec needs to be declared" >&5 if eval "test \"`echo '$''{'sr_cv_declare_iovec'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_declare_iovec=check fi if test x$sr_cv_declare_iovec = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext < struct iovec { int blah; } int main (void) { exit(0); } EOF if { (eval echo configure:2113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_declare_iovec=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_declare_iovec=no fi rm -fr conftest* fi fi if test x$sr_cv_declare_iovec = xyes; then cat >> confdefs.h <<\EOF #define DECLARE_IOVEC 1 EOF fi echo "$ac_t""$sr_cv_declare_iovec" 1>&6 fi echo $ac_n "checking for gethostid""... $ac_c" 1>&6 echo "configure:2138: checking for gethostid" >&5 if eval "test \"`echo '$''{'sr_cv_gethostid'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else sr_cv_gethostid=check fi if test x$sr_cv_gethostid = xcheck; then if test "$cross_compiling" = yes; then eval $CROSS_ERROR else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then sr_cv_gethostid=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* sr_cv_gethostid=no fi rm -fr conftest* fi fi echo "$ac_t""$sr_cv_gethostid" 1>&6 if test x$sr_cv_gethostid = xyes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTID 1 EOF fi # Check whether --enable-ppp or --disable-ppp was given. if test "${enable_ppp+set}" = set; then enableval="$enable_ppp" : else PPPOBJ='$(PPPOBJS)' USE_PPP=-DUSE_PPP cat >> confdefs.h <<\EOF #define DUMMY_PPP 1 EOF fi UNAME_MACHINE=`uname -m 2>/dev/null` UNAME_SYSTEM=`uname -s 2>/dev/null` case "${UNAME_MACHINE}:${UNAME_SYSTEM}" in alpha:OSF1) if test x$GCC = xyes; then LDFLAGS="$LDFLAGS -T 0x12000000 -Wl,-D -Wl,0x14000000" else LDFLAGS="$LDFLAGS -T 0x12000000 -D 0x14000000" fi ;; *) ;; esac PPPCFLAGS="`echo $CFLAGS $CFLAGS2 | sed -e 's/-W.*//g;'`" trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 DEFS=-DHAVE_CONFIG_H # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@version@%$version%g s%@CC@%$CC%g s%@CPP@%$CPP%g s%@PERL@%$PERL%g s%@MAKEPRO@%$MAKEPRO%g s%@DASH_POSIX@%$DASH_POSIX%g s%@LIBOBJS@%$LIBOBJS%g s%@PPPOBJ@%$PPPOBJ%g s%@USE_PPP@%$USE_PPP%g s%@CFLAGS2@%$CFLAGS2%g s%@PPPCFLAGS@%$PPPCFLAGS%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' ac_dC='\3' ac_dD='%g' # ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='\([ ]\)%\1#\2define\3' ac_uC=' ' ac_uD='\4%g' # ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_eB='$%\1#\2define\3' ac_eC=' ' ac_eD='%g' if test "${CONFIG_HEADERS+set}" != set; then EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF fi for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac echo creating $ac_file rm -f conftest.frag conftest.in conftest.out ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` cat $ac_file_inputs > conftest.in EOF # Transform confdefs.h into a sed script conftest.vals that substitutes # the proper values into config.h.in to produce config.h. And first: # Protect against being on the right side of a sed subst in config.status. # Protect against being in an unquoted here document in config.status. rm -f conftest.vals cat > conftest.hdr <<\EOF s/[\\&%]/\\&/g s%[\\$`]%\\&%g s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp s%ac_d%ac_u%gp s%ac_u%ac_e%gp EOF sed -n -f conftest.hdr confdefs.h > conftest.vals rm -f conftest.hdr # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >> conftest.vals <<\EOF s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% EOF # Break up conftest.vals because some shells have a limit on # the size of here documents, and old seds have small limits too. rm -f conftest.tail while : do ac_lines=`grep -c . conftest.vals` # grep -c gives empty output for an empty file on some AIX systems. if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi # Write a limited-size here document to conftest.frag. echo ' cat > conftest.frag <> $CONFIG_STATUS sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS echo 'CEOF sed -f conftest.frag conftest.in > conftest.out rm -f conftest.in mv conftest.out conftest.in ' >> $CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail rm -f conftest.vals mv conftest.tail conftest.vals done rm -f conftest.vals cat >> $CONFIG_STATUS <<\EOF rm -f conftest.frag conftest.h echo "/* $ac_file. Generated automatically by configure. */" > conftest.h cat conftest.in >> conftest.h rm -f conftest.in if cmp -s $ac_file conftest.h 2>/dev/null; then echo "$ac_file is unchanged" rm -f conftest.h else # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" fi rm -f $ac_file mv conftest.h $ac_file fi fi; done EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 slirp-1.0.17/src/configure.in0000644000175000017500000001767410115316532015121 0ustar roverroverdnl --- Process this file with autoconf to produce a configure script. AC_INIT(debug.c) AC_CONFIG_HEADER(config.h) echo "Reminder: If you don't want PPP compiled in, run configure with the option --disable-ppp" dnl - dnl - First, extract the version dnl - AC_MSG_CHECKING(version) version=`cat ${srcdir}/version.h | sed -ne '1 s/.* \"\(.*\)\"/\1/; 1 p'` AC_SUBST(version) AC_MSG_RESULT($version) dnl - dnl - This error happens so often I should tell them what's going on dnl - Use as "eval $CROSS_ERROR" dnl - CROSS_ERROR="echo ;\ echo Error: could not execute test program;\ echo ;\ echo This error occurs when either:;\ echo 1\) You are cross-compiling, in which case don\'t. Slirp needs to execute;\ echo \ \ \ test programs to figure some things out\; or;\ echo 2\) There is a problem with your compiler setup, in which case you should;\ echo \ \ \ ask your sysadmin for help. You might also want to send her the;\ echo \ \ \ resulting config.log file for clues.; exit 1" dnl - dnl - Checks for programs. dnl - dnl AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_CPP dnl -XXX Must fix this. Some cc's -Wxxxx, -O2, etc. Should check dnl -XXX them individually? dnl - Warn about not compiling with GCC. Somehow, GCC's better at things. dnl - But then, that's just me. --RedWolf if test x$GCC = xyes; then CFLAGS2="-O2 -Wall -Wno-implicit -Wmissing-prototypes" else CFLAGS2="-O" echo "WARNING: Not using GCC to compile may be hazzardous to your health." echo " If you can get Slirp to compile and run w/o GCC, notify us so" echo " we can test for which compiler you're using. RedWolf recommends" echo " installing GCC anyway if you don't have it." fi AC_PROG_GCC_TRADITIONAL dnl AC_PROG_INSTALL if test x$cross_compiling = xyes; then eval $CROSS_ERROR fi dnl - Check for perl 5 AC_PATH_PROG(PERL, perl, no) if test x$PERL = xno; then MAKEPRO='touch $@' else AC_MSG_CHECKING(whether perl is version 5 or greater) AC_CACHE_VAL(sr_cv_perl5, sr_cv_perl5=check) if test x$sr_cv_perl5 = xcheck; then eval "$PERL -e '$] < 5.000 && exit 1'" if test $? = 1; then sr_cv_perl5=no else sr_cv_perl5=yes fi fi if test x$sr_cv_perl5 = xyes; then MAKEPRO='$(CPP) $< | $(MKPRO) > $@.bak && mv -f $@.bak $@' AC_MSG_RESULT(yes) else MAKEPRO='touch $@' AC_MSG_RESULT(no - prototypes will not be dynamically extracted) fi fi AC_SUBST(MAKEPRO) AC_MSG_CHECKING(whether you are compiling on NeXT) AC_CACHE_VAL(sr_cv_next, sr_cv_next=check) if test x$sr_cv_next = xcheck; then AC_TRY_RUN([ int main() { #ifdef NeXT return 1; #else return 0; #endif }], sr_cv_next=no, sr_cv_next=yes, eval $CROSS_ERROR) fi AC_MSG_RESULT($sr_cv_next) if test x$sr_cv_next = xyes; then DASH_POSIX="-posix" AC_SUBST(DASH_POSIX) LDFLAGS="-posix $LDFLAGS" fi dnl - dnl - Some systems have a sprintf which returns char * dnl - AC_MSG_CHECKING(whether sprintf returns int) AC_CACHE_VAL(sr_cv_sprintf_int, sr_cv_sprintf_int=check) if test x$sr_cv_sprintf_int = xcheck; then AC_TRY_RUN([ #include int main () { char buff[1]; int ret; ret = (int)sprintf(buff,""); if (ret == 0) exit(1); else exit(0); }], sr_cv_sprintf_int=no, sr_cv_sprintf_int=yes, eval $CROSS_ERROR) fi if test x$sr_cv_sprintf_int = xno; then AC_DEFINE(BAD_SPRINTF) fi AC_MSG_RESULT($sr_cv_sprintf_int) dnl - dnl - Some systems need sprintf/fprintf declared, others complain dnl - when you do *sigh* dnl - AC_MSG_CHECKING(whether sprintf/fprintf need to be declared) AC_CACHE_VAL(sr_cv_sprintf_declare, sr_cv_sprintf_declare=check) if test x$sr_cv_sprintf_declare = xcheck; then AC_TRY_RUN([#include int main () { int (*tmp1)(); int (*tmp2)(); tmp1 = (int (*)())fprintf; tmp2 = (int (*)())sprintf; exit(0); }], sr_cv_sprintf_declare=no, sr_cv_sprintf_declare=yes, eval $CROSS_ERROR) fi if test x$sr_cv_sprintf_declare = xyes; then AC_DEFINE(DECLARE_SPRINTF) fi AC_MSG_RESULT($sr_cv_sprintf_declare) dnl - dnl - Check whether gettimeofday takes two arguments dnl - AC_MSG_CHECKING(whether gettimeofday takes two arguments) AC_CACHE_VAL(sr_cv_gettimeofday, sr_cv_gettimeofday=check) if test x$sr_cv_gettimeofday = xcheck; then AC_TRY_COMPILE([#include ], [gettimeofday((void *)0, (void *)0);], sr_cv_gettimeofday=yes, sr_cv_gettimeofday=no) fi if test x$sr_cv_gettimeofday = xno; then AC_DEFINE(GETTIMEOFDAY_ONE_ARG) fi AC_MSG_RESULT($sr_cv_gettimeofday) dnl - dnl - Check memcmp dnl - AC_FUNC_MEMCMP dnl - dnl - Check for libraries dnl - AC_CHECK_LIB(nsl, main) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(posix, main) AC_CHECK_LIB(crypt, main) dnl - dnl - Check for unix domain sockets dnl - AC_MSG_CHECKING(for unix-domain sockets) AC_CACHE_VAL(sr_cv_unix_sockets, sr_cv_unix_sockets=check) if test x$sr_cv_unix_sockets = xcheck; then AC_TRY_RUN([ #include #include #include #include int main () { if (socket(AF_UNIX, SOCK_STREAM, 0) < 0) exit(1); else exit(0); }], sr_cv_unix_sockets=yes, sr_cv_unix_sockets=no, eval $CROSS_ERROR) fi if test x$sr_cv_unix_sockets = xno; then AC_DEFINE(NO_UNIX_SOCKETS) fi AC_MSG_RESULT($sr_cv_unix_sockets) dnl - dnl - Check for header files dnl - AC_HEADER_TIME AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([sys/ioctl.h unistd.h stdlib.h sys/filio.h sys/select.h string.h sys/signal.h sys/bitypes.h termios.h sys/stropts.h sys/types32.h]) AC_C_BIGENDIAN dnl - dnl - Check for typedefs, structures, and compiler characteristics dnl - AC_C_CONST AC_C_INLINE AC_MSG_CHECKING(whether u_int32_t etc. need to be typedef'd) if test x$ac_cv_header_sys_bitypes_h = xyes; then INC_BITYPES='#include ' fi AC_CACHE_VAL(sr_cv_need_typedefs, sr_cv_need_typedefs=check) if test x$sr_cv_need_typedefs = xcheck; then AC_TRY_COMPILE([#include $INC_BITYPES #include ], [u_int32_t foo = 0;], sr_cv_need_typedefs=no, sr_cv_need_typedefs=yes) fi AC_MSG_RESULT($sr_cv_need_typedefs) if test x$sr_cv_need_typedefs = xyes; then AC_DEFINE(NEED_TYPEDEFS) AC_CHECK_SIZEOF(char) if test x$ac_cv_sizeof_char != x1; then echo "Error: something is wrong with configure!" echo "sizeof(char) is '$ac_cv_sizeof_char', not 1!" exit 1 fi AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) fi AC_CHECK_SIZEOF(char *) dnl - dnl - Check for library functions dnl - dnl XXX AC_FUNC_VPRINTF AC_CHECK_FUNCS(strdup strerror random srandom index bcmp drand48 memmove setenv inet_aton revoke grantpt fchmod) AC_REPLACE_FUNCS(strtoul) AC_CHECK_FUNC(readv, AC_DEFINE(HAVE_READV), AC_MSG_CHECKING(whether iovec needs to be declared) AC_CACHE_VAL(sr_cv_declare_iovec, sr_cv_declare_iovec=check) if test x$sr_cv_declare_iovec = xcheck; then AC_TRY_RUN([#include struct iovec { int blah; } int main (void) { exit(0); }], sr_cv_declare_iovec=yes, sr_cv_declare_iovec=no, eval $CROSS_ERROR) fi if test x$sr_cv_declare_iovec = xyes; then AC_DEFINE(DECLARE_IOVEC) fi AC_MSG_RESULT($sr_cv_declare_iovec) ) AC_MSG_CHECKING(for gethostid) AC_CACHE_VAL(sr_cv_gethostid, sr_cv_gethostid=check) if test x$sr_cv_gethostid = xcheck; then AC_TRY_RUN([ int main() { gethostid(); return 0; }], sr_cv_gethostid=yes, sr_cv_gethostid=no, eval $CROSS_ERROR) fi AC_MSG_RESULT($sr_cv_gethostid) if test x$sr_cv_gethostid = xyes; then AC_DEFINE(HAVE_GETHOSTID) fi AC_ARG_ENABLE(ppp, --disable-ppp don't compile in ppp, [], [ PPPOBJ='$(PPPOBJS)' USE_PPP=-DUSE_PPP AC_DEFINE(DUMMY_PPP)]) AC_SUBST(PPPOBJ) AC_SUBST(USE_PPP) dnl -XXXXX will be fixed in a better way dnl Quick hack for alpha UNAME_MACHINE=`uname -m 2>/dev/null` UNAME_SYSTEM=`uname -s 2>/dev/null` case "${UNAME_MACHINE}:${UNAME_SYSTEM}" in alpha:OSF1) if test x$GCC = xyes; then LDFLAGS="$LDFLAGS -T 0x12000000 -Wl,-D -Wl,0x14000000" else LDFLAGS="$LDFLAGS -T 0x12000000 -D 0x14000000" fi ;; *) ;; esac dnl - dnl - Do substitutions dnl - In compiling PPP code, we don't want full warnings dnl - AC_SUBST(CFLAGS2) PPPCFLAGS="`echo $CFLAGS $CFLAGS2 | sed -e 's/-W.*//g;'`" AC_SUBST(PPPCFLAGS) AC_OUTPUT(Makefile) slirp-1.0.17/src/ctl.h0000644000175000017500000000021310115276014013520 0ustar roverrover#define CTL_CMD 0 #define CTL_EXEC 1 #define CTL_ALIAS 2 #define CTL_DNS 3 #define CTL_SPECIAL "10.0.2.0" #define CTL_LOCAL "10.0.2.15" slirp-1.0.17/src/debug.c0000644000175000017500000002645110433144606014037 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * Portions copyright (c) 2000 Kelly Price. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include FILE *dfd = NULL; #ifdef DEBUG int dostats = 1; #else int dostats = 0; #endif int slirp_debug = 0; extern char *strerror _P((int)); /* Carry over one item from main.c so that the tty's restored. * Only done when the tty being used is /dev/tty --RedWolf */ extern struct termios slirp_tty_settings; extern int slirp_tty_restore; extern int slirp_fdout; void debug_init(file, dbg) char *file; int dbg; { /* Close the old debugging file */ if (dfd) fclose(dfd); dfd = fopen(file,"w"); if (dfd != NULL) { fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); fprintf(dfd,"Debugging Started level %i.\r\n",dbg); fflush(dfd); slirp_debug = dbg; } else { lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", file, strerror(errno)); } } /* * Dump a packet in the same format as tcpdump -x */ #ifdef DEBUG void dump_packet(dat, n) void *dat; int n; { u_char *pptr = (u_char *)dat; int j,k; n /= 16; n++; DEBUG_MISC((dfd, "PACKET DUMPED: \n")); for(j = 0; j < n; j++) { for(k = 0; k < 6; k++) DEBUG_MISC((dfd, "%02x ", *pptr++)); DEBUG_MISC((dfd, "\n")); fflush(dfd); } } #endif /* * Statistic routines * * These will print statistics to the screen, the debug file (dfd), or * a buffer, depending on "type", so that the stats can be sent over * the link as well. */ void ttystats(ttyp) struct ttys *ttyp; { struct slirp_ifstats *is = &ttyp->ifstats; char buff[512]; lprint(" \r\n"); if (if_comp & IF_COMPRESS) strcpy(buff, "on"); else if (if_comp & IF_NOCOMPRESS) strcpy(buff, "off"); else strcpy(buff, "off (for now)"); lprint("Unit %d:\r\n", ttyp->unit); lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( #ifdef USE_PPP ttyp->proto==PROTO_PPP?"PPP": #endif "SLIP"), buff); #ifndef FULL_BOLT lprint(" %d baudrate\r\n", ttyp->baud); #endif lprint(" interface is %s\r\n", ttyp->up?"up":"down"); lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); #ifndef FULL_BOLT lprint(" towrite is %d bytes\r\n", ttyp->towrite); #endif if (ttyp->zeros) lprint(" %d zeros have been typed\r\n", ttyp->zeros); else if (ttyp->ones) lprint(" %d ones have been typed\r\n", ttyp->ones); lprint("Interface stats:\r\n"); lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); lprint(" %6d bad input packets\r\n", is->in_mbad); } void allttystats() { struct ttys *ttyp; for (ttyp = ttys; ttyp; ttyp = ttyp->next) ttystats(ttyp); } void ipstats() { lprint(" \r\n"); lprint("IP stats:\r\n"); lprint(" %6d total packets received (%d were unaligned)\r\n", ipstat.ips_total, ipstat.ips_unaligned); lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); lprint(" %6d fragments received\r\n", ipstat.ips_fragments); lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); } void vjstats() { lprint(" \r\n"); lprint("VJ compression stats:\r\n"); lprint(" %6d outbound packets (%d compressed)\r\n", comp_s.sls_packets, comp_s.sls_compressed); lprint(" %6d searches for connection stats (%d misses)\r\n", comp_s.sls_searches, comp_s.sls_misses); lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); } void tcpstats() { lprint(" \r\n"); lprint("TCP stats:\r\n"); lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); lprint(" %6d data packets (%d bytes)\r\n", tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); lprint(" %6d data packets retransmitted (%d bytes)\r\n", tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); lprint(" %6d ack-only packets (%d delayed)\r\n", tcpstat.tcps_sndacks, tcpstat.tcps_delack); lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); lprint(" %6d acks (for %d bytes)\r\n", tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); lprint(" %6d packets received in sequence (%d bytes)\r\n", tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); lprint(" %6d completely duplicate packets (%d bytes)\r\n", tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); lprint(" %6d out-of-order packets (%d bytes)\r\n", tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); lprint(" %6d packets of data after window (%d bytes)\r\n", tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); lprint(" %6d discarded for bad header offset fields\r\n", tcpstat.tcps_rcvbadoff); lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); lprint(" %6d connections closed (including %d drop)\r\n", tcpstat.tcps_closed, tcpstat.tcps_drops); lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); lprint(" %6d connections dropped by rxmt timeout\r\n", tcpstat.tcps_timeoutdrop); lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); /* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ /* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ } void udpstats() { lprint(" \r\n"); lprint("UDP stats:\r\n"); lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); } void icmpstats() { lprint(" \r\n"); lprint("ICMP stats:\r\n"); lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); } void mbufstats() { struct mbuf *m; int i; lprint(" \r\n"); lprint("Mbuf stats:\r\n"); lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); i = 0; for (m = m_freelist.m_next; m && m != &m_freelist; m = m->m_next) i++; lprint(" %6d mbufs on free list\r\n", i); i = 0; for (m = m_usedlist.m_next; m && m != &m_usedlist; m = m->m_next) i++; lprint(" %6d mbufs on used list\r\n", i); lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); } void sockstats() { char buff[256]; int n; struct socket *so; lprint(" \r\n"); lprint( "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); for (so = tcb.so_next; so && so != &tcb; so = so->so_next) { n = snprintf(buff, sizeof(buff), "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); while (n < 17) buff[n++] = ' '; buff[17] = 0; lprint("%s %3d %15s %5d ", buff, so->s, inet_ntoa(so->so_laddr), ntohs(so->so_lport)); lprint("%15s %5d %5d %5d\r\n", inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } for (so = udb.so_next; so && so != &udb; so = so->so_next) { n = snprintf(buff, sizeof(buff), "udp[%d sec]", (so->so_expire - curtime) / 1000); while (n < 17) buff[n++] = ' '; buff[17] = 0; lprint("%s %3d %15s %5d ", buff, so->s, inet_ntoa(so->so_laddr), ntohs(so->so_lport)); lprint("%15s %5d %5d %5d\r\n", inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } } void slirp_exit(exit_status) int exit_status; { struct ttys *ttyp, *next_ttyp; DEBUG_CALL("slirp_exit"); DEBUG_ARG("exit_status = %d", exit_status); if (dostats) { lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; if (!dfd) debug_init("slirp_stats", 0xf); lprint_arg = (char **)&dfd; ipstats(); tcpstats(); udpstats(); icmpstats(); mbufstats(); sockstats(); allttystats(); vjstats(); } for (ttyp = ttys; ttyp;) { next_ttyp = ttyp->next; tty_detached(ttyp, 1); ttyp=next_ttyp; } if (slirp_forked) { /* Menendez time */ if (kill(getppid(), SIGQUIT) < 0) lprint("Couldn't kill parent process %ld!\n", (long) getppid()); } exit(exit_status); } slirp-1.0.17/src/debug.h0000644000175000017500000000172210115276014014032 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define PRN_STDERR 1 #define PRN_SPRINTF 2 extern FILE *dfd; extern FILE *lfd; extern int dostats; extern int slirp_debug; #define DBG_CALL 0x1 #define DBG_MISC 0x2 #define DBG_ERROR 0x4 #define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR #ifdef DEBUG #define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } #define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } #define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } #define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } #define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } #else #define DEBUG_CALL(x) #define DEBUG_ARG(x, y) #define DEBUG_ARGS(x) #define DEBUG_MISC(x) #define DEBUG_ERROR(x) #endif slirp-1.0.17/src/debug.p0000644000175000017500000000053110117211711014032 0ustar roverrovervoid debug_init _P((char *, int)); void dump_packet _P((void *, int)); void ttystats _P((struct ttys *)); void allttystats _P((void)); void ipstats _P((void)); void vjstats _P((void)); void tcpstats _P((void)); void udpstats _P((void)); void icmpstats _P((void)); void mbufstats _P((void)); void sockstats _P((void)); void slirp_exit _P((int)); slirp-1.0.17/src/icmp_var.h0000644000175000017500000000536310115276014014551 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp */ #ifndef _NETINET_ICMP_VAR_H_ #define _NETINET_ICMP_VAR_H_ /* * Variables related to this implementation * of the internet control message protocol. */ struct icmpstat { /* statistics related to input messages processed */ u_long icps_received; /* #ICMP packets received */ u_long icps_tooshort; /* packet < ICMP_MINLEN */ u_long icps_checksum; /* bad checksum */ u_long icps_notsupp; /* #ICMP packets not supported */ u_long icps_badtype; /* #with bad type feild */ u_long icps_reflect; /* number of responses */ }; /* * Names for ICMP sysctl objects */ #define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ #define ICMPCTL_STATS 2 /* statistics (read-only) */ #define ICMPCTL_MAXID 3 #define ICMPCTL_NAMES { \ { 0, 0 }, \ { "maskrepl", CTLTYPE_INT }, \ { "stats", CTLTYPE_STRUCT }, \ } extern struct icmpstat icmpstat; #endif slirp-1.0.17/src/if.c0000644000175000017500000002615210117211711013334 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include extern int nozeros; int if_mtu, if_mru; int if_comp; int if_maxlinkhdr; int if_queued = 0; /* Number of packets queued so far */ int if_thresh = 10; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ struct mbuf if_fastq; /* fast queue (for interactive data) */ struct mbuf if_batchq; /* queue for non-interactive data */ struct mbuf *next_m; /* Pointer to next mbuf to output */ #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) void ifs_insque(ifm, ifmhead) struct mbuf *ifm, *ifmhead; { ifm->ifs_next = ifmhead->ifs_next; ifmhead->ifs_next = ifm; ifm->ifs_prev = ifmhead; ifm->ifs_next->ifs_prev = ifm; } void ifs_remque(ifm) struct mbuf *ifm; { ifm->ifs_prev->ifs_next = ifm->ifs_next; ifm->ifs_next->ifs_prev = ifm->ifs_prev; } void if_init() { /* * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, * and 8 bytes for PPP, but need to have it on an 8byte boundary */ #ifdef USE_PPP if_maxlinkhdr = 48; #else if_maxlinkhdr = 40; #endif if_mtu = 1500; if_mru = 1500; if_comp = IF_AUTOCOMP; if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; sl_compress_init(&comp_s); next_m = &if_batchq; } /* * This shouldn't be needed since the modem is blocking and * we don't expect any signals, but what the hell.. */ inline int writen(fd, bptr, n) int fd; char *bptr; int n; { int ret; int total; int x; for(x=0;x total) { ret = write(fd, bptr+total, n-total); if (ret <= 0) return ret; total += ret; } return total; } /* * if_input - read() the tty, do "top level" processing (ie: check for any escapes), * and pass onto (*ttyp->if_input) * * 0's and 1's arriving by themselves now ARE put into packet processing. * (But still will cause stop/detach) * Had problems with slow links, just losing 0's */ #define INBUFF_SIZE 2048 /* XXX */ void if_input(ttyp) struct ttys *ttyp; { u_char if_inbuff[INBUFF_SIZE]; int if_n; DEBUG_CALL("if_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); if_n = read(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE); DEBUG_MISC((dfd, " read %d bytes, fd=%d\n", if_n, ttyp->fd)); if (if_n <= 0) { if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { if (ttyp->up) link_up--; tty_detached(ttyp, 0); } return; } #if MS_DCC /*@@ Hack, should be elsewhere. Chat processing, handle MS DCC */ if(ttyp->up) ttyp->dccpos=0; else { static char ring[]="CLIENT"; static char answer[]="CLIENTSERVER"; int idxPos; if(ttyp->dccpos < sizeof(ring) && if_n !=0) { for(idxPos=0;idxPosdccpos < sizeof(ring); idxPos++, ttyp->dccpos++) { if(if_inbuff[idxPos]!=ring[ttyp->dccpos]) ttyp->dccpos=0; } if(ttyp->dccpos >= sizeof(ring)-1) /* Seen ring send CLIENTSERVER back. */ { DEBUG_MISC((dfd,"Got Ring\n")); write(ttyp->fd,answer, sizeof(answer)-1); } } } #endif #if DEBUG /* Raw incoming data */ if(if_n > 0) { int ax; for(ax=0;axones = 0; if (++ttyp->zeros >= 5) slirp_exit(0); } else if (*if_inbuff == '1') { ttyp->zeros = 0; if (++ttyp->ones >= 5) { tty_detached(ttyp, 0); return; } } else ttyp->ones = ttyp->zeros = 0; } else ttyp->ones = ttyp->zeros = 0; } (*ttyp->if_input)(ttyp, if_inbuff, if_n); } /* * if_output: Queue packet into an output queue. * There are 2 output queue's, if_fastq and if_batchq. * Each output queue is a doubly linked list of double linked lists * of mbufs, each list belonging to one "session" (socket). This * way, we can output packets fairly by sending one packet from each * session, instead of all the packets from one session, then all packets * from the next session, etc. Packets on the if_fastq get absolute * priority, but if one session hogs the link, it gets "downgraded" * to the batchq until it runs out of packets, then it'll return * to the fastq (eg. if the user does an ls -alR in a telnet session, * it'll temporarily get downgraded to the batchq) */ void if_output(so, ifm) struct socket *so; struct mbuf *ifm; { struct mbuf *ifq; int on_fastq = 1; DEBUG_CALL("if_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ifm = %lx", (long)ifm); /* * First remove the mbuf from m_usedlist, * since we're gonna use m_next and m_prev ourselves * XXX Shouldn't need this, gotta change dtom() etc. */ if (ifm->m_flags & M_USEDLIST) { remque(ifm); ifm->m_flags &= ~M_USEDLIST; } /* * See if there's already a batchq list for this session. * This can include an interactive session, which should go on fastq, * but gets too greedy... hence it'll be downgraded from fastq to batchq. * We mustn't put this packet back on the fastq (or we'll send it out of order) * XXX add cache here? */ for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { if (so == ifq->ifq_so) { /* A match! */ ifm->ifq_so = so; ifs_insque(ifm, ifq->ifs_prev); goto diddit; } } /* No match, check which queue to put it on */ if (so && (so->so_iptos & IPTOS_LOWDELAY)) { ifq = if_fastq.ifq_prev; on_fastq = 1; /* * Check if this packet is a part of the last * packet's session */ if (ifq->ifq_so == so) { ifm->ifq_so = so; ifs_insque(ifm, ifq->ifs_prev); goto diddit; } } else ifq = if_batchq.ifq_prev; /* Create a new doubly linked list for this session */ ifm->ifq_so = so; ifs_init(ifm); insque(ifm, ifq); diddit: ++if_queued; if (so) { /* Update *_queued */ so->so_queued++; so->so_nqueued++; /* * Check if the interactive session should be downgraded to * the batchq. A session is downgraded if it has queued 6 * packets without pausing, and at least 3 of those packets * have been sent over the link * (XXX These are arbitrary numbers, probably not optimal..) */ if (on_fastq && ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) { /* Remove from current queue... */ remque(ifm->ifs_next); /* ...And insert in the new. That'll teach ya! */ insque(ifm->ifs_next, &if_batchq); } } #ifndef FULL_BOLT /* * This prevents us from malloc()ing too many mbufs */ if (link_up) { /* if_start will check towrite */ if_start(); } #endif } /* * Send a packet * We choose a packet based on it's position in the output queues; * If there are packets on the fastq, they are sent FIFO, before * everything else. Otherwise we choose the first packet from the * batchq and send it. the next packet chosen will be from the session * after this one, then the session after that one, and so on.. So, * for example, if there are 3 ftp session's fighting for bandwidth, * one packet will be sent from the first session, then one packet * from the second session, then one packet from the third, then back * to the first, etc. etc. */ #ifdef FULL_BOLT void if_start(ttyp) struct ttys *ttyp; { #else void if_start() { #endif struct mbuf *ifm, *ifqt; int n; #ifndef FULL_BOLT struct ttys *ttyp; struct ttys *ttyp_best = ttys; char if_outbuff[2*2048+2]; /* XXX */ #endif struct ip *ip; u_int proto; DEBUG_CALL("if_start"); again: #ifndef FULL_BOLT if (if_queued == 0) return; /* Nothing to do */ /* * First, find the best modem to write to.. ie: the one with * the greatest towrite * We do this first so that if all the towrite's are < 0, * we can bail early */ for (ttyp = ttys->next /* ttyp_best is already ttys */; ttyp; ttyp = ttyp->next) { if (!ttyp->up) continue; if (ttyp->towrite == ttyp_best->towrite) { if (ttyp->bytesps > ttyp_best->bytesps) ttyp_best = ttyp; } else if (ttyp->up && ttyp->towrite > ttyp_best->towrite) { ttyp_best = ttyp; } } /* If the greatest towrite is still < 0, bail */ if (!ttyp_best->up || ttyp_best->towrite < 0) return; #else /* * First write what was left over from last time */ if (ttyp->nbuff) { n = write(ttyp->fd, ttyp->if_outbuff+ttyp->nbuff_written, ttyp->nbuff - ttyp->nbuff_written); DEBUG_ARG("wrote %lu bytes", (long)n); if (n <= 0) return; ttyp->nbuff_written += n; if (ttyp->nbuff_written == ttyp->nbuff) { ttyp->nbuff = 0; ttyp->nbuff_written = 0; } else { return; } } if (if_queued == 0) return; /* Nothing to do */ #endif /* * See which queue to get next packet from * If there's something in the fastq, select it immediately */ if (if_fastq.ifq_next != &if_fastq) { ifm = if_fastq.ifq_next; } else { /* Nothing on fastq, see if next_m is valid */ if (next_m != &if_batchq) ifm = next_m; else ifm = if_batchq.ifq_next; /* Set which packet to send on next iteration */ next_m = ifm->ifq_next; } /* Remove it from the queue */ ifqt = ifm->ifq_prev; remque(ifm); --if_queued; /* If there are more packets for this session, re-queue them */ if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { insque(ifm->ifs_next, ifqt); ifs_remque(ifm); } /* Update so_queued */ if (ifm->ifq_so) { if (--ifm->ifq_so->so_queued == 0) /* If there's no more queued, reset nqueued */ ifm->ifq_so->so_nqueued = 0; } /* Compress, if needed */ proto = TYPE_IP; if (if_comp & IF_COMPRESS) { ip = mtod(ifm, struct ip *); if (ip->ip_p == IPPROTO_TCP) proto = sl_compress_tcp(ifm, ip, &comp_s, !(if_comp&IF_NOCIDCOMP)); } #ifndef FULL_BOLT /* Encapsulate the packet for sending */ n = (*ttyp_best->if_encap)(if_outbuff, ifm, ttyp_best->unit, (ttyp_best->towrite == towrite_max), proto); /* ifm is m_free()'d by if_encap */ /* Send it */ writen(ttyp_best->fd, if_outbuff, n); DEBUG_ARG("wrote %lu bytes", (long)n); ttyp_best->towrite -= n; ttyp_best->ifstats.out_pkts++; ttyp_best->ifstats.out_bytes += n; goto again; #else /* Encapsulate the packet for sending */ ttyp->nbuff = (*ttyp->if_encap)(ttyp->if_outbuff, ifm, ttyp->unit, 0, proto); /* XXXXX */ ttyp->nbuff_written = write(ttyp->fd, ttyp->if_outbuff, ttyp->nbuff); if (ttyp->nbuff_written < 0) { ttyp->nbuff_written = 0; return; } if (ttyp->nbuff_written == ttyp->nbuff) { ttyp->nbuff = 0; ttyp->nbuff_written = 0; } if (if_queued) goto again; #endif } slirp-1.0.17/src/if.h0000644000175000017500000000310310115276014013335 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _IF_H_ #define _IF_H_ #define IF_COMPRESS 0x01 /* We want compression */ #define IF_NOCOMPRESS 0x02 /* Do not do compression */ #define IF_AUTOCOMP 0x04 /* Autodetect (default) */ #define IF_NOCIDCOMP 0x08 /* CID compression */ /* Needed for FreeBSD */ #undef if_mtu extern int if_mtu; extern int if_mru; /* MTU and MRU */ extern int if_comp; /* Flags for compression */ extern int if_maxlinkhdr; extern int if_queued; /* Number of packets queued so far */ extern int if_thresh; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ extern struct mbuf if_fastq; /* fast queue (for interactive data) */ extern struct mbuf if_batchq; /* queue for non-interactive data */ extern struct mbuf *next_m; #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) /* Interface statistics */ struct slirp_ifstats { u_int out_pkts; /* Output packets */ u_int out_bytes; /* Output bytes */ u_int out_errpkts; /* Output Error Packets */ u_int out_errbytes; /* Output Error Bytes */ u_int in_pkts; /* Input packets */ u_int in_bytes; /* Input bytes */ u_int in_errpkts; /* Input Error Packets */ u_int in_errbytes; /* Input Error Bytes */ u_int bytes_saved; /* Number of bytes that compression "saved" */ /* ie: number of bytes that didn't need to be sent over the link * because of compression */ u_int in_mbad; /* Bad incoming packets */ }; #endif slirp-1.0.17/src/if.p0000644000175000017500000000036410117211711013346 0ustar roverrovervoid ifs_insque _P((struct mbuf *, struct mbuf *)); void ifs_remque _P((struct mbuf *)); void if_init _P((void)); inline int writen _P((int, char *, int)); void if_input _P((struct ttys *)); void if_output _P((struct socket *, struct mbuf *)); slirp-1.0.17/src/ip.h0000644000175000017500000002352710115276014013363 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp */ #ifndef _IP_H_ #define _IP_H_ #ifdef WORDS_BIGENDIAN # ifndef NTOHL # define NTOHL(d) # endif # ifndef NTOHS # define NTOHS(d) # endif # ifndef HTONL # define HTONL(d) # endif # ifndef HTONS # define HTONS(d) # endif #else # ifndef NTOHL # define NTOHL(d) ((d) = ntohl((d))) # endif # ifndef NTOHS # define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) # endif # ifndef HTONL # define HTONL(d) ((d) = htonl((d))) # endif # ifndef HTONS # define HTONS(d) ((d) = htons((u_int16_t)(d))) # endif #endif typedef u_int32_t n_long; /* long as received from the net */ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ #define IPVERSION 4 /* * Structure of an internet header, naked of options. * * We declare ip_len and ip_off to be short, rather than u_short * pragmatically since otherwise unsigned comparisons can result * against negative integers quite easily, and fail in subtle ways. */ struct ip { #ifdef WORDS_BIGENDIAN u_int ip_v:4, /* version */ ip_hl:4; /* header length */ #else u_int ip_hl:4, /* header length */ ip_v:4; /* version */ #endif u_int8_t ip_tos; /* type of service */ int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ int16_t ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* don't fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_int8_t ip_ttl; /* time to live */ u_int8_t ip_p; /* protocol */ u_int16_t ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ }; #define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 /* * Definitions for options. */ #define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_CONTROL 0x00 #define IPOPT_RESERVED1 0x20 #define IPOPT_DEBMEAS 0x40 #define IPOPT_RESERVED2 0x60 #define IPOPT_EOL 0 /* end of option list */ #define IPOPT_NOP 1 /* no operation */ #define IPOPT_RR 7 /* record packet route */ #define IPOPT_TS 68 /* timestamp */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SSRR 137 /* strict source route */ /* * Offsets to fields in options other than EOL and NOP. */ #define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OLEN 1 /* option length */ #define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ struct ip_timestamp { u_int8_t ipt_code; /* IPOPT_TS */ u_int8_t ipt_len; /* size of structure (variable) */ u_int8_t ipt_ptr; /* index of current entry */ #ifdef WORDS_BIGENDIAN u_int ipt_oflw:4, /* overflow counter */ ipt_flg:4; /* flags, see below */ #else u_int ipt_flg:4, /* flags, see below */ ipt_oflw:4; /* overflow counter */ #endif union ipt_timestamp { n_long ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; n_long ipt_time; } ipt_ta[1]; } ipt_timestamp; }; /* flag bits for ipt_flg */ #define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ #define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ #define MAXTTL 255 /* maximum time to live (seconds) */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ #ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ #include #else #if SIZEOF_CHAR_P == 4 typedef caddr_t caddr32_t; #else typedef u_int32_t caddr32_t; #endif #endif #if SIZEOF_CHAR_P == 4 typedef struct ipq *ipqp_32; typedef struct ipasfrag *ipasfragp_32; #else typedef caddr32_t ipqp_32; typedef caddr32_t ipasfragp_32; #endif /* * Overlay for ip header used by other protocols (tcp, udp). */ struct ipovly { caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ u_int8_t ih_x1; /* (unused) */ u_int8_t ih_pr; /* protocol */ int16_t ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ }; /* * Ip reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. * They are timed out after ipq_ttl drops to 0, and may also * be reclaimed if memory becomes tight. * size 28 bytes */ struct ipq { ipqp_32 next,prev; /* to other reass headers */ u_int8_t ipq_ttl; /* time for reass q to live */ u_int8_t ipq_p; /* protocol of this fragment */ u_int16_t ipq_id; /* sequence id for reassembly */ ipasfragp_32 ipq_next,ipq_prev; /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; }; /* * Ip header, when holding a fragment. * * Note: ipf_next must be at same offset as ipq_next above */ struct ipasfrag { #ifdef WORDS_BIGENDIAN u_int ip_v:4, ip_hl:4; #else u_int ip_hl:4, ip_v:4; #endif /* BUG : u_int changed to u_int8_t. * sizeof(u_int)==4 on linux 2.0 */ u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit * to avoid destroying tos (PPPDTRuu); * copied from (ip_off&IP_MF) */ int16_t ip_len; u_int16_t ip_id; int16_t ip_off; u_int8_t ip_ttl; u_int8_t ip_p; u_int16_t ip_sum; ipasfragp_32 ipf_next; /* next fragment */ ipasfragp_32 ipf_prev; /* previous fragment */ }; /* * Structure stored in mbuf in inpcb.ip_options * and passed to ip_output when ip options are in use. * The actual length of the options (including ipopt_dst) * is in m_len. */ #define MAX_IPOPTLEN 40 struct ipoption { struct in_addr ipopt_dst; /* first-hop dst if source routed */ int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. */ struct ipstat { u_long ips_total; /* total packets received */ u_long ips_badsum; /* checksum bad */ u_long ips_tooshort; /* packet too short */ u_long ips_toosmall; /* not enough data */ u_long ips_badhlen; /* ip header length < data size */ u_long ips_badlen; /* ip length < ip header length */ u_long ips_fragments; /* fragments received */ u_long ips_fragdropped; /* frags dropped (dups, out of space) */ u_long ips_fragtimeout; /* fragments timed out */ u_long ips_forward; /* packets forwarded */ u_long ips_cantforward; /* packets rcvd for unreachable dest */ u_long ips_redirectsent; /* packets forwarded on same net */ u_long ips_noproto; /* unknown or unsupported protocol */ u_long ips_delivered; /* datagrams delivered to upper level*/ u_long ips_localout; /* total ip packets generated here */ u_long ips_odropped; /* lost packets due to nobufs, etc. */ u_long ips_reassembled; /* total packets reassembled ok */ u_long ips_fragmented; /* datagrams successfully fragmented */ u_long ips_ofragments; /* output fragments created */ u_long ips_cantfrag; /* don't fragment flag was set, etc. */ u_long ips_badoptions; /* error in option processing */ u_long ips_noroute; /* packets discarded due to no route */ u_long ips_badvers; /* ip version != 4 */ u_long ips_rawout; /* total raw ip packets generated */ u_long ips_unaligned; /* times the ip packet was not aligned */ }; extern struct ipstat ipstat; extern struct ipq ipq; /* ip reass. queue */ extern u_int16_t ip_id; /* ip packet ctr, for ids */ extern int ip_defttl; /* default IP ttl */ #endif slirp-1.0.17/src/ip_icmp.c0000644000175000017500000002507210117211711014356 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1993 * 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. * * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp */ #include "slirp.h" #include "ip_icmp.h" struct icmpstat icmpstat; /* The message sent when emulating PING */ /* Be nice and tell them it's just a psuedo-ping packet */ char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; /* list of actions for icmp_error() on RX of an icmp message */ static int icmp_flush[19] = { /* ECHO REPLY (0) */ 0, 1, 1, /* DEST UNREACH (3) */ 1, /* SOURCE QUENCH (4)*/ 1, /* REDIRECT (5) */ 1, 1, 1, /* ECHO (8) */ 0, /* ROUTERADVERT (9) */ 1, /* ROUTERSOLICIT (10) */ 1, /* TIME EXCEEDED (11) */ 1, /* PARAMETER PROBLEM (12) */ 1, /* TIMESTAMP (13) */ 0, /* TIMESTAMP REPLY (14) */ 0, /* INFO (15) */ 0, /* INFO REPLY (16) */ 0, /* ADDR MASK (17) */ 0, /* ADDR MASK REPLY (18) */ 0 }; /* * Process a received ICMP message. */ void icmp_input(m, hlen) struct mbuf *m; int hlen; { register struct icmp *icp; register struct ip *ip=mtod(m, struct ip *); int icmplen=ip->ip_len; /* int code; */ DEBUG_CALL("icmp_input"); DEBUG_ARG("m = %lx", (long )m); DEBUG_ARG("m_len = %d", m->m_len); icmpstat.icps_received++; /* * Locate icmp structure in mbuf, and check * that its not corrupted and of at least minimum length. */ if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ icmpstat.icps_tooshort++; freeit: m_freem(m); goto end_error; } m->m_len -= hlen; m->m_data += hlen; icp = mtod(m, struct icmp *); if (cksum(m, icmplen)) { icmpstat.icps_checksum++; goto freeit; } m->m_len += hlen; m->m_data -= hlen; /* icmpstat.icps_inhist[icp->icmp_type]++; */ /* code = icp->icmp_code; */ DEBUG_ARG("icmp_type = %d", icp->icmp_type); switch (icp->icmp_type) { case ICMP_ECHO: icp->icmp_type = ICMP_ECHOREPLY; ip->ip_len += hlen; /* since ip_input subtracts this */ if (ip->ip_dst.s_addr == our_addr.s_addr || (ip->ip_dst.s_addr == (special_addr.s_addr|htonl(CTL_ALIAS))) ) { icmp_reflect(m); } else { struct socket *so; struct sockaddr_in addr; if ((so = socreate()) == NULL) goto freeit; if(udp_attach(so) == -1) { DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); m_free(m); goto end_error; } so->so_m = m; so->so_faddr = ip->ip_dst; so->so_fport = htons(7); so->so_laddr = ip->ip_src; so->so_lport = htons(9); so->so_iptos = ip->ip_tos; so->so_type = IPPROTO_ICMP; so->so_state = SS_ISFCONNECTED; /* Send the packet */ addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else { addr.sin_addr = so->so_faddr; } addr.sin_port = so->so_fport; if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", errno,strerror(errno))); icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); udp_detach(so); } } /* if ip->ip_dst.s_addr == our_addr.s_addr */ break; case ICMP_UNREACH: /* XXX? report error? close socket? */ case ICMP_TIMXCEED: case ICMP_PARAMPROB: case ICMP_SOURCEQUENCH: case ICMP_TSTAMP: case ICMP_MASKREQ: case ICMP_REDIRECT: icmpstat.icps_notsupp++; m_freem(m); break; default: icmpstat.icps_badtype++; m_freem(m); } /* swith */ end_error: /* m is m_free()'d xor put in a socket xor or given to ip_send */ return; } /* * Send an ICMP message in response to a situation * * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). * MUST NOT change this header information. * MUST NOT reply to a multicast/broadcast IP address. * MUST NOT reply to a multicast/broadcast MAC address. * MUST reply to only the first fragment. */ /* * Send ICMP_UNREACH back to the source regarding msrc. * mbuf *msrc is used as a template, but is NOT m_free()'d. * It is reported as the bad ip packet. The header should * be fully correct and in host byte order. * ICMP fragmentation is illegal. All machines must accept 576 bytes in one * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 */ #define ICMP_MAXDATALEN (IP_MSS-28) void icmp_error(msrc, type, code, minsize, message) struct mbuf *msrc; u_char type; u_char code; int minsize; char *message; { unsigned hlen, shlen, s_ip_len; register struct ip *ip; register struct icmp *icp; register struct mbuf *m; DEBUG_CALL("icmp_error"); DEBUG_ARG("msrc = %lx", (long )msrc); DEBUG_ARG("msrc_len = %d", msrc->m_len); if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; /* check msrc */ if(!msrc) goto end_error; ip = mtod(msrc, struct ip *); #if DEBUG { char bufa[20], bufb[20]; strncpy(bufa, inet_ntoa(ip->ip_src), sizeof(bufa)); strncpy(bufb, inet_ntoa(ip->ip_dst), sizeof(bufb)); DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); } #endif if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ shlen=ip->ip_hl << 2; s_ip_len=ip->ip_len; if(ip->ip_p == IPPROTO_ICMP) { icp = (struct icmp *)((char *)ip + shlen); /* * Assume any unknown ICMP type is an error. This isn't * specified by the RFC, but think about it.. */ if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; } /* make a copy */ if(!(m=m_get())) goto end_error; /* get mbuf */ { int new_m_size; new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; if(new_m_size>m->m_size) m_inc(m, new_m_size); } memcpy(m->m_data, msrc->m_data, msrc->m_len); m->m_len = msrc->m_len; /* copy msrc to m */ /* make the header of the reply packet */ ip = mtod(m, struct ip *); hlen= sizeof(struct ip ); /* no options in reply */ /* fill in icmp */ m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ s_ip_len=ICMP_MAXDATALEN; m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ /* min. size = 8+sizeof(struct ip)+8 */ icp->icmp_type = type; icp->icmp_code = code; icp->icmp_id = 0; icp->icmp_seq = 0; memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ HTONS(icp->icmp_ip.ip_len); HTONS(icp->icmp_ip.ip_id); HTONS(icp->icmp_ip.ip_off); #if DEBUG if(message) { /* DEBUG : append message to ICMP packet */ int message_len; char *cpnt; message_len=strlen(message); if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; cpnt=(char *)m->m_data+m->m_len; memcpy(cpnt, message, message_len); m->m_len+=message_len; } #endif icp->icmp_cksum = 0; icp->icmp_cksum = cksum(m, m->m_len); m->m_data -= hlen; m->m_len += hlen; /* fill in ip */ ip->ip_hl = hlen >> 2; ip->ip_len = m->m_len; ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ ip->ip_ttl = MAXTTL; ip->ip_p = IPPROTO_ICMP; ip->ip_dst = ip->ip_src; /* ip adresses */ ip->ip_src = our_addr; (void ) ip_output((struct socket *)NULL, m); icmpstat.icps_reflect++; end_error: return; } #undef ICMP_MAXDATALEN /* * Reflect the ip packet back to the source */ void icmp_reflect(m) struct mbuf *m; { register struct ip *ip = mtod(m, struct ip *); int hlen = ip->ip_hl << 2; int optlen = hlen - sizeof(struct ip ); register struct icmp *icp; /* * Send an icmp packet back to the ip level, * after supplying a checksum. */ m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); icp->icmp_cksum = 0; icp->icmp_cksum = cksum(m, ip->ip_len - hlen); m->m_data -= hlen; m->m_len += hlen; /* fill in ip */ if (optlen > 0) { /* * Strip out original options by copying rest of first * mbuf's data back, and adjust the IP length. */ memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, (unsigned )(m->m_len - hlen)); hlen -= optlen; ip->ip_hl = hlen >> 2; ip->ip_len -= optlen; m->m_len -= optlen; } ip->ip_ttl = MAXTTL; { /* swap */ struct in_addr icmp_dst; icmp_dst = ip->ip_dst; ip->ip_dst = ip->ip_src; ip->ip_src = icmp_dst; } (void ) ip_output((struct socket *)NULL, m); icmpstat.icps_reflect++; } slirp-1.0.17/src/ip_icmp.h0000644000175000017500000001426710115276014014374 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp */ #ifndef _NETINET_IP_ICMP_H_ #define _NETINET_IP_ICMP_H_ /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ typedef u_int32_t n_time; /* * Structure of an icmp header. */ struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ union { u_char ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { u_short icd_id; u_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { u_short ipm_void; u_short ipm_nextmtu; } ih_pmtu; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu union { struct id_ts { n_time its_otime; n_time its_rtime; n_time its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; u_long id_mask; char id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data }; /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the * packet is large enought to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) /* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ #define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_ECHO 8 /* echo service */ #define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_IREQ 15 /* information request */ #define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MAXTYPE 18 #define ICMP_INFOTYPE(type) \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #endif slirp-1.0.17/src/ip_icmp.p0000644000175000017500000000022310117211711014362 0ustar roverrovervoid icmp_input _P((struct mbuf *, int)); void icmp_error _P((struct mbuf *, u_char, u_char, int, char *)); void icmp_reflect _P((struct mbuf *)); slirp-1.0.17/src/ip_input.c0000644000175000017500000004204410115276013014567 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1993 * 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. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp */ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include "ip_icmp.h" int ip_defttl; struct ipstat ipstat; struct ipq ipq; /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ void ip_init() { ipq.next = ipq.prev = (ipqp_32)&ipq; ip_id = tt.tv_sec & 0xffff; udp_init(); tcp_init(); ip_defttl = IPDEFTTL; } /* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ip_input(m) struct mbuf *m; { register struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); ipstat.ips_total++; if (m->m_len < sizeof (struct ip)) { ipstat.ips_toosmall++; return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlenm->m_len) {/* min header length */ ipstat.ips_badhlen++; /* or packet too short */ goto bad; } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { ipstat.ips_tooshort++; goto bad; } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ /* We do no IP options */ /* if (hlen > sizeof (struct ip) && ip_dooptions(m)) * goto next; */ /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; /* * Look for queue of fragments * of this datagram. */ for (fp = (struct ipq *) ipq.next; fp != &ipq; fp = (struct ipq *) fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; found: /* * Adjust ip_len to not reflect header, * set ip_mff if more fragments are expected, * convert offset of this to bytes. */ ip->ip_len -= hlen; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; else ((struct ipasfrag *)ip)->ipf_mff &= ~1; ip->ip_off <<= 3; /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) return; ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; switch (ip->ip_p) { case IPPROTO_TCP: tcp_input(m, hlen, (struct socket *)NULL); break; case IPPROTO_UDP: udp_input(m, hlen); break; case IPPROTO_ICMP: icmp_input(m, hlen); break; default: ipstat.ips_noproto++; m_free(m); } return; bad: m_freem(m); return; } /* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */ struct ip * ip_reass(ip, fp) register struct ipasfrag *ip; register struct ipq *fp; { register struct mbuf *m = dtom(ip); register struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; DEBUG_CALL("ip_reass"); DEBUG_ARG("ip = %lx", (long)ip); DEBUG_ARG("fp = %lx", (long)fp); DEBUG_ARG("m = %lx", (long)m); /* * Presence of header sizes in mbufs * would confuse code below. * Fragment m_data is concatenated. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { struct mbuf *t; if ((t = m_get()) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque_32(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *)q->ipf_next) if (q->ip_off > ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if (q->ipf_prev != (ipasfragp_32)fp) { i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; m_adj(dtom(ip), i); ip->ip_off += i; ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { i = (ip->ip_off + ip->ip_len) - q->ip_off; if (i < q->ip_len) { q->ip_len -= i; q->ip_off += i; m_adj(dtom(q), i); break; } q = (struct ipasfrag *) q->ipf_next; m_freem(dtom((struct ipasfrag *) q->ipf_prev)); ip_deq((struct ipasfrag *) q->ipf_prev); } insert: /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, (struct ipasfrag *) q->ipf_prev); next = 0; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *) q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) return (0); /* * Reassembly is complete; concatenate fragments. */ q = (struct ipasfrag *) fp->ipq_next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; while (q != (struct ipasfrag *)fp) { struct mbuf *t; t = dtom(q); m_cat(m, t); q = (struct ipasfrag *) q->ipf_next; } /* * Create header for new ip packet by * modifying header of first packet; * dequeue and discard fragment reassembly header. * Make header visible. */ ip = (struct ipasfrag *) fp->ipq_next; /* * If the fragments concatenated to an mbuf that's * bigger than the total size of the fragment, then and * m_ext buffer was alloced. But fp->ipq_next points to * the old buffer (in the mbuf), so we must point ip * into the new buffer. */ if (m->m_flags & M_EXT) { int delta; delta = (char *)ip - m->m_dat; ip = (struct ipasfrag *)(m->m_ext + delta); } /* DEBUG_ARG("ip = %lx", (long)ip); * ip=(struct ipasfrag *)m->m_data; */ ip->ip_len = next; ip->ipf_mff &= ~1; ((struct ip *)ip)->ip_src = fp->ipq_src; ((struct ip *)ip)->ip_dst = fp->ipq_dst; remque_32(fp); (void) m_free(dtom(fp)); m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); return ((struct ip *)ip); dropfrag: ipstat.ips_fragdropped++; m_freem(m); return (0); } /* * Free a fragment reassembly header and all * associated datagrams. */ void ip_freef(fp) struct ipq *fp; { register struct ipasfrag *q, *p; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { p = (struct ipasfrag *) q->ipf_next; ip_deq(q); m_freem(dtom(q)); } remque_32(fp); (void) m_free(dtom(fp)); } /* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ void ip_enq(p, prev) register struct ipasfrag *p, *prev; { DEBUG_CALL("ip_enq"); DEBUG_ARG("prev = %lx", (long)prev); p->ipf_prev = (ipasfragp_32) prev; p->ipf_next = prev->ipf_next; ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; prev->ipf_next = (ipasfragp_32) p; } /* * To ip_enq as remque is to insque. */ void ip_deq(p) register struct ipasfrag *p; { ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; } /* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */ void ip_slowtimo() { register struct ipq *fp; DEBUG_CALL("ip_slowtimo"); fp = (struct ipq *) ipq.next; if (fp == 0) return; while (fp != &ipq) { --fp->ipq_ttl; fp = (struct ipq *) fp->next; if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef((struct ipq *) fp->prev); } } } /* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, * or forwarding it if source-routed. * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */ #ifdef notdef int ip_dooptions(m) struct mbuf *m; { register struct ip *ip = mtod(m, struct ip *); register u_char *cp; register struct ip_timestamp *ipt; register struct in_ifaddr *ia; /* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ int opt, optlen, cnt, off, code, type, forward = 0; struct in_addr *sin, dst; typedef u_int32_t n_time; n_time ntime; dst = ip->ip_dst; cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= 0 || optlen > cnt) { code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } } switch (opt) { default: break; /* * Source routing with record. * Find interface with current destination address. * If none on this machine then drop if strictly routed, * or do nothing if loosely routed. * Record interface address and bring up next address * component. If strictly routed make sure next * address is on directly accessible net. */ case IPOPT_LSRR: case IPOPT_SSRR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } ipaddr.sin_addr = ip->ip_dst; ia = (struct in_ifaddr *) ifa_ifwithaddr((struct sockaddr *)&ipaddr); if (ia == 0) { if (opt == IPOPT_SSRR) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } /* * Loose routing, and not at next destination * yet; nothing to do except forward. */ break; } off--; / * 0 origin * / if (off > optlen - sizeof(struct in_addr)) { /* * End of source route. Should be for us. */ save_rte(cp, ip->ip_src); break; } /* * locate outgoing interface */ bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); if (opt == IPOPT_SSRR) { #define INA struct in_ifaddr * #define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) ia = (INA)ifa_ifwithnet((SA)&ipaddr); } else ia = ip_rtaddr(ipaddr.sin_addr); if (ia == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } ip->ip_dst = ipaddr.sin_addr; bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); /* * Let ip_intr's mcast routing check handle mcast pkts */ forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); break; case IPOPT_RR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } /* * If no space remains, ignore. */ off--; * 0 origin * if (off > optlen - sizeof(struct in_addr)) break; bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); /* * locate outgoing interface; if we're the destination, * use the incoming interface (should be same). */ if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; goto bad; } bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; if (ipt->ipt_len < 5) goto bad; if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { if (++ipt->ipt_oflw == 0) goto bad; break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; ipaddr.sin_addr = dst; ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, m->m_pkthdr.rcvif); if (ia == 0) continue; bcopy((caddr_t)&IA_SIN(ia)->sin_addr, (caddr_t)sin, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); break; case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) continue; ipt->ipt_ptr += sizeof(struct in_addr); break; default: goto bad; } ntime = iptime(); bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, sizeof(n_time)); ipt->ipt_ptr += sizeof(n_time); } } if (forward) { ip_forward(m, 1); return (1); } } } return (0); bad: /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ /* Not yet */ icmp_error(m, type, code, 0, 0); ipstat.ips_badoptions++; return (1); } #endif /* notdef */ /* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. * (XXX) should be deleted; last arg currently ignored. */ void ip_stripoptions(m, mopt) register struct mbuf *m; struct mbuf *mopt; { register int i; struct ip *ip = mtod(m, struct ip *); register caddr_t opts; int olen; olen = (ip->ip_hl<<2) - sizeof (struct ip); opts = (caddr_t)(ip + 1); i = m->m_len - (sizeof (struct ip) + olen); memcpy(opts, opts + olen, (unsigned)i); m->m_len -= olen; ip->ip_hl = sizeof(struct ip) >> 2; } slirp-1.0.17/src/ip_input.p0000644000175000017500000000060310115325663014605 0ustar roverrovervoid ip_init _P((void)); void ip_input _P((struct mbuf *)); struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); void ip_freef _P((struct ipq *)); void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); void ip_deq _P((register struct ipasfrag *)); void ip_slowtimo _P((void)); void ip_stripoptions _P((register struct mbuf *, struct mbuf *)); slirp-1.0.17/src/ip_output.c0000644000175000017500000001277610115276013015001 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * 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. * * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp */ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include u_int16_t ip_id; /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. */ int ip_output(so, m0) struct socket *so; struct mbuf *m0; { register struct ip *ip; register struct mbuf *m = m0; register int hlen = sizeof(struct ip ); int len, off, error = 0; DEBUG_CALL("ip_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m0 = %lx", (long)m0); /* We do no options */ /* if (opt) { * m = ip_insertoptions(m, opt, &len); * hlen = len; * } */ ip = mtod(m, struct ip *); /* * Fill in IP header. */ ip->ip_v = IPVERSION; ip->ip_off &= IP_DF; ip->ip_id = htons(ip_id++); ip->ip_hl = hlen >> 2; ipstat.ips_localout++; /* * Verify that we have any chance at all of being able to queue * the packet or packet fragments */ /* XXX Hmmm... */ /* if (if_queued > if_thresh && towrite <= 0) { * error = ENOBUFS; * goto bad; * } */ /* * If small enough for interface, can just send directly. */ if ((u_int16_t)ip->ip_len <= if_mtu) { ip->ip_len = htons((u_int16_t)ip->ip_len); ip->ip_off = htons((u_int16_t)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); if_output(so, m); goto done; } /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. */ if (ip->ip_off & IP_DF) { error = -1; ipstat.ips_cantfrag++; goto bad; } len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ if (len < 8) { error = -1; goto bad; } { int mhlen, firstlen = len; struct mbuf **mnext = &m->m_nextpkt; /* * Loop through length of segment after first fragment, * make new header and copy data of each part and link onto chain. */ m0 = m; mhlen = sizeof (struct ip); for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { register struct ip *mhip; m = m_get(); if (m == 0) { error = -1; ipstat.ips_odropped++; goto sendorfree; } m->m_data += if_maxlinkhdr; mhip = mtod(m, struct ip *); *mhip = *ip; /* No options */ /* if (hlen > sizeof (struct ip)) { * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); * mhip->ip_hl = mhlen >> 2; * } */ m->m_len = mhlen; mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); if (ip->ip_off & IP_MF) mhip->ip_off |= IP_MF; if (off + len >= (u_int16_t)ip->ip_len) len = (u_int16_t)ip->ip_len - off; else mhip->ip_off |= IP_MF; mhip->ip_len = htons((u_int16_t)(len + mhlen)); if (m_copy(m, m0, off, len) < 0) { error = -1; goto sendorfree; } mhip->ip_off = htons((u_int16_t)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = cksum(m, mhlen); *mnext = m; mnext = &m->m_nextpkt; ipstat.ips_ofragments++; } /* * Update first fragment by trimming what's been copied out * and updating header, then send each fragment (in order). */ m = m0; m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); ip->ip_len = htons((u_int16_t)m->m_len); ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) if_output(so, m); else m_freem(m); } if (error == 0) ipstat.ips_fragmented++; } done: return (error); bad: m_freem(m0); goto done; } slirp-1.0.17/src/ip_output.p0000644000175000017500000000006410115325663015007 0ustar roverroverint ip_output _P((struct socket *, struct mbuf *)); slirp-1.0.17/src/main.c0000644000175000017500000010126310433144606013670 0ustar roverrover/* * Copyright (c) 1995,1996 Danny Gasparovski. * Parts Copyright (c) 2000,2001 Kelly "STrRedWolf" Price. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #define WANT_TERMIOS_H #include #include "main.h" struct timeval tt; struct ex_list *exec_list = NULL; /* The patch broke slirp, but I think this will fix it. * I did a SLIRP_TTY=/dev/tty slirp and it actually worked. * So lets make it a default and change it all over to what the patch * does. * * Oh, yeah, Slirp likes to set a terminal to raw. Grumble. * -RedWolf */ char *slirp_default_tty = "/dev/tty"; /* Ugly constant, but it works */ struct termios slirp_tty_settings; /* Half the world probably going to kill me. */ int slirp_tty_restore=0; /* Just incase we default to /dev/tty */ char *slirp_tty=NULL; /* Make sure this is NULL */ extern int nozeros; char *exec_shell; char *socket_path; int do_slowtimo; int ctty_closed; struct ttys *ttys; extern void alrm _P((int)); struct in_addr our_addr; struct in_addr ctl_addr; struct in_addr special_addr; struct in_addr dns_addr, dns2_addr; struct in_addr loopback_addr; int link_up; int slirp_socket = -1; int slirp_socket_unit = -1; u_int32_t slirp_socket_addr; int slirp_socket_port; char *slirp_socket_passwd; u_int slirp_socket_wait; char *username; int towrite_max = TOWRITEMAX; #ifdef USE_PPP char *path_upap; char *path_chap; #endif FILE *lfd; int main(argc, argv) int argc; char **argv; { lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; lprint_ptr2 = (char *)stderr; lprint_arg = (char **)&lprint_ptr2; lprint("Slirp v%s (%s)\n\n", SLIRP_VERSION, SLIRP_STATUS); lprint("Copyright (c) 1995,1996 Danny Gasparovski and others.\n"); lprint("All rights reserved.\n"); lprint("This program is copyrighted, free software.\n"); lprint("Please read the file COPYRIGHT that came with the Slirp\n"); lprint("package for the terms and conditions of the copyright.\n\n"); /* To enable debugging early, enable the following line, Do NOT use -d -1 on the command line in this case. */ /* debug_init("slirp_debug", -1); */ main_init(argc, argv); main_loop(); /* NOTREACHED */ return 0; } void tty_init (argc, argv) int argc; char **argv; { char* env_tty; size_t env_tty_len; /* @@Hack, first scan command line for a "tty /dev/ttyS0 type entry, make slirp_tty = that, otherwise use SLIRP_TTY environment. The options code will check that an argument is present for tty, but otherwise ignores it. */ for(++argv;*argv;++argv) { if((strncmp(*argv, "tty", 3 ) == 0) && isspace((*argv)[3])) { /* Skip whitespace */ char *ptr = (*argv)+3; while(isspace(*ptr) && *ptr) ptr++; if(*ptr) slirp_tty = strdup(ptr); break; } } if(slirp_tty == NULL) { env_tty = getenv ("SLIRP_TTY"); if (NULL == env_tty) { /* We're using the terminal, so default to it. * While we're at it, save the terminal. */ slirp_tty=NULL; /* Assume nothing */ } else { env_tty_len = strlen (env_tty); slirp_tty = malloc (env_tty_len + 1); if (NULL == slirp_tty) { lprint ("Error: Out of memory allocating tty string.\r\n"); slirp_exit (1); } strncpy2 (slirp_tty, env_tty, env_tty_len); } } } void main_init(argc, argv) int argc; char **argv; { int i; char buff[512]; char *bptr; #ifdef USE_PPP sigset_t mask; struct sigaction sa; #endif tty_init(argc,argv); inet_aton("127.0.0.1", &loopback_addr); ctl_addr.s_addr = 0; special_addr.s_addr = -1; #ifdef USE_TMPSOCKET /* Get user's name */ username = getlogin(); if (!username) { struct passwd *pw = getpwuid(getuid()); if (pw) username = pw->pw_name; if (!username) { lprint("Error: can't find your username\n"); slirp_exit(1); } } strcpy(buff, "/tmp/"); strncat(buff, username, sizeof(buff)-6); socket_path = strdup(buff); #else if ((bptr = (char *)getenv("HOME")) == NULL) { lprint("Error: can't find your HOME\n"); slirp_exit(1); } strncpy2(buff, bptr, sizeof(buff) - 15 ); strcat(buff, "/.slirp_socket"); socket_path = strdup(buff); #endif /* XXX PPP init */ #ifdef USE_PPP if (gethostname(hostname, MAXNAMELEN) < 0 ) { perror("couldn't get hostname"); die(1); } hostname[MAXNAMELEN-1] = 0; sigemptyset(&mask); sigaddset(&mask, SIGALRM); sa.sa_mask = mask; sa.sa_flags = 0; sa.sa_handler = alrm; sigaction(SIGALRM, &sa, NULL); #endif /* Initialise everything */ /* Main aim of this seems to be to make debugging harder... for (i = 255; i > 2; i--) { close(i); } */ /* * Check the socket */ { #ifndef NO_UNIX_SOCKETS struct sockaddr_un sock_un; #endif struct sockaddr_in sock_in; int s = -1, unit, port = 0, ret; int want_link = 0; char pwd[256], hn[256]; struct hostent *hp; /* * Check if the user wants to "attach" a new session */ if (argc >= 3 && argv[1][0] == '-' && argv[1][1] == 'l') { argv += 2; /* Point past -l N */ argc -= 2; if (strchr(*argv, ':')) { /* It's an internet socket */ if (sscanf(*argv, "%d,%[^:]:%d,%s", &unit, hn, &port, pwd) != 4) { lprint("Error: bad arguements to -l\n"); slirp_exit(1); } if (strcmp(pwd, "-") == 0) { /* It's in the environmental variable SLIRP_PASSWORD */ slirp_socket_passwd = (char *)getenv("SLIRP_PASSWORD"); if (slirp_socket_passwd == NULL) { lprint("Error: no password in environmental variable SLIRP_PASSWORD\r\n"); slirp_exit(1); } slirp_socket_passwd = strdup(slirp_socket_passwd); } else { slirp_socket_passwd = strdup(pwd); } if (!port) { lprint("Error: bad port number\n"); slirp_exit(1); } if ((hp = gethostbyname(hn)) == NULL) { lprint("Error: bad hostname\n"); slirp_exit(1); } slirp_socket_addr = *(u_int32_t *)hp->h_addr; /* Clear the password */ memset(*argv, 'X', strlen(*argv)); } else { unit = atoi(*argv); } want_link = 1; } slirp_socket_unit = unit; slirp_socket_port = port; ret = -1; if (slirp_socket_passwd) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("Error: Cannot create socket"); slirp_exit(1); } sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = slirp_socket_addr; sock_in.sin_port = htons(port); ret = connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)); } #ifndef NO_UNIX_SOCKETS else { s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { perror("Error: Cannot create socket"); slirp_exit(1); } sock_un.sun_family = AF_UNIX; strncpy2(sock_un.sun_path, socket_path, sizeof(sock_un.sun_path)); sock_un.sun_path[sizeof(sock_un.sun_path)-1]='\0'; ret = connect(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)); } #endif if (ret == 0) { /* Connected, we either link or die */ if (!want_link) { /* * Ooops, user doesn't want to attach another tty, * but there's already a slirp running, quit. */ lprint("Error: Slirp is already running\n"); slirp_exit(1); } /* Warn the user no more options are parsed */ if (argc > 1) lprint("Warning: all options past -l are ignored\r\n"); if (slirp_socket_passwd) { /* Internet connection */ snprintf(buff, sizeof(buff), "%d %d %s", unit, 0, slirp_socket_passwd); } #ifndef NO_UNIX_SOCKETS else { snprintf(buff, sizeof(buff), "%d %d %s", unit, (int)getpid(), ttyname(0)); } #endif write(s, buff, strlen(buff)+1); read(s, buff, 256); if (sscanf(buff, "%d %256[^\177]", &unit, buff) != 2) { lprint("Error: buff = %s\n", buff); slirp_exit(1); } if (unit) { /* Succeeded */ lprint("Connected: %s\r\n", buff); if (slirp_socket_passwd) relay(s); else snooze(); } else { /* Failed */ lprint("Error:: %s\r\n", buff); slirp_exit(1); } close(s); } else { close(s); /* If we want a link, and it's not unit 0, bail... */ if (want_link && unit != 0) { lprint("Error: cannot connect to Slirp socket\r\n"); slirp_exit(1); } } } /* * Setup first modem */ updtime(); /* By this time, slirp_tty is NULL or is a string... */ if (NULL == tty_attach (0, slirp_tty)) { lprint ("Error: tty_attach failed in main.c:main_init()\r\n"); slirp_exit (1); } /* tty_attach in ttys.c takes care of this: ttys->fd = 0; */ { struct stat stat; if (isatty(ttys->fd) && fstat(ttys->fd, &stat) == 0) { /* Save the current permissions */ ttys->mode = stat.st_mode; #ifdef HAVE_FCHMOD fchmod(ttys->fd, S_IRUSR|S_IWUSR); #else chmod(ttyname(ttys->fd), S_IRUSR|S_IWUSR); #endif } } ttys->flags |= TTY_CTTY; /* Initialise everything */ /* so_init(); */ if_init(); ip_init(); getouraddr(); if ((bptr = (char *)getenv("HOME")) != NULL) { strncpy2(buff, bptr, sizeof(buff)-11); #ifdef USE_PPP path_upap=strjoin(buff, "/.pap-secrets"); path_chap = strjoin(buff, "/.chap-secrets"); #endif strncat(buff, "/.slirprc", sizeof(buff)); config(buff, ttys->unit); } #ifdef USE_PPP else { path_upap = "/.pap-secrets"; path_chap = "/.chap-secrets"; } #endif /* Parse options */ cfg_unit = ttys->unit; while(--argc > 0) { int str_len; argv++; i = 0; do { if ((((str_len = strlen(cfg[i].command)) && !strncmp(*argv, cfg[i].command, str_len)) || (cfg[i].command_line && (str_len = strlen(cfg[i].command_line)) && !strncmp(*argv, cfg[i].command_line, str_len))) && (*(*argv+str_len) == ' ' || *(*argv+str_len) == '\t' || *(*argv+str_len) == 0)) { /* Found it */ while (*(*argv+str_len) == ' ' || *(*argv+str_len) == '\t') str_len++; if (cfg[i].type & PRN_STDERR) { if (**argv == '-' || **argv == '+') { if (cfg[i].flags & CFG_NEEDARG) { if (argc == 1) { lprint("Error: command \"%s\" requires an argument.\r\n", cfg[i].command_line?cfg[i].command_line:cfg[i].command); break; } argv++; argc--; str_len = 0; } } else if ((cfg[i].flags & CFG_NEEDARG) && *(*argv+str_len) == 0) { lprint("Error: Insufficient arguments to \"%s\".\r\n", cfg[i].command); break; } if ((*cfg[i].func)((*(*argv+str_len)?(*argv+str_len):(char *)0), (struct socket *)0) == CFG_BADARGS) lprint("Error: Usage %s %s\r\n", cfg[i].command, cfg[i].usage_args); break; } else { lprint("Error: Command can only be executed in telnet.\r\n"); break; } } i++; } while (cfg[i].command); if (!cfg[i].command) lprint("Error: Invalid option: %s\r\n", *argv); } if (special_addr.s_addr == -1) inet_aton(CTL_SPECIAL, &special_addr); if (our_addr.s_addr == 0) { lprint("Error: Slirp Could not determine the address of this host.\r\n"); lprint(" Some programs may not work without knowing this address.\r\n"); lprint(" It is recommended you use the \"host address aaa.bbb.ccc.ddd\r\n\""); lprint(" option in your ~/.slirprc config file (where aaa.bbb.ccc.ddd\r\n"); lprint(" is the IP address of the host Slirp is running on).\r\n\r\n"); } else { lprint("IP address of Slirp host: %s\r\n", inet_ntoa(our_addr)); } /* Print the DNS */ { char buff[512]; char buff2[256]; FILE *f; int found = 0; struct in_addr tmp_addr; if(dns_addr.s_addr) /* Set up on command line perhaps. */ { lprint("IP address of your DNS(s): %s", inet_ntoa(dns_addr)); if(dns2_addr.s_addr) lprint(", %s", inet_ntoa(dns2_addr)); lprint("\r\n"); } else { if ((f = fopen("/etc/resolv.conf", "r")) != NULL) { lprint("IP address of your DNS(s): "); while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { if (!inet_aton(buff2, &tmp_addr)) continue; if (tmp_addr.s_addr == loopback_addr.s_addr) tmp_addr = our_addr; /* If it's the first one, set it to dns_addr */ if (!found) dns_addr = tmp_addr; else { lprint(", "); if(!dns2_addr.s_addr) /* Secondary dns */ dns2_addr = tmp_addr; } if (++found > 3) { lprint("(more)"); break; } else lprint("%s", inet_ntoa(tmp_addr)); } } } if (found) lprint("\r\n"); else { lprint("[none found]\r\n"); dns_addr = our_addr; /* ??? */ } } } lprint("Your address is %s\r\n", CTL_LOCAL); lprint("(or anything else you want)\r\n\r\n"); if(!nozeros) lprint("Type five zeroes (0) to exit.\r\n\r\n"); /* Setup exec_list */ if (exec_shell) { add_exec(&exec_list, 1, exec_shell, CTL_EXEC, htons(23)); free(exec_shell); exec_shell = 0; } else add_exec(&exec_list, 1, "/bin/sh", CTL_EXEC, htons(23)); add_exec(&exec_list, 0, "slirp.ftpd", CTL_EXEC, htons(21)); #ifdef USE_PPP if(ttys->proto == PROTO_SLIP) { #endif switch(if_comp) { case IF_COMPRESS: lprint("[talking CSLIP"); break; case IF_AUTOCOMP: lprint("[autodetect SLIP/CSLIP"); break; case IF_NOCOMPRESS: lprint("[talking SLIP"); break; } #ifndef FULL_BOLT lprint(", MTU %d, MRU %d, %d baud]\r\n\r\n", if_mtu, if_mru, ttys->baud); #else lprint(", MTU %d, MRU %d]\r\n\r\n", if_mtu, if_mru); #endif #ifdef USE_PPP } else { #ifndef FULL_BOLT lprint("[talking PPP, %d baud]\r\n\r\n", ttys->baud); #else lprint("[talking PPP]\r\n\r\n"); #endif } #endif lprint("SLiRP Ready ...\r\n"); if (lfd) { fprintf(lfd, "End log.\n"); fclose(lfd); lfd = 0; } /* Init a few things XXX */ last_slowtimo = curtime; time_fasttimo = 0; /* Initialise mbufs *after* setting the MTU */ m_init(); /* Main_loop init */ signal(SIGCHLD, do_wait); signal(SIGHUP, slirp_hup); signal(SIGPIPE, SIG_IGN); signal(SIGINT, slirp_exit); signal(SIGQUIT, slirp_exit); signal(SIGTERM, slirp_exit); /* signal(SIGBUS, SIG_IGN); */ /* clobber stdout and stderr so fprintf's don't clobber the link, **Updates** If stderr or stdout are not going to the same place as the ppp data will go too/come from (eg slirp_tty, or stdin) keep it open. Mainly for testing purposes, nice to be able to do fprintf(stderr... Includes Tim Watt's ttyname() fixes (modified) */ { int blnKeepErr, blnKeepStdOut; const char *ttyname_0_dup = 0; const char *ttyname_1_dup = 0; const char *ttyname_2_dup = 0; #define dup_ttyname(n) \ if( (ttyname_##n##_dup = ttyname(n)) ) { \ ttyname_##n##_dup = strdup(ttyname_##n##_dup); \ } #define clr_ttyname(n) \ if( (ttyname_##n##_dup) ) { \ free((char *) ttyname_##n##_dup); \ ttyname_##n##_dup = 0; \ } dup_ttyname(0) dup_ttyname(1) dup_ttyname(2) /* stderr going elsewhere ?? */ blnKeepErr = FALSE; if(!isatty(2)) blnKeepErr = TRUE; else { if((slirp_tty == NULL && ttyname_0_dup && ttyname_2_dup && strcmp(ttyname_0_dup, ttyname_2_dup) == 0) || (slirp_tty != NULL && ttyname_2_dup && strcmp(ttyname_2_dup, slirp_tty) == 0) ) blnKeepErr = FALSE; else blnKeepErr = TRUE; } /* stdout going elsewhere ?? */ blnKeepStdOut = FALSE; if(!isatty(1)) blnKeepStdOut = TRUE; else { if((slirp_tty == NULL && ttyname_0_dup && ttyname_1_dup && strcmp(ttyname_0_dup, ttyname_1_dup) == 0) || (slirp_tty != NULL && ttyname_1_dup && strcmp(ttyname_1_dup, slirp_tty) == 0) ) blnKeepStdOut = FALSE; else blnKeepStdOut = TRUE; } clr_ttyname(0); clr_ttyname(1); clr_ttyname(2); #undef dup_ttyname #undef clr_ttyname i = open("/dev/null", O_RDWR); if(!blnKeepStdOut) dup2(i, 1); if(!blnKeepErr) dup2(i, 2); if (i > 2) close(i); } } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) #define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) #define UPD_NFDS(x) if (nfds < (x)) nfds = (x) fd_set writefds, readfds, xfds; void main_loop() { struct socket *so, *so_next; struct timeval timeout; int ret, nfds; struct ttys *ttyp, *ttyp2; #ifndef FULL_BOLT int best_time; #endif int tmp_time; while(1) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&xfds); nfds = 0; /* * Always set modems for reading. */ link_up = 0; for (ttyp = ttys; ttyp; ttyp = ttyp->next) { if (ctty_closed && (ttyp->flags & TTY_CTTY)) { tty_detached(ttyp, 0); ctty_closed = 0; continue; } if (ttyp->up) link_up++; #ifdef USE_PPP else if (ttyp->flags & TTY_PPPSTART) { ppp_start(ttyp->unit); ttyp->flags &= ~TTY_PPPSTART; } #endif #ifdef FULL_BOLT if ((ttyp->up && if_queued) || ttyp->nbuff) { FD_SET(ttyp->fd, &writefds); UPD_NFDS(ttyp->fd); } #endif FD_SET(ttyp->fd, &readfds); UPD_NFDS(ttyp->fd); } /* * Set unix socket for reading if it exists */ if (slirp_socket >= 0) { if (!slirp_socket_wait || (curtime - slirp_socket_wait) >= 10000) { slirp_socket_wait = 0; FD_SET(slirp_socket, &readfds); UPD_NFDS(slirp_socket); } /* * If there are no active tty's, make sure we don't * hang around more than 10 minutes */ if (!ttys && ((curtime - detach_time) >= detach_wait)) slirp_exit(0); } /* * First, TCP sockets */ do_slowtimo = 0; if (link_up) { /* * *_slowtimo needs calling if there are IP fragments * in the fragment queue, or there are TCP connections active */ do_slowtimo = ((tcb.so_next != &tcb) || ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; /* * See if we need a tcp_fasttimo */ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) time_fasttimo = curtime; /* Flag when we want a fasttimo */ /* * NOFDREF can include still connecting to local-host, * newly socreated() sockets etc. Don't want to select these. */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; /* * Set for reading sockets which are accepting */ if (so->so_state & SS_FACCEPTCONN) { FD_SET(so->s,&readfds); UPD_NFDS(so->s); continue; } /* * Set for writing sockets which are connecting */ if (so->so_state & SS_ISFCONNECTING) { FD_SET(so->s,&writefds); UPD_NFDS(so->s); continue; } /* * Set for writing if we are connected, can send more, and * we have something to send */ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { FD_SET(so->s, &writefds); UPD_NFDS(so->s); } /* * Set for reading (and urgent data) if we are connected, can * receive more, and we have room for it XXX /2 ? */ if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { FD_SET(so->s, &readfds); FD_SET(so->s, &xfds); UPD_NFDS(so->s); } } /* * UDP sockets */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; /* * See if it's timed out */ if (so->so_expire) { if (so->so_expire <= curtime) { udp_detach(so); continue; } else do_slowtimo = 1; /* Let socket expire */ } /* * When UDP packets are received from over the * link, they're sendto()'d straight away, so * no need for setting for writing * Limit the number of packets queued by this session * to 4. Note that even though we try and limit this * to 4 packets, the session could have more queued * if the packets needed to be fragmented * (XXX <= 4 ?) */ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { FD_SET(so->s, &readfds); UPD_NFDS(so->s); } } } /* * Setup timeout to use minimum CPU usage, especially when idle */ /* * First, see the timeout needed by *timo */ timeout.tv_sec = 0; timeout.tv_usec = -1; /* * If a slowtimo is needed, set timeout to 500ms from the last * slow timeout. If a fast timeout is needed, set timeout within * 200ms of when it was requested. */ if (do_slowtimo) { /* XXX + 10000 because some select()'s aren't that accurate */ timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000; if (timeout.tv_usec < 0) timeout.tv_usec = 0; else if (timeout.tv_usec > 510000) timeout.tv_usec = 510000; /* Can only fasttimo if we also slowtimo */ if (time_fasttimo) { tmp_time = (200 - (curtime - time_fasttimo)) * 1000; if (tmp_time < 0) tmp_time = 0; /* Choose the smallest of the 2 */ if (tmp_time < timeout.tv_usec) timeout.tv_usec = (u_int)tmp_time; } } #ifndef FULL_BOLT /* * Find the timeout such that we can then write to a modem */ if (!if_queued || !link_up) tmp_time = -1; /* Nothing to do, flag to block forever */ else { best_time = 500001; for (ttyp = ttys; ttyp; ttyp = ttyp->next) { if (!ttyp->up) continue; /* * If there's a modem which we can write to now, * set the timeout to 0 (although it will be adjusted later on) */ if (ttyp->towrite >= 0) { best_time = 0; /* * If this modem hasn't been busy lately * (ie: it has a maximum towrite (XXX? towrite_max/2?)) * then we *really* have a timeout of 0, instead of an adjusted one */ if (ttyp->towrite == towrite_max) goto cont_1; } else { if (best_time) { tmp_time = (((-ttyp->towrite + 1) * 1000000) / ttyp->bytesps); if (tmp_time < best_time) best_time = tmp_time; } } } /* * Adjust the timeout to make the minimum timeout * 50ms (XXX?) to lessen the CPU load */ if (best_time > 500000) best_time = 500000; else if (best_time < 50000) /* XXX */ best_time = 50000; cont_1: tmp_time = best_time; } /* * Take the minimum of the above calculated timeouts */ if ((timeout.tv_usec < 0) || (tmp_time >= 0 && tmp_time < timeout.tv_usec)) timeout.tv_usec = (u_int)tmp_time; #endif DEBUG_MISC((dfd, " timeout.tv_usec = %u", (u_int)timeout.tv_usec)); if (time_fasttimo) { DEBUG_MISC((dfd, ", need fasttimo\n")); } else { DEBUG_MISC((dfd, "\n")); } /* * Do the real select call */ /* * If we're told to "wait forever", wait for 5 seconds * This will make timings (like idle timer and "wait" timer) * up to 10 seconds late, but will be more system friendly */ if (timeout.tv_usec == -1) { timeout.tv_usec = 0; timeout.tv_sec = 5; /* XXX */ } ret = select(nfds+1, &readfds, &writefds, &xfds, &timeout); if (ret < 0) { if (errno == EINTR) continue; slirp_exit(1); } /* Update time */ updtime(); /* * See if anything has timed out */ if (link_up) { if (time_fasttimo && ((curtime - time_fasttimo) >= 199)) { tcp_fasttimo(); time_fasttimo = 0; } if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) { ip_slowtimo(); tcp_slowtimo(); last_slowtimo = curtime; } } /* * Check if there are any tty's attaching */ if (slirp_socket >= 0 && FD_ISSET(slirp_socket, &readfds)) { int fd, unit, pid=0; char buff[512]; char buff2[256]; char dev[256]; char *device = dev; #ifndef NO_UNIX_SOCKETS struct sockaddr_un sock_un; int sock_len = sizeof(struct sockaddr_un); #endif struct sockaddr_in sock_in; int sock_len2 = sizeof(struct sockaddr_in); fd = -1; if (slirp_socket_passwd) fd = accept(slirp_socket, (struct sockaddr *)&sock_in, &sock_len2); #ifndef NO_UNIX_SOCKETS else fd = accept(slirp_socket, (struct sockaddr *)&sock_un, &sock_len); #endif if (fd < 0) { /* * This shouldn't happen, but if it does, something's * amiss, so we nuke the socket so that we don't enter * a tight loop of failure to accept() the socket * */ slirp_socket = -1; goto failed; } /* * Some maniac could telnet to this port and stall Slirp forever. * So, we make the socket non-blocking and wait a second. If the message * hasn't arrived, we wait another seconds and try again. If it still * hasn't arrived, we nuke the connection and don't let them connect back * for another 10 seconds * * Infact, whenever it fails we don't allow another connect for 10 seconds, * again to stop some joker from writing a program to keep connecting to this * socket in a tight loop */ fd_nonblock(fd); if (read(fd, buff, 256) < 0) { sleep(1); if (read(fd, buff, 256) < 0) { /* Nuke both connections */ sprintf(buff, "0 Connection timed out"); write(fd, buff, strlen(buff)+1); slirp_socket_wait = curtime; close(fd); goto failed; } } /* XXX Make it blocking again? */ fd_block(fd); if (sscanf(buff, "%d %d %256s", &unit, &pid, device) == 3) { if (unit >= MAX_INTERFACES || unit < 0) { sprintf(buff, "0 Unit out of range (must be between 0 and %d, inclusive)", MAX_INTERFACES-1); write(fd, buff, strlen(buff)+1); slirp_socket_wait = curtime; close(fd); goto failed; } /* Socket is an internet socket and the device is the password * (pid is invalid) */ if (slirp_socket_passwd) { if (strcmp(slirp_socket_passwd, device) != 0) { sprintf(buff, "0 Incorrect password"); write(fd, buff, strlen(buff)+1); slirp_socket_wait = curtime; close(fd); goto failed; } else { device = 0; /* Make tty_attach not open a device */ } } /* * Check that unit is not already taken, * and it's valid */ for (ttyp = ttys; ttyp; ttyp = ttyp->next) { if (ttyp->unit == unit) break; } /* * Reply is of the form " " where N is 0 for * failure, 1 for exit, and message is printed */ if (ttyp) { sprintf(buff, "0 Unit already attached"); write(fd, buff, strlen(buff)+1); slirp_socket_wait = curtime; close(fd); goto failed; } ttyp = tty_attach(unit, device); if (ttyp) { #ifdef USE_PPP if (ttyp->proto == PROTO_PPP) strcpy(buff2, "PPP"); else #endif sprintf(buff2, "SLIP, MTU %d, MRU %d", if_mtu, if_mru); #ifndef FULL_BOLT snprintf(buff, sizeof(buff), "1 Attached as unit %d, device %s\r\n\r\n[talking %s, %d baud]\r\n\r\nSLiRP Ready ...", unit, device?device:"(socket)", buff2, ttyp->baud); #else snprintf(buff, sizeof(buff), "1 Attached as unit %d, device %s\r\n\r\n[talking %s]\r\n\r\nSLiRP Ready ...", unit, device, buff2); #endif write(fd, buff, strlen(buff)+1); if (!slirp_socket_passwd) { close(fd); } ttyp->pid = pid; if (slirp_socket_passwd) { /* Internet socket, don't close fd */ ttyp->fd = fd; } } else { sprintf(buff, "0 %s", strerror(errno)); write(fd, buff, strlen(buff)+1); slirp_socket_wait = curtime; close(fd); goto failed; } } else if (sscanf(buff, "kill %[^:]:%d", device, &unit) == 2) { if (slirp_socket_passwd) { if (strcmp(slirp_socket_passwd, device) != 0) { slirp_socket_wait = curtime; close(fd); goto failed; } } for (ttyp = ttys; ttyp; ttyp = ttyp->next) { if (ttyp->unit == unit) { tty_detached(ttyp, 0); continue; } } close(fd); } else { /* Ooops, close the socket and don't accept * another connection for 10 seconds */ slirp_socket_wait = curtime; close(fd); } } failed: /* * Check if a tty is ready for reading [or writing] */ for (ttyp = ttys; ttyp; ttyp = ttyp2) { ttyp2 = ttyp->next; /* Just in case if_input removes it from under us */ DEBUG_ARG("hunting ttyp=%lx", (long) ttyp); if (FD_ISSET(ttyp->fd, &readfds)) if_input(ttyp); #ifdef FULL_BOLT if (FD_ISSET(ttyp->fd, &writefds)) if_start(ttyp); #endif /* ttyp may not be valid here, if_input() may have had it deleted... */ } /* * Check sockets */ if (link_up) { /* * Check TCP sockets */ for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; /* * FD_ISSET is meaningless on these sockets * (and they can crash the program) */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; /* * Check for URG data * This will soread as well, so no need to * test for readfds below if this succeeds */ if (FD_ISSET(so->s, &xfds)) sorecvoob(so); /* * Check sockets for reading */ else if (FD_ISSET(so->s, &readfds)) { /* * Check for incoming connections */ if (so->so_state & SS_FACCEPTCONN) { tcp_connect(so); continue; } /* else */ ret = soread(so); /* Output it if we read something */ if (ret > 0) tcp_output(sototcpcb(so)); } /* * Check sockets for writing */ if (FD_ISSET(so->s,&writefds)) { /* * Check for non-blocking, still-connecting sockets */ if (so->so_state & SS_ISFCONNECTING) { /* Connected */ so->so_state &= ~SS_ISFCONNECTING; ret = write(so->s, &ret, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* else failed */ so->so_state = SS_NOFDREF; } /* else so->so_state &= ~SS_ISFCONNECTING; */ /* * Continue tcp_input */ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); /* continue; */ } else ret = sowrite(so); /* * XXXXX If we wrote something (a lot), there * could be a need for a window update. * In the worst case, the remote will send * a window probe to get things going again */ } /* * Probe a still-connecting, non-blocking socket * to check if it's still alive */ #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { ret = read(so->s, (char *)&ret, 0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* Still connecting, continue */ /* else failed */ so->so_state = SS_NOFDREF; /* tcp_input will take care of it */ } else { ret = write(so->s, &ret, 0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* else failed */ so->so_state = SS_NOFDREF; } else so->so_state &= ~SS_ISFCONNECTING; } tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); } /* SS_ISFCONNECTING */ #endif } /* * Now UDP sockets. * Incoming packets are sent straight away, they're not buffered. * Incoming UDP data isn't buffered either. */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; if (so->s != -1 && FD_ISSET(so->s,&readfds)) sorecvfrom(so); } } #ifndef FULL_BOLT /* * See if we can start outputting */ if (if_queued && link_up) if_start(); #endif } /* while(1) { */ } void do_wait(n) int n; { int stat; #ifndef WNOHANG /* XXXXX YUCK! but it's the only solution I was given for OSF/1 */ #define WNOHANG 0x1 #endif while (waitpid((pid_t)-1, &stat, WNOHANG) > 0) ; /* do nothing */ signal(SIGCHLD, do_wait); } /* * curtime kept to an accuracy of 1ms */ void updtime() { #ifndef FULL_BOLT u_int inc; struct ttys *ttyp; static u_int towrite_lastime; #endif gettimeofday(&tt, 0); curtime = (u_int)tt.tv_sec * (u_int)1000; curtime += (u_int)tt.tv_usec / (u_int)1000; if ((tt.tv_usec % 1000) >= 500) curtime++; #ifndef FULL_BOLT /* * Update towrite on if either * a) all modems have towrite < 0; or * b) it's been 1 second since the last time it was updated * The reson is that if there's lots of UDP packets for example, * and the user uses an unusually high baudrate (as most do), * each call to updtime() will completely restore the tty's towrite * hence the next packet will go over the same modem again * (this won't happen with TCP because it sends data in 4k chunks, * so updtime() won't be called in between each packet) */ if ((curtime - towrite_lastime) < 1000) { for (ttyp = ttys; ttyp; ttyp = ttyp->next) { if (ttyp->towrite >= 0) return; } } /* Update all towrite's */ towrite_lastime = curtime; for (ttyp = ttys; ttyp; ttyp = ttyp->next) { inc = (((curtime - ttyp->lastime) * ttyp->bytesps) / 1000); if (inc > 0) { ttyp->lastime = curtime; ttyp->towrite += inc; if (ttyp->towrite > towrite_max) ttyp->towrite = towrite_max; } } #endif } void slirp_hup(num) int num; { ctty_closed = 1; signal(SIGHUP, SIG_IGN); /* XXX */ } slirp-1.0.17/src/main.h0000644000175000017500000000244010433144606013672 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define TRUE 1 #define FALSE 0 #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #define TOWRITEMAX 512 #define min(x,y) ((x) < (y) ? (x) : (y)) extern struct timeval tt; extern int link_up; extern int slirp_socket; extern int slirp_socket_unit; extern int slirp_socket_port; extern u_int32_t slirp_socket_addr; extern char *slirp_socket_passwd; extern int ctty_closed; /* * Get the difference in 2 times from updtim() * Allow for wraparound times, "just in case" * x is the greater of the 2 (current time) and y is * what it's being compared against. */ #define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) extern char *slirp_tty; extern char *exec_shell; extern u_int curtime; extern fd_set readfds, writefds, xfds; extern struct in_addr ctl_addr; extern struct in_addr special_addr; extern struct in_addr our_addr; extern struct in_addr loopback_addr; extern struct in_addr dns_addr, dns2_addr; extern char *username; extern char *socket_path; extern int towrite_max; extern int ppp_exit; extern int so_options; extern int tcp_keepintvl; #define PROTO_SLIP 0x1 #ifdef USE_PPP #define PROTO_PPP 0x2 #endif slirp-1.0.17/src/main.p0000644000175000017500000000031110433172427013677 0ustar roverroverint main _P((int, char **)); void tty_init _P((int, char **)); void main_init _P((int, char **)); void main_loop _P((void)); void do_wait _P((int)); void updtime _P((void)); void slirp_hup _P((int)); slirp-1.0.17/src/mbuf.c0000644000175000017500000001120110433144606013665 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ /* * mbuf's in SLiRP are much simpler than the real mbufs in * FreeBSD. They are fixed size, determined by the MTU, * so that one whole packet can fit. Mbuf's cannot be * chained together. If there's more data than the mbuf * could hold, an external malloced buffer is pointed to * by m_ext (and the data pointers) and M_EXT is set in * the flags */ #include struct mbuf *mbutl; char *mclrefcnt; int mbuf_alloced = 0; struct mbuf m_freelist, m_usedlist; int mbuf_thresh = 30; int mbuf_max = 0; int msize; void m_init() { m_freelist.m_next = m_freelist.m_prev = &m_freelist; m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; msize_init(); } void msize_init() { /* * Find a nice value for msize * XXX if_maxlinkhdr already in mtu */ msize = (if_mtu>if_mru?if_mtu:if_mru) + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; } /* * Get an mbuf from the free list, if there are none * malloc one * * Because fragmentation can occur if we alloc new mbufs and * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, * which tells m_free to actually free() it */ struct mbuf * m_get() { register struct mbuf *m; int flags = 0; DEBUG_CALL("m_get"); if (m_freelist.m_next == &m_freelist) { m = (struct mbuf *)malloc(msize); if (m == NULL) goto end_error; mbuf_alloced++; if (mbuf_alloced > mbuf_thresh) flags = M_DOFREE; if (mbuf_alloced > mbuf_max) mbuf_max = mbuf_alloced; } else { m = m_freelist.m_next; remque(m); } /* Insert it in the used list */ insque(m,&m_usedlist); m->m_flags = (flags | M_USEDLIST); /* Initialise it */ m->m_size = msize - sizeof(struct m_hdr); m->m_data = m->m_dat; m->m_len = 0; m->m_nextpkt = 0; m->m_prevpkt = 0; end_error: DEBUG_ARG("m = %lx", (long )m); return m; } void m_free(m) struct mbuf *m; { DEBUG_CALL("m_free"); DEBUG_ARG("m = %lx", (long )m); if(m) { /* Remove from m_usedlist */ if (m->m_flags & M_USEDLIST) remque(m); /* If it's M_EXT, free() it */ if (m->m_flags & M_EXT) free(m->m_ext); /* * Either free() it or put it on the free list */ if (m->m_flags & M_DOFREE) { free(m); mbuf_alloced--; } else if ((m->m_flags & M_FREELIST) == 0) { insque(m,&m_freelist); m->m_flags = M_FREELIST; /* Clobber other flags */ } } /* if(m) */ } /* * Copy data from one mbuf to the end of * the other.. if result is too big for one mbuf, malloc() * an M_EXT data segment */ void m_cat(m, n) register struct mbuf *m, *n; { /* * If there's no room, realloc */ if (M_FREEROOM(m) < n->m_len) m_inc(m,m->m_size+MINCSIZE); memcpy(m->m_data+m->m_len, n->m_data, n->m_len); m->m_len += n->m_len; m_free(n); } /* make m size bytes large */ void m_inc(m, size) struct mbuf *m; int size; { int datasize; /* some compiles throw up on gotos. This one we can fake. */ if(m->m_size>size) return; if (m->m_flags & M_EXT) { datasize = m->m_data - m->m_ext; m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; */ m->m_data = m->m_ext + datasize; } else { char *dat; datasize = m->m_data - m->m_dat; dat = (char *)malloc(size); /* if (dat == NULL) * return (struct mbuf *)NULL; */ memcpy(dat, m->m_dat, m->m_size); m->m_ext = dat; m->m_data = m->m_ext + datasize; m->m_flags |= M_EXT; } m->m_size = size; } void m_adj(m, len) struct mbuf *m; int len; { if (m == NULL) return; if (len >= 0) { /* Trim from head */ m->m_data += len; m->m_len -= len; } else { /* Trim from tail */ len = -len; m->m_len -= len; } } /* * Copy len bytes from m, starting off bytes into n */ int m_copy(n, m, off, len) struct mbuf *n, *m; int off, len; { if (len > M_FREEROOM(n)) return -1; memcpy((n->m_data + n->m_len), (m->m_data + off), len); n->m_len += len; return 0; } /* * Given a pointer into an mbuf, return the mbuf * XXX This is a kludge, I should eliminate the need for it * Fortunately, it's not used often */ struct mbuf * dtom(dat) void *dat; { struct mbuf *m; DEBUG_CALL("dtom"); DEBUG_ARG("dat = %lx", (long )dat); /* bug corrected for M_EXT buffers */ for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { if (m->m_flags & M_EXT) { if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) return m; } else { if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) return m; } } DEBUG_ERROR((dfd, "dtom failed")); return (struct mbuf *)0; } slirp-1.0.17/src/mbuf.h0000644000175000017500000001104610115276015013676 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1993 * 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. * * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp */ #ifndef _MBUF_H_ #define _MBUF_H_ #define m_freem m_free #define MINCSIZE 4096 /* Amount to increase mbuf if too small */ /* * Macros for type conversion * mtod(m,t) - convert mbuf pointer to data pointer of correct type * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) */ #define mtod(m,t) ((t)(m)->m_data) /* #define dtom(x) ((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */ /* XXX About mbufs for slirp: * Only one mbuf is ever used in a chain, for each "cell" of data. * m_nextpkt points to the next packet, if fragmented. * If the data is too large, the M_EXT is used, and a larger block * is alloced. Therefore, m_free[m] must check for M_EXT and if set * free the m_ext. This is inefficient memory-wise, but who cares. */ /* XXX should union some of these! */ /* header at beginning of each mbuf: */ struct m_hdr { struct mbuf *mh_next; /* Linked list of mbufs */ struct mbuf *mh_prev; struct mbuf *mh_nextpkt; /* Next packet in queue/record */ struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */ int mh_flags; /* Misc flags */ int mh_size; /* Size of data */ struct socket *mh_so; caddr_t mh_data; /* Location of data */ int mh_len; /* Amount of data in this mbuf */ }; /* * How much room is in the mbuf, from m_data to the end of the mbuf */ #define M_ROOM(m) ((m->m_flags & M_EXT)? \ (((m)->m_ext + (m)->m_size) - (m)->m_data) \ : \ (((m)->m_dat + (m)->m_size) - (m)->m_data)) /* * How much free room there is */ #define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) #define M_TRAILINGSPACE M_FREEROOM struct mbuf { struct m_hdr m_hdr; union M_dat { char m_dat_[1]; /* ANSI don't like 0 sized arrays */ char *m_ext_; } M_dat; }; #define m_next m_hdr.mh_next #define m_prev m_hdr.mh_prev #define m_nextpkt m_hdr.mh_nextpkt #define m_prevpkt m_hdr.mh_prevpkt #define m_flags m_hdr.mh_flags #define m_len m_hdr.mh_len #define m_data m_hdr.mh_data #define m_size m_hdr.mh_size #define m_dat M_dat.m_dat_ #define m_ext M_dat.m_ext_ #define m_so m_hdr.mh_so #define ifq_prev m_prev #define ifq_next m_next #define ifs_prev m_prevpkt #define ifs_next m_nextpkt #define ifq_so m_so #define M_EXT 0x01 /* m_ext points to more (malloced) data */ #define M_FREELIST 0x02 /* mbuf is on free list */ #define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ #define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() * it rather than putting it on the free list */ /* * Mbuf statistics. XXX */ struct mbstat { int mbs_alloced; /* Number of mbufs allocated */ }; extern struct mbstat mbstat; extern int mbuf_alloced; extern struct mbuf m_freelist, m_usedlist; extern mbuf_max; #endif slirp-1.0.17/src/mbuf.p0000644000175000017500000000053210115325663013710 0ustar roverrovervoid m_init _P((void)); void msize_init _P((void)); struct mbuf * m_get _P((void)); void m_free _P((struct mbuf *)); void m_cat _P((register struct mbuf *, register struct mbuf *)); void m_inc _P((struct mbuf *, int)); void m_adj _P((struct mbuf *, int)); int m_copy _P((struct mbuf *, struct mbuf *, int, int)); struct mbuf * dtom _P((void *)); slirp-1.0.17/src/memcmp.c0000644000175000017500000000023410115276013014211 0ustar roverrover int memcmp(a, b, len) char *a; char *b; int len; { int n = 0; while (n < len) { if (a[n] != b[n]) return a[n] - b[n]; n++; } return 0; } slirp-1.0.17/src/misc.c0000644000175000017500000005016710117213336013701 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include #include u_int curtime, time_fasttimo, last_slowtimo, detach_time; u_int detach_wait = 600000; /* 10 minutes */ int x_port = -1; int x_display = 0; int x_screen = 0; int show_x(buff, inso) char *buff; struct socket *inso; { if (x_port < 0) { lprint("X Redir: X not being redirected.\r\n"); } else { lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", inet_ntoa(our_addr), x_port, x_screen); lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", inet_ntoa(our_addr), x_port, x_screen); if (x_display) lprint("X Redir: Redirecting to display %d\r\n", x_display); } return CFG_OK; } /* * XXX Allow more than one X redirection? */ void redir_x(inaddr, start_port, display, screen) u_int32_t inaddr; int start_port; int display; int screen; { int i; if (x_port >= 0) { lprint("X Redir: X already being redirected.\r\n"); show_x(0, 0); } else { for (i = 6001 + (start_port-1); i <= 6100; i++) { if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { /* Success */ x_port = i - 6000; x_display = display; x_screen = screen; show_x(0, 0); return; } } lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); } } #ifndef HAVE_INET_ATON int inet_aton(cp, ia) const char *cp; struct in_addr *ia; { u_int32_t addr = inet_addr(cp); if (addr == 0xffffffff) return 0; ia->s_addr = addr; return 1; } #endif /* * Get our IP address and put it in our_addr */ void getouraddr() { char buff[256]; struct hostent *he; if (gethostname(buff,256) < 0) return; if ((he = gethostbyname(buff)) == NULL) return; our_addr = *(struct in_addr *)he->h_addr; } #if SIZEOF_CHAR_P == 8 struct quehead_32 { u_int32_t qh_link; u_int32_t qh_rlink; }; inline void insque_32(a, b) void *a; void *b; { register struct quehead_32 *element = (struct quehead_32 *) a; register struct quehead_32 *head = (struct quehead_32 *) b; element->qh_link = head->qh_link; head->qh_link = (u_int32_t)element; element->qh_rlink = (u_int32_t)head; ((struct quehead_32 *)(element->qh_link))->qh_rlink = (u_int32_t)element; } inline void remque_32(a) void *a; { register struct quehead_32 *element = (struct quehead_32 *) a; ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; element->qh_rlink = 0; } #endif /* SIZEOF_CHAR_P == 8 */ struct quehead { struct quehead *qh_link; struct quehead *qh_rlink; }; inline void insque(a, b) void *a, *b; { register struct quehead *element = (struct quehead *) a; register struct quehead *head = (struct quehead *) b; element->qh_link = head->qh_link; head->qh_link = (struct quehead *)element; element->qh_rlink = (struct quehead *)head; ((struct quehead *)(element->qh_link))->qh_rlink = (struct quehead *)element; } inline void remque(a) void *a; { register struct quehead *element = (struct quehead *) a; ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; element->qh_rlink = NULL; /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ } /* #endif */ int add_exec(ex_ptr, do_pty, exec, addr, port) struct ex_list **ex_ptr; int do_pty; char *exec; int addr; int port; { struct ex_list *tmp_ptr; /* First, check if the port is "bound" */ for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) return -1; } tmp_ptr = *ex_ptr; *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); (*ex_ptr)->ex_fport = port; (*ex_ptr)->ex_addr = addr; (*ex_ptr)->ex_pty = do_pty; (*ex_ptr)->ex_exec = strdup(exec); (*ex_ptr)->ex_next = tmp_ptr; return 0; } #ifndef HAVE_STRERROR /* * For systems with no strerror */ extern int sys_nerr; extern char *sys_errlist[]; char * strerror(error) int error; { if (error < sys_nerr) return sys_errlist[error]; else return "Unknown error."; } #endif int openpty(amaster, aslave) int *amaster, *aslave; { register int master, slave; #ifdef HAVE_GRANTPT char *ptr; if ((master = open("/dev/ptmx", O_RDWR)) < 0 || grantpt(master) < 0 || unlockpt(master) < 0 || (ptr = ptsname(master)) == NULL) { close(master); return -1; } if ((slave = open(ptr, O_RDWR)) < 0 #ifdef I_PUSH || ioctl(slave, I_PUSH, "ptem") < 0 || ioctl(slave, I_PUSH, "ldterm") < 0 || ioctl(slave, I_PUSH, "ttcompat") < 0 #endif ) { close(master); close(slave); return -1; } *amaster = master; *aslave = slave; return 0; #else static char line[] = "/dev/ptyXX"; register const char *cp1, *cp2; for (cp1 = "pqrsPQRS"; *cp1; cp1++) { line[8] = *cp1; for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { line[9] = *cp2; if ((master = open(line, O_RDWR, 0)) == -1) { if (errno == ENOENT) return (-1); /* out of ptys */ } else { line[5] = 't'; /* These will fail */ (void) chown(line, getuid(), 0); (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); #ifdef HAVE_REVOKE (void) revoke(line); #endif if ((slave = open(line, O_RDWR, 0)) != -1) { *amaster = master; *aslave = slave; return 0; } (void) close(master); line[5] = 'p'; } } } errno = ENOENT; /* out of ptys */ return (-1); #endif } /* * XXX This is ugly * We create and bind a socket, then fork off to another * process, which connects to this socket, after which we * exec the wanted program. If something (strange) happens, * the accept() call could block us forever. * * do_pty = 0 Fork/exec inetd style * do_pty = 1 Fork/exec using slirp.telnetd * do_ptr = 2 Fork/exec using pty */ int fork_exec(so, ex, do_pty) struct socket *so; char *ex; int do_pty; { int s; struct sockaddr_in addr; int addrlen = sizeof(addr); int opt; int master; char *argv[256]; char buff[256]; /* don't want to clobber the original */ char *bptr; char *curarg; int c, i; DEBUG_CALL("fork_exec"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ex = %lx", (long)ex); DEBUG_ARG("do_pty = %lx", (long)do_pty); if (do_pty == 2) { if (openpty(&master, &s) == -1) { lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } } else { addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); close(s); return 0; } } switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); close(s); if (do_pty == 2) close(master); return 0; case 0: /* Set the DISPLAY */ if (do_pty == 2) { (void) close(master); #ifdef TIOCSCTTY /* XXXXX */ (void) setsid(); ioctl(s, TIOCSCTTY, (char *)NULL); #endif } else { getsockname(s, (struct sockaddr *)&addr, &addrlen); close(s); /* * Connect to the socket * XXX If any of these fail, we're in trouble! */ s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_addr = loopback_addr; connect(s, (struct sockaddr *)&addr, addrlen); } if (x_port >= 0) { #ifdef HAVE_SETENV snprintf(buff, sizeof(buff), "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else snprintf(buff, sizeof(buff), "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } dup2(s, 0); dup2(s, 1); dup2(s, 2); for (s = 3; s <= 255; s++) close(s); i = 0; bptr = strdup(ex); /* No need to free() this */ if (do_pty == 1) { /* Setup "slirp.telnetd -x" */ argv[i++] = "slirp.telnetd"; argv[i++] = "-x"; argv[i++] = bptr; } else do { /* Change the string into argv[] */ curarg = bptr; while (*bptr != ' ' && *bptr != (char)0) bptr++; c = *bptr; *bptr++ = (char)0; argv[i++] = strdup(curarg); } while (c); argv[i] = 0; /* SECURITY TODO: is this safe? see execlp comment below. */ execvp(argv[0], argv); /* Ooops, failed, let's tell the user why */ { char buff[256]; sprintf(buff, "Error: execvp of %s failed: %s\n", argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } close(0); close(1); close(2); /* XXX */ exit(1); default: if (do_pty == 2) { close(s); so->s = master; } else { /* * XXX this could block us... * XXX Should set a timer here, and if accept() doesn't * return after X seconds, declare it a failure * The only reason this will block forever is if socket() * of connect() fail in the child process */ so->s = accept(s, (struct sockaddr *)&addr, &addrlen); close(s); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); } fd_nonblock(so->s); /* Append the telnet options now */ if (so->so_m != 0 && do_pty == 1) { sbappend(so, so->so_m); so->so_m = 0; } return 1; } } #ifndef HAVE_STRDUP char * strdup(str) const char *str; { char *bptr; bptr = (char *)malloc(strlen(str)+1); strcpy(bptr, str); return bptr; } #endif void snooze_hup(num) int num; { int s, ret; #ifndef NO_UNIX_SOCKETS struct sockaddr_un sock_un; #endif struct sockaddr_in sock_in; char buff[256]; ret = -1; if (slirp_socket_passwd) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) slirp_exit(1); sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = slirp_socket_addr; sock_in.sin_port = htons(slirp_socket_port); if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) slirp_exit(1); /* just exit...*/ snprintf(buff, sizeof(buff), "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); write(s, buff, strlen(buff)+1); } #ifndef NO_UNIX_SOCKETS else { s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) slirp_exit(1); sock_un.sun_family = AF_UNIX; strncpy2(sock_un.sun_path, socket_path, sizeof(sock_un.sun_path)); if (connect(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) slirp_exit(1); sprintf(buff, "kill none:%d", slirp_socket_unit); write(s, buff, strlen(buff)+1); } #endif slirp_exit(0); } void snooze() { sigset_t s; int i; extern int dostats; /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ /* Close all fd's */ for (i = 255; i >= 0; i--) close(i); /* in -l x (attached) mode, we are snoozing and will have no stats, so just exit */ dostats=0; signal(SIGQUIT, slirp_exit); signal(SIGHUP, snooze_hup); sigemptyset(&s); /* Wait for any signal */ sigsuspend(&s); /* Just in case ... */ exit(255); } void relay(s) int s; { char buf[8192]; int n; fd_set readfds; struct ttys *ttyp; /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ signal(SIGQUIT, slirp_exit); signal(SIGHUP, slirp_exit); signal(SIGINT, slirp_exit); signal(SIGTERM, slirp_exit); /* Fudge to get term_raw and term_restore to work */ if (NULL == (ttyp = tty_attach (0, slirp_tty))) { lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); slirp_exit (1); } ttyp->fd = 0; ttyp->flags |= TTY_CTTY; term_raw(ttyp); while (1) { FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(s, &readfds); n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if (n <= 0) slirp_exit(0); if (FD_ISSET(0, &readfds)) { n = read(0, buf, 8192); if (n <= 0) slirp_exit(0); n = writen(s, buf, n); if (n <= 0) slirp_exit(0); } if (FD_ISSET(s, &readfds)) { n = read(s, buf, 8192); if (n <= 0) slirp_exit(0); n = writen(0, buf, n); if (n <= 0) slirp_exit(0); } } /* Just in case.... */ exit(1); } int (*lprint_print) _P((void *, const char *, va_list)); char *lprint_ptr, *lprint_ptr2, **lprint_arg; void #ifdef __STDC__ lprint(const char *format, ...) #else lprint(va_alist) va_dcl #endif { va_list args; #ifdef __STDC__ va_start(args, format); #else char *format; va_start(args); format = va_arg(args, char *); #endif /* If we're printing to an sbuf, make sure there's enough room */ /* XXX +100? */ if (lprint_sb) { if ((lprint_ptr - lprint_sb->sb_wptr) >= (lprint_sb->sb_datalen - (strlen(format) + 100))) { int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; int deltap = lprint_ptr - lprint_sb->sb_data; lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, lprint_sb->sb_datalen + TCP_SNDSPACE); /* Adjust all values */ lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; lprint_ptr = lprint_sb->sb_data + deltap; lprint_sb->sb_datalen += TCP_SNDSPACE; } } if (lprint_print) lprint_ptr += (*lprint_print)(*lprint_arg, format, args); /* Check if they want output to be logged to file as well */ if (lfd) { /* * Remove \r's * otherwise you'll get ^M all over the file */ int len = strlen(format); char *bptr1, *bptr2; bptr1 = bptr2 = strdup(format); while (len--) { if (*bptr1 == '\r') memcpy(bptr1, bptr1+1, len+1); else bptr1++; } vfprintf(lfd, bptr2, args); free(bptr2); } va_end(args); } void add_emu(buff) char *buff; { u_int lport, fport; u_int8_t tos = 0, emu = 0; char buff1[256], buff2[256], buff4[128]; char *buff3 = buff4; struct emu_t *emup; struct socket *so; if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { lprint("Error: Bad arguments\r\n"); return; } if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { lport = 0; if (sscanf(buff1, "%d", &fport) != 1) { lprint("Error: Bad first argument\r\n"); return; } } if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { buff3 = 0; if (sscanf(buff2, "%256s", buff1) != 1) { lprint("Error: Bad second argument\r\n"); return; } } if (buff3) { if (strcmp(buff3, "lowdelay") == 0) tos = IPTOS_LOWDELAY; else if (strcmp(buff3, "throughput") == 0) tos = IPTOS_THROUGHPUT; else { lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); return; } } if (strcmp(buff1, "ftp") == 0) emu = EMU_FTP; else if (strcmp(buff1, "irc") == 0) emu = EMU_IRC; else if (strcmp(buff1, "none") == 0) emu = EMU_NONE; /* ie: no emulation */ else { lprint("Error: Unknown service\r\n"); return; } /* First, check that it isn't already emulated */ for (emup = tcpemu; emup; emup = emup->next) { if (emup->lport == lport && emup->fport == fport) { lprint("Error: port already emulated\r\n"); return; } } /* link it */ emup = (struct emu_t *)malloc(sizeof (struct emu_t)); emup->lport = (u_int16_t)lport; emup->fport = (u_int16_t)fport; emup->tos = tos; emup->emu = emu; emup->next = tcpemu; tcpemu = emup; /* And finally, mark all current sessions, if any, as being emulated */ for (so = tcb.so_next; so != &tcb; so = so->so_next) { if ((lport && lport == ntohs(so->so_lport)) || (fport && fport == ntohs(so->so_fport))) { if (emu) so->so_emu = emu; if (tos) so->so_iptos = tos; } } lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); } #ifdef BAD_SPRINTF #undef vsprintf #undef sprintf /* * Some BSD-derived systems have a sprintf which returns char * */ int vsprintf_len(string, format, args) char *string; const char *format; va_list args; { vsprintf(string, format, args); return strlen(string); } int #ifdef __STDC__ sprintf_len(char *string, const char *format, ...) #else sprintf_len(va_alist) va_dcl #endif { va_list args; #ifdef __STDC__ va_start(args, format); #else char *string; char *format; va_start(args); string = va_arg(args, char *); format = va_arg(args, char *); #endif vsprintf(string, format, args); return strlen(string); } #endif void u_sleep(usec) int usec; { struct timeval t; fd_set fdset; FD_ZERO(&fdset); t.tv_sec = 0; t.tv_usec = usec * 1000; select(0, &fdset, &fdset, &fdset, &t); } /* * Set fd blocking and non-blocking */ void fd_nonblock(fd) int fd; { #ifdef FIONBIO int opt = 1; ioctl(fd, FIONBIO, &opt); #else int opt; opt = fcntl(fd, F_GETFL, 0); opt |= O_NONBLOCK; fcntl(fd, F_SETFL, opt); #endif } void fd_block(fd) int fd; { #ifdef FIONBIO int opt = 0; ioctl(fd, FIONBIO, &opt); #else int opt; opt = fcntl(fd, F_GETFL, 0); opt &= ~O_NONBLOCK; fcntl(fd, F_SETFL, opt); #endif } /* * invoke RSH */ int rsh_exec(so,ns, user, host, args) struct socket *so; struct socket *ns; char *user; char *host; char *args; { int fd[2]; int fd0[2]; int s; char buff[256]; DEBUG_CALL("rsh_exec"); DEBUG_ARG("so = %lx", (long)so); if (pipe(fd)<0) { lprint("Error: pipe failed: %s\n", strerror(errno)); return 0; } /* #ifdef HAVE_SOCKETPAIR */ #if 1 if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { close(fd[0]); close(fd[1]); lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } #else if (openpty(&fd0[0], &fd0[1]) == -1) { close(fd[0]); close(fd[1]); lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } #endif switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); close(fd[0]); close(fd[1]); close(fd0[0]); close(fd0[1]); return 0; case 0: close(fd[0]); close(fd0[0]); /* Set the DISPLAY */ if (x_port >= 0) { #ifdef HAVE_SETENV snprintf(buff, sizeof(buff), "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else snprintf(buff, sizeof(buff), "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } dup2(fd0[1], 0); dup2(fd0[1], 1); dup2(fd[1], 2); for (s = 3; s <= 255; s++) close(s); /* SECURITY * TODO: This type of exec is very dangerous if this process is privileged in any way. * A user could escalate privileges by subverting the $PATH, and having an rsh * binary of their own making get executed. */ execlp("rsh","rsh","-l", user, host, args, NULL); /* Ooops, failed, let's tell the user why */ sprintf(buff, "Error: execlp of %s failed: %s\n", "rsh", strerror(errno)); write(2, buff, strlen(buff)+1); close(0); close(1); close(2); /* XXX */ exit(1); default: close(fd[1]); close(fd0[1]); ns->s=fd[0]; so->s=fd0[0]; return 1; } } /* strncpy2() Same as strncpy, except it always zero terminates and stops as soon as it hits the zero. Note: If max length is 0, it will write a 0. (Perhaps not correct, but terminated) Thanks to apache for the idea. */ char * strncpy2(dest, src, length) char * dest; char * src; size_t length; { char *ptr=dest; assert(dest != NULL); assert(src != NULL); if(!length) length=1; /* Always puts in terminating 0 */ while( --length && *src) *ptr++=*src++; *ptr='\0'; return dest; } /* Join 2 strings together using a malloc'ed memory block Skips strings if they are null. */ char * strjoin(s1, s2) char * s1; char *s2; { char * ptr; size_t len1; len1 = 0; if(s1) len1 += strlen(s1); if(s2) len1 += strlen(s2); len1++; /* Terminating null */ ptr = malloc(len1); if(!ptr) return ptr; *ptr = '\0'; if(s1) strcpy(ptr, s1); if(s2) strcat(ptr, s2); return ptr; } slirp-1.0.17/src/misc.h0000644000175000017500000000257410115276015013706 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _MISC_H_ #define _MISC_H_ struct ex_list { int ex_pty; /* Do we want a pty? */ int ex_addr; /* The last byte of the address */ int ex_fport; /* Port to telnet to */ char *ex_exec; /* Command line of what to exec */ struct ex_list *ex_next; }; extern struct ex_list *exec_list; extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; extern int (*lprint_print) _P((void *, const char *, va_list)); extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; extern struct sbuf *lprint_sb; #ifndef HAVE_STRDUP char *strdup _P((const char *)); #endif void do_wait _P((int)); #define EMU_NONE 0x0 /* TCP emulations */ #define EMU_CTL 0x1 #define EMU_FTP 0x2 #define EMU_KSH 0x3 #define EMU_IRC 0x4 #define EMU_REALAUDIO 0x5 #define EMU_RLOGIN 0x6 #define EMU_IDENT 0x7 #define EMU_RSH 0x8 #define EMU_NOCONNECT 0x10 /* Don't connect */ /* UDP emulations */ #define EMU_TALK 0x1 #define EMU_NTALK 0x2 #define EMU_CUSEEME 0x3 struct tos_t { u_int16_t lport; u_int16_t fport; u_int8_t tos; u_int8_t emu; }; struct emu_t { u_int16_t lport; u_int16_t fport; u_int8_t tos; u_int8_t emu; struct emu_t *next; }; extern struct emu_t *tcpemu; extern int x_port, x_server, x_display; #endif slirp-1.0.17/src/misc.p0000644000175000017500000000127610117224466013721 0ustar roverroverint show_x _P((char *, struct socket *)); void redir_x _P((u_int32_t, int, int, int)); void getouraddr _P((void)); inline void slirp_insque _P((void *, void *)); inline void slirp_remque _P((void *)); int add_exec _P((struct ex_list **, int, char *, int, int)); int openpty _P((int *, int *)); int fork_exec _P((struct socket *, char *, int)); void snooze_hup _P((int)); void snooze _P((void)); void relay _P((int)); void add_emu _P((char *)); void u_sleep _P((int)); void fd_nonblock _P((int)); void fd_block _P((int)); int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *)); char * strncpy2 _P((char *, char *, size_t)); char * strjoin _P((char *, char *)); slirp-1.0.17/src/mkpro0000755000175000017500000000452710115316533013660 0ustar roverrover#!/usr/bin/perl # # Copyright (c) 1995, Danny Gasparovski # # Please read the file COPYRIGHT for the # terms and conditions of the copyright. # # Print out prototypes from C source. # # My first perl script! *proud* :) # # Function declaration must be of the form: # type # func(arglist) # argdec; # { # or: # type func(arglist) # argdec; # { # (former preferred), argdec must be in order of arglist, # and you must not use "func(void)" when no arguments are # expected, use "func()" instead. # If you don't want a particular function to be prototyped, # put it in %ignore_funcs # # Needs perl v5, v4 doesn't seem to like the STATE0: label # ("?:" can be removed though) $] < 5.000 && die("Sorry, needs version 5.000 or greater.\n"); $state = 0; $nargs = 0; $nargs_guess = -1; $ignore = 0; %ignore_funcs = ('if_start', 1); WHILE: while(<>) { $lines++; # Ignore blank lines (/^[ \t]*$/) && next WHILE; # C comments and pre-processor directives are already removed if (/^{$/) { # Done, @line may hold the full prototype if ($nargs_guess == $nargs) { print @line[0..$state-1]; print "void" if ($state == 2); print "));\n"; } $nargs_guess = -1; $state = 0; } elsif ($state == 0) { # State 0: Try and get the function type STATE0: if (/([a-zA-Z0-9_\* \t]+)/) { $line[0] = "$1 "; } else { # Maybe function type is on the same line as function $line[0] = ""; } $nargs_guess = -1; $state = 1; } elsif ($state == 1) { # State 1: We think we have the function type, # try and find a function /^(.*)\((.*)\)[ \t]*$/ || goto STATE0; if ($ignore_funcs{$1}) { goto STATE0; } $line[1] = "$1 _P(("; $nargs_guess = split(/,/, $2); $nargs = 0; $state = 2; } else { # State >= 2: We think we have both function type and the # actual function, try and find the argument types # From here on we use $state as an index into @line $line[$state++] = ", " if ($state != 2); /^[ \t]*([^,;]+)[ \t]+[^,; \t]+[,;](?:[ \t]*$|.*;)/ || goto STATE0; $1 =~ /([^\*]+)/; # Remove "*" $type = $1; $n = split(/,/); $nargs += $n; goto STATE0 if ($nargs > $nargs_guess); # Extract multiple args of the form: # int *arg1, arg2, *arg3; $i = 0; while($n--) { $line[$state++] = "$type"; $line[$state++] = " $1" if ($_[$i++] =~ /(\*+)/); $line[$state++] = ", " if ($n); } } } exit 1 if (!$lines); slirp-1.0.17/src/options.c0000644000175000017500000014122510117211712014431 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #ifdef USE_PPP #include "ppp/ppp.h" #include "ppp/pppd.h" #include "ppp/pathnames.h" #include "ppp/patchlevel.h" #include "ppp/fsm.h" #include "ppp/lcp.h" #include "ppp/ipcp.h" #include "ppp/upap.h" #include "ppp/chap.h" #include "ppp/ccp.h" #include "ppp/ppp-comp.h" #define FALSE 0 #define TRUE 1 #ifndef GIDSET_TYPE #define GIDSET_TYPE int #endif void readable _P((int fd)); /* * Option variables */ int debug = 0; /* Debug flag */ int kdebugflag = 0; /* Tell kernel to print debug messages */ int default_device = 1; /* Using /dev/tty or equivalent */ char devnam[MAXPATHLEN] = "/dev/tty"; /* Device name */ int crtscts = 0; /* Use hardware flow control */ int modem = 1; /* Use modem control lines */ int inspeed = 0; /* Input/Output speed requested */ u_int32_t netmask = 0; /* IP netmask to set on interface */ int lockflag = 0; /* Create lock file to lock the serial dev */ int nodetach = 0; /* Don't detach from controlling tty */ char *connector = NULL; /* Script to establish physical link */ char *disconnector = NULL; /* Script to disestablish physical link */ char user[MAXNAMELEN]; /* Username for PAP */ char passwd[MAXSECRETLEN]; /* Password for PAP */ int auth_required = 0; /* Peer is required to authenticate */ int defaultroute = 0; /* assign default route through interface */ int proxyarp = 0; /* Set up proxy ARP entry for peer */ int persist = 0; /* Reopen link after it goes down */ int uselogin = 0; /* Use /etc/passwd for checking PAP */ int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ int usehostname = 0; /* Use hostname for our_name */ int disable_defaultip = 0; /* Don't use hostname for default IP adrs */ char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ int cryptpap; /* Passwords in pap-secrets are encrypted */ #ifndef IMPLEMENTATION #define IMPLEMENTATION "" #endif #endif int nozeros; /* If set, 5 0's will not terminate link...*/ /* * Read the config file */ int (*lprint_print) _P((void *, const char *format, va_list)); char *lprint_ptr, *lprint_ptr2, **lprint_arg; struct sbuf *lprint_sb; int cfg_unit; int ctl_password_ok; char *ctl_password; void config(file, unit) char *file; int unit; { FILE *cfg; char buff[256]; cfg = fopen(file, "r"); if (cfg == NULL) return; cfg_unit = unit; lprint("Reading config file: %s\r\n", file); while(fgets(buff, 256, cfg) != NULL) do_config(buff, (struct socket *)0, PRN_STDERR); fclose(cfg); } int do_config(buff, inso, type) char *buff; struct socket *inso; int type; { int str_len, i = 0, is_sprintf = 0; switch (type) { case PRN_STDERR: lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; lprint_ptr2 = (char *)stderr; lprint_arg = (char **)&lprint_ptr2; break; case PRN_SPRINTF: lprint_print = (int (*) _P((void *, const char *, va_list)))vsprintf; lprint_sb = &inso->so_snd; lprint_ptr2 = lprint_sb->sb_wptr; lprint_ptr = lprint_sb->sb_wptr; lprint_arg = (char **)&lprint_ptr; is_sprintf = 1; break; default: return 0; } /* Remove any whitespace */ while (*buff == ' ' || *buff == '\t') buff++; /* Ignore if it's a comment, or it's an empty line */ if (*buff == '#' || *buff == '\r' || *buff == '\n' || *buff == 0) return 0; while (cfg[i].command) { if ((((str_len = strlen(cfg[i].command)) && !strncmp(buff, cfg[i].command, str_len)) || (cfg[i].command_line && (str_len = strlen(cfg[i].command_line)) && !strncmp(buff, cfg[i].command_line, str_len))) && (buff[str_len] == ' ' || buff[str_len] == '\t' || buff[str_len] == '\n' || buff[str_len] == '\r' || buff[str_len] == 0)) { while (buff[str_len] == ' ' || buff[str_len] == '\t') str_len++; if (buff[str_len] == '\n' || buff[str_len] == '\r') buff[str_len] = 0; if (cfg[i].type & type) { if ((cfg[i].flags & CFG_NEEDARG) && buff[str_len] == 0) { lprint("Error: Insufficient arguments to \"%s\".\r\n", buff); goto done; } if ((*cfg[i].func)((buff[str_len]?buff+str_len:(char *)0), inso) == CFG_BADARGS) lprint("Error: Usage: %s %s\r\n", cfg[i].command, cfg[i].usage_args); goto done; } else { lprint("Error: Option unavailable from %s.\r\n", (type == PRN_STDERR)?"config file/command line": "telnet"); goto done; } } i++; } /* Command failed */ lprint("Error: Bad command: %s", buff); if (inso) lprint("\r\n"); done: if (do_echo) lprint("\r"); if (is_sprintf) lprint_print = 0; if (lprint_sb) { i = lprint_ptr - lprint_sb->sb_wptr; lprint_sb = 0; return i; } else return 0; } int get_port(buff, proto_tcp) char *buff; int proto_tcp; { int x; struct servent *servp; if (!(x = atoi(buff))) { /* Must be a service */ servp = getservbyname(buff, proto_tcp==1?"tcp":"udp"); if (!servp) { lprint("Error: Unknown service: %s\r\n", buff); return -1; } x = ntohs(servp->s_port); } return x; } int cfg_redir_x(buff, inso) char *buff; struct socket *inso; { u_int32_t laddr = 0; int display = 0; int screen = 0; int start_port = 0; char *ptr = 0; if (buff) { if (strncmp(buff, "start", 5) == 0) { buff += 5; while (*buff == ' ' || *buff == '\t') buff++; start_port = strtol(buff, &ptr, 10); if (buff == ptr) return CFG_BADARGS; buff = ptr; while (*buff == ' ' || *buff == '\t') buff++; } if ((ptr = strchr(buff, ':'))) { *ptr++ = 0; if (*ptr == 0) return CFG_BADARGS; } if (buff[0]) { laddr = inet_addr(buff); if (laddr == 0xffffffff) { lprint("Error: bad address\r\n"); return CFG_ERROR; } } if (ptr) { if (strchr(ptr, '.')) { if (sscanf(ptr, "%d.%d", &display, &screen) != 2) return CFG_BADARGS; } else { if (sscanf(ptr, "%d", &display) != 1) return CFG_BADARGS; } } } if (!laddr) { if (inso) laddr = inso->so_laddr.s_addr; else laddr = inet_addr(CTL_LOCAL); } redir_x(laddr, start_port, display, screen); return CFG_OK; } int cfg_setunit(buff, inso) char *buff; struct socket *inso; { int x; x = atoi(buff); if (x < 0 || x >= MAX_INTERFACES) { lprint("Error: unit out of range\r\n"); return CFG_ERROR; } if (!ttys_unit[x]) { lprint("Error: no such unit\r\n"); return CFG_ERROR; } cfg_unit = x; lprint("Configuring unit %d\r\n", cfg_unit); return CFG_OK; } int cfg_redir(buff, inso) char *buff; struct socket *inso; { u_int32_t laddr; int port = 0, lport; char str[256]; char str2[256]; int once_time = 0, proto_tcp = -1; struct socket *so; if (strncmp(buff, "once", 4) == 0) { once_time = SS_FACCEPTONCE; proto_tcp = 1; buff += 4; } else if (strncmp(buff, "time", 4) == 0) { once_time = SS_FACCEPTONCE; proto_tcp = 0; buff += 4; } while (*buff == ' ' || *buff == '\t') buff++; if (strncmp(buff, "tcp", 3) == 0) { if (proto_tcp == 0) { lprint("Error: TCP redirections can't timeout (yet)\r\n"); return CFG_ERROR; } proto_tcp = 1; buff += 3; } else if (strncmp(buff, "udp", 3) == 0) { if (proto_tcp == 1) { lprint("Error: UDP redirections can't redirect only once (yet)\r\n"); return CFG_ERROR; } proto_tcp = 0; buff += 3; } while (*buff == ' ' || *buff == '\t') buff++; /* If we can't infer the protocol, assume tcp */ if (proto_tcp == -1) proto_tcp = 1; if (sscanf(buff, "%d%*[to \t]%256[^:]:%256s", &port, str, str2) == 3) { if ((laddr = inet_addr(str)) == -1) { lprint("Error: Bad address: %s\r\n", buff); return CFG_ERROR; } } else if (sscanf(buff, "%d%*[to \t]%256s", &port, str2) == 2) { if (inso) laddr = inso->so_laddr.s_addr; else laddr = inet_addr(CTL_LOCAL); } else if (sscanf(buff, "%256[^:]:%256s", str, str2) == 2) { if ((laddr = inet_addr(str)) == -1) { lprint("Error: Bad address: %s\r\n", buff); return CFG_ERROR; } } else if (sscanf(buff, "%256s", str2) == 1) { if (inso) laddr = inso->so_laddr.s_addr; else laddr = inet_addr(CTL_LOCAL); } else { return CFG_BADARGS; } lport = get_port(str2, proto_tcp); if (lport < 0) return CFG_ERROR; /* Do the redirection */ if (proto_tcp) { so = solisten(htons(port), laddr, htons(lport), once_time); if (so) lprint("Redirecting TCP port %d to %s:%d\r\n", ntohs(so->so_fport), inet_ntoa(so->so_laddr), lport); else lprint("Redirection failed: %s\r\n", strerror(errno)); } else { so = udp_listen(htons(port), laddr, htons(lport), once_time); if (so) lprint("Redirecting UDP port %d to %s:%d\r\n", ntohs(so->so_fport), inet_ntoa(so->so_laddr), lport); else lprint("Redirection failed: %s\r\n", strerror(errno)); } return CFG_OK; } #ifndef FULL_BOLT int cfg_baudrate(buff, inso) char *buff; struct socket *inso; { int x; struct ttys *ttyp = ttys_unit[cfg_unit]; if (!ttyp) { lprint("Error: Unit does not exist. Weird.\r\n"); return CFG_ERROR; } x = atoi(buff); if (x < 300) { lprint("Error: baudrate too low\r\n"); return CFG_ERROR; } ttyp->baud = x; ttyp->bytesps = ttyp->baud / 10; /* XXX */ lprint("Setting baudrate to %d\r\n", ttyp->baud); return CFG_OK; } #endif int cfg_wait(buff, inso) char *buff; struct socket *inso; { if (buff) { int x = atoi(buff); if (x < 0) { lprint("Error: wait value must be non-negative\r\n"); return CFG_ERROR; } if (x > 24*60) { lprint("Error: wait value too large (one day max)\r\n"); return CFG_ERROR; } detach_wait = x * 60 * 1000; } lprint("Wait time is %d minutes\r\n", detach_wait/1000/60); return CFG_OK; } int cfg_sp_addr(buff, inso) char *buff; struct socket *inso; { struct in_addr tmp_addr; if (!inet_aton(buff, &tmp_addr)) { lprint("Error: Bad special address: %s\r\n", buff); return CFG_ERROR; } special_addr = tmp_addr; lprint("Setting special address to %s\r\n", buff); return CFG_OK; } int cfg_ctl_addr(buff, inso) char *buff; struct socket *inso; { struct in_addr tmp_addr; if (!inet_aton(buff, &tmp_addr)) { lprint("Error: Bad control address: %s\r\n", buff); return CFG_ERROR; } ctl_addr = tmp_addr; lprint("Setting control address to %s\r\n", buff); return CFG_OK; } int cfg_compress(buff, inso) char *buff; struct socket *inso; { if_comp &= ~(IF_AUTOCOMP|IF_NOCOMPRESS); if_comp |= IF_COMPRESS; lprint("Setting VJ compression\r\n"); return CFG_OK; } int cfg_host_addr(buff, inso) char *buff; struct socket *inso; { struct in_addr tmp_addr; if (!inet_aton(buff, &tmp_addr)) { lprint("Error: Bad host address: %s\r\n", buff); return CFG_ERROR; } our_addr = tmp_addr; lprint("Setting host address to %s\r\n", buff); return CFG_OK; } int cfg_add_exec(buff, inso) char *buff; struct socket *inso; { char str[256]; char str2[256]; char str3[256]; int x; u_int32_t laddr; if (sscanf(buff, "%256[^:]:%256[^:]:%256s", str, str2, str3) == 3) { /* XXX should check if address == special address */ x = get_port(str3, 1); if (x < 0) return CFG_ERROR; if (x > 65535) { lprint("Error: Port out of range: %d\r\n", x); return CFG_ERROR; } else if ((laddr = inet_addr(str2)) == -1) { lprint("Error: Invalid address: %s\r\n", str2); return CFG_ERROR; } else if (add_exec(&exec_list, 0, str, (ntohl(laddr) & 0xff), htons(x)) < 0) { lprint("Error: Port already used: %s\r\n", buff); return CFG_ERROR; } else lprint("Adding execution of %s to address %s, port %d\r\n", str, str2, x); } else if (sscanf(buff, "%256[^:]:%256s", str, str3) == 2) { x = get_port(str3, 1); if (x < 0) return CFG_ERROR; if (x > 65535) { lprint("Error: Port out of range: %d\r\n", x); return CFG_ERROR; } else if (add_exec(&exec_list, 0, str, CTL_EXEC, htons(x)) < 0) { lprint("Error: Port already used: %s\r\n", buff); return CFG_ERROR; } else lprint("Adding execution of %s to port %d\r\n", str, x); } else return CFG_BADARGS; return CFG_OK; } int cfg_add_ptyexec(buff, inso) char *buff; struct socket *inso; { char str[256]; char str2[256]; int x; u_int32_t laddr; if (sscanf(buff, "%256[^:]:%256[^:]:%d", str, str2, &x) == 3) { /* XXX should check if address == special address */ if (x < 0 || x > 65535) { lprint("Error: Port out of range: %d\r\n", x); return CFG_ERROR; } else if ((laddr = inet_addr(str2)) == -1) { lprint("Error: Invalid address: %s\r\n", str2); return CFG_ERROR; } else if (add_exec(&exec_list, 1, str, (ntohl(laddr) & 0xff), htons(x)) < 0) { lprint("Error: Port already used: %s\r\n", buff); return CFG_ERROR; } else lprint("Adding %s to address %s, port %d\r\n", str, str2, x); } else if (sscanf(buff, "%256[^:]:%d", str, &x) == 2) { if (x < 0 || x > 65535) { lprint("Error: Port out of range: %d\r\n", x); return CFG_ERROR; } else if (add_exec(&exec_list, 1, str, CTL_EXEC, htons(x)) < 0) { lprint("Error: Port already used.\r\n"); return CFG_ERROR; } else lprint("Adding %s to port %d\r\n", str, x); } else return CFG_BADARGS; return CFG_OK; } int cfg_shell(buff, inso) char *buff; struct socket *inso; { char str[256]; if (exec_shell) free(exec_shell); sscanf(buff, "%256s", str); exec_shell = (char *)strdup(str); return CFG_OK; } int cfg_debug(buff, inso) char *buff; struct socket *inso; { int x; if (!buff) x = DEBUG_DEFAULT; else { if ((x = atoi(buff)) == 0) x = DEBUG_DEFAULT; } debug_init("slirp_debug", x); return CFG_OK; } int cfg_logstart(buff, inso) char *buff; struct socket *inso; { char buff1[256]; char *bptr; if (!buff) { buff1[0] = 0; if ((bptr = (char *)getenv("HOME")) != NULL) strncpy2(buff1, bptr, sizeof(buff1)); strncat(buff1, "/.slirp_start", sizeof(buff1)); lfd = fopen(buff1, "w"); bptr = buff1; } else { lfd = fopen(buff, "w"); bptr = buff; } if (!lfd) { lprint("Error: could not open logstart file: %s\r\n", strerror(errno)); return CFG_ERROR; } lprint("Log started to %s\r\n", bptr); return CFG_OK; } int cfg_logstats(buff, inso) char *buff; struct socket *inso; { dostats = 1; lprint("Logging statistics\r\n"); return CFG_OK; } int cfg_config(buff, inso) char *buff; struct socket *inso; { config(buff, cfg_unit); return CFG_OK; } int cfg_help(buff, inso) char *buff; struct socket *inso; { int i = 0; int str_len; int count = 0; char str[256]; char *str2; char *sptr; if (!buff) { lprint("Valid commands:\r\n"); while (cfg[i].command) { if (count >= 2) { sprintf(str, "\r\n"); count = 0; } else { count++; sptr = str; str_len = strlen(cfg[i].command); str_len = 20 - str_len; while (str_len-- >= 0) *sptr++ = ' '; *sptr = 0; } lprint("%s%s", cfg[i].command, str); i++; } if (count != 0) lprint("\r\n"); lprint("For more help type \"help COMMAND\" where command is either\r\n"); lprint("one of the above commands or a portion of a command.\r\n"); } else { str_len = strlen(buff); while (cfg[i].command) { if (!strncmp(cfg[i].command, buff, str_len) || (cfg[i].command_line && !strncmp(cfg[i].command_line, buff, str_len))) { /* Found a match, print the help */ count++; if (cfg[i].command_line) snprintf(str, sizeof(str), "Command-line: %s\r\n", cfg[i].command_line); else str[0] = 0; if (cfg[i].type == CFG_TELNET) str2 = "telnet"; else if (cfg[i].type == CFG_CMD_FILE) str2 = "command-line, config-file"; else if (cfg[i].type == (CFG_ANY)) str2 = "command-line, config-file, telnet"; else str2 = "[none]"; lprint( "Command: \"%s\"\r\nUsage: %s %s\r\n%sAvailable: %s\r\n %s\r\n\r\n", cfg[i].command, cfg[i].command, cfg[i].usage_args, str, str2, cfg[i].help); } i++; } lprint("%d match(es) found\r\n", count); } /* If it was called from the command-line, exit */ if (!inso) slirp_exit(0); return CFG_OK; } int cfg_stats(buff, inso) char *buff; struct socket *inso; { if (!strncmp(buff, "ip", 2)) ipstats(); else if (!strncmp(buff, "socket", 6)) sockstats(); else if (!strncmp(buff, "tcp", 3)) tcpstats(); else if (!strncmp(buff, "udp", 3)) udpstats(); else if (!strncmp(buff, "icmp", 4)) icmpstats(); else if (!strncmp(buff, "mbuf", 4)) mbufstats(); else if (!strncmp(buff, "vj", 2)) vjstats(); else if (!strncmp(buff, "alltty", 6)) allttystats(); else if (!strncmp(buff, "tty", 3)) ttystats(ttys_unit[cfg_unit]); else return CFG_BADARGS; return CFG_OK; } int cfg_echo(buff, inso) char *buff; struct socket *inso; { if (!buff) { lprint("Echo is %s\r\n", do_echo?"on":"off"); } else { if (strncmp(buff, "on", 2) == 0) { do_echo = 1; lprint("Echo is on.\r\n"); } else if (strncmp(buff, "off", 3) == 0) { do_echo = 0; lprint("Echo is off\r\n"); } else return CFG_BADARGS; } return CFG_OK; } int cfg_kill_close(x, type) int x, type; { struct socket *so; for (so = tcb.so_next; so != &tcb; so = so->so_next) { if (so->s == x) { /* Found it */ if (type == 1) { tcp_close(sototcpcb(so)); lprint( "Session removed.\r\n"); } else { tcp_sockclosed(sototcpcb(so)); shutdown(so->s, 0); /* XXX */ shutdown(so->s, 1); /* XXX */ so->so_state = SS_NOFDREF; /* XXX */ lprint("Session closed.\r\n"); } return CFG_OK; } } /* * Not TCP, maybe UDP */ for (so = udb.so_next; so != &tcb; so = so->so_next) { if (so->s == x) { udp_detach(so); lprint("Session closed.\r\n"); return CFG_OK; } } /* * Nup, cant find it */ lprint(" Error: session not found.\r\n"); return CFG_ERROR; } int cfg_quitting; int cfg_quit(buff, inso) char *buff; struct socket *inso; { lprint("Goodbye\r\n"); tcp_sockclosed(sototcpcb(inso)); cfg_quitting = 1; return CFG_OK; } int cfg_pass(buff, inso) char *buff; struct socket *inso; { char *ptr = buff; if (ctl_password) free(ctl_password); while (*ptr) { if (*ptr == '\n' || *ptr == '\r') *ptr = 0; else ptr++; } ctl_password = strdup(buff); return CFG_OK; } int cfg_tty(buff, inso) char *buff; struct socket *inso; { /* TTY actually set up earlier prior to main options processing (Only usable on command line) */ return CFG_OK; } int cfg_nozeros(buff, inso) char *buff; struct socket *inso; { /* Disable special zero processing */ nozeros++; return CFG_OK; } int cfg_kill(buff, inso) char *buff; struct socket *inso; { cfg_kill_close(atoi(buff), 1); return CFG_OK; } int cfg_close(buff, inso) char *buff; struct socket *inso; { cfg_kill_close(atoi(buff), 0); return CFG_OK; } int cfg_exec(buff, inso) char *buff; struct socket *inso; { fork_exec(inso, buff, 0); soisfconnected(inso); inso->so_emu = 0; return CFG_OK; } int cfg_ptyexec(buff, inso) char *buff; struct socket *inso; { fork_exec(inso, buff, 1); soisfconnected(inso); inso->so_emu = 0; return CFG_OK; } int cfg_add_emu(buff, inso) char *buff; struct socket *inso; { add_emu(buff); return CFG_OK; } int cfg_socket(buff, inso) char *buff; struct socket *inso; { struct sockaddr_in addr; char pwd[256]; int s, port; if (!buff) { /* Want unix domain socket */ #ifndef NO_UNIX_SOCKETS struct sockaddr_un sock_un; if (slirp_socket >= 0) { /* Close the old socket */ close(slirp_socket); slirp_socket = -1; } if (slirp_socket_passwd) { free(slirp_socket_passwd); slirp_socket_passwd = 0; } s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { lprint("Error: socket() failed\r\n"); return CFG_ERROR; } /* Remove the old socket */ (void) unlink(socket_path); /* Create a new one */ sock_un.sun_family = AF_UNIX; strncpy2(sock_un.sun_path, socket_path, sizeof(sock_un.sun_path)); if ((bind(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) < 0) || (listen(s, 1) < 0)) { close(s); lprint("Error: %s: %s\r\n", socket_path, strerror(errno)); return CFG_ERROR; } slirp_socket = s; return CFG_OK; #else lprint("Sorry, your system does not support unix-domain sockets.\r\n"); return CFG_OK; #endif } else { /* Want internet domain socket */ if (slirp_socket >= 0) { /* Close the old socket */ close(slirp_socket); slirp_socket = -1; } if (sscanf(buff, "%d,%s", &port, pwd) != 2) { lprint("Error: bad arguments to \"socket\"\r\n"); return CFG_ERROR; } s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { lprint("Error: socket() failed: %s\r\n", strerror(errno)); close(s); return CFG_ERROR; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) != 0) { lprint("Error: bind() failed: %s\r\n", strerror(errno)); close(s); return CFG_ERROR; } listen(s, 1); slirp_socket = s; if (slirp_socket_passwd) { /* Free old password */ free(slirp_socket_passwd); } slirp_socket_passwd = strdup(pwd); return CFG_OK; } } int cfg_dns(buff, inso) char *buff; struct socket *inso; { struct in_addr tmp_addr; if (!inet_aton(buff, &tmp_addr)) { lprint("Error: Bad IP\r\n"); return CFG_ERROR; } if(dns_addr.s_addr) { dns2_addr = tmp_addr; lprint("Setting DNS2 to %s\r\n", buff); } else { dns_addr = tmp_addr; lprint("Setting DNS to %s\r\n", buff); } return CFG_OK; } int cfg_keepalive(buff, inso) char *buff; struct socket *inso; { int tmp; if (buff) { tmp = atoi(buff); if (tmp < 5*PR_SLOWHZ || tmp > tcp_keepidle) { lprint("Error: TCP keepalive interval must be between 5 and %d\r\n", tcp_keepidle); return CFG_ERROR; } tcp_keepintvl = tmp*PR_SLOWHZ; } so_options = 1; lprint("Setting keepalive to %d seconds\r\n", tcp_keepintvl/PR_SLOWHZ); return CFG_OK; } int cfg_version(buff, inso) char *buff; struct socket *inso; { lprint("Slirp v%s (%s)\r\n", SLIRP_VERSION, SLIRP_STATUS); return CFG_OK; } int cfg_towrite_max(buff, inso) char *buff; struct socket *inso; { int tmp; tmp = atoi(buff); if (tmp < 0) { lprint("Error: towrite_max must be positive\r\n"); return CFG_ERROR; } towrite_max = tmp; lprint("Setting towrite_max to %d\r\n", towrite_max); return CFG_OK; } #ifdef USE_PPP int cfg_ppp_exit(buff, inso) char *buff; struct socket *inso; { ppp_exit = 1; lprint("Slirp will exit when PPP goes down\r\n"); return CFG_OK; } void setipdefault(unit) int unit; { struct hostent *hp; u_int32_t local; ipcp_options *wo = &ipcp_wantoptions[unit]; /* * If local IP address already given, don't bother. */ if (wo->ouraddr != 0 || disable_defaultip) return; /* * Look up our hostname (possibly with domain name appended) * and take the first IP address as our local IP address. * If there isn't an IP address for our hostname, too bad. */ wo->accept_local = 1; /* don't insist on this default value */ if ((hp = gethostbyname(hostname)) == NULL) return; local = *(u_int32_t *)hp->h_addr; if (local != 0 && !bad_ip_adrs(local)) wo->ouraddr = local; return; } /* * Read a word from a file. * Words are delimited by white-space or by quotes ("). * Quotes, white-space and \ may be escaped with \. * \ is ignored. */ int getword(f, word, newlinep, filename) FILE *f; char *word; int *newlinep; char *filename; { int c, len, escape; int quoted; *newlinep = 0; len = 0; escape = 0; quoted = 0; /* * First skip white-space and comments */ while ((c = getc(f)) != EOF) { if (c == '\\') { /* * \ is ignored; \ followed by anything else * starts a word. */ if ((c = getc(f)) == '\n') continue; word[len++] = '\\'; escape = 1; break; } if (c == '\n') *newlinep = 1; /* next word starts a line */ else if (c == '#') { /* comment - ignore until EOF or \r\n */ while ((c = getc(f)) != EOF && c != '\n') ; if (c == EOF) break; *newlinep = 1; } else if (!isspace(c)) break; } /* * End of file or error - fail */ if (c == EOF) { if (ferror(f)) { perror(filename); die(1); } return 0; } for (;;) { /* * Is this character escaped by \ ? */ if (escape) { if (c == '\n') --len; /* ignore \ */ else if (c == '"' || isspace(c) || c == '\\') word[len-1] = c; /* put special char in word */ else { if (len < MAXWORDLEN-1) word[len] = c; ++len; } escape = 0; } else if (c == '"') { quoted = !quoted; } else if (!quoted && (isspace(c) || c == '#')) { ungetc(c, f); break; } else { if (len < MAXWORDLEN-1) word[len] = c; ++len; if (c == '\\') escape = 1; } if ((c = getc(f)) == EOF) break; } if (ferror(f)) { perror(filename); die(1); } if (len >= MAXWORDLEN) { word[MAXWORDLEN-1] = 0; lprint("Warning: word in file %s too long (%.20s...)\r\n", filename, word); } else word[len] = 0; return 1; } u_int32_t GetMask(addr) u_int32_t addr; { return(netmask); } /* * number_option - parse a numeric parameter for an option */ u_int number_option(str, valp, base) char *str; u_int32_t *valp; int base; { char *bptr; *valp = strtoul(str, &bptr, base); if (bptr == str) { lprint("invalid number: %s\r\n", str); return CFG_ERROR; } return CFG_OK; } /* * int_option - like number_option, but valp is int *, * the base is assumed to be 0, and *valp is not changed * if there is an error. */ u_int int_option(str, valp) char *str; int *valp; { u_int32_t v; if (number_option(str, &v, 0) == CFG_ERROR) return CFG_ERROR; *valp = (u_int) v; return CFG_OK; } #endif int cfg_ppp(buff, inso) char *buff; struct socket *inso; { #ifdef USE_PPP struct ttys *ttyp = ttys_unit[cfg_unit]; if (!ttyp) { lprint("Error: Unit does not exists. Weird.\r\n"); return CFG_ERROR; } ppp_init(ttyp); return CFG_OK; #else lprint("Error: PPP not compiled into this slirp executable\r\n"); return CFG_OK; #endif } #ifdef USE_PPP /* * The following procedures execute commands. */ /* * setdebug - Set debug (command line argument). */ int setdebug(buff, inso) char *buff; struct socket *inso; { if (logfile) fclose(logfile); logfile = fopen("slirp_pppdebug", "w"); if (!logfile) { lprint("Error: can't open logfile\r\n"); return CFG_ERROR; } debug = 1; return CFG_OK; } /* * noopt - Disable all options. */ int noopt(buff, inso) char *buff; struct socket *inso; { BZERO((char *) &lcp_wantoptions[cfg_unit], sizeof (struct lcp_options)); BZERO((char *) &lcp_allowoptions[cfg_unit], sizeof (struct lcp_options)); BZERO((char *) &ipcp_wantoptions[cfg_unit], sizeof (struct ipcp_options)); BZERO((char *) &ipcp_allowoptions[cfg_unit], sizeof (struct ipcp_options)); return CFG_OK; } /* * noaccomp - Disable Address/Control field compression negotiation. */ int noaccomp(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_accompression = 0; lcp_allowoptions[cfg_unit].neg_accompression = 0; return CFG_OK; } /* * noasyncmap - Disable async map negotiation. */ int noasyncmap(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_asyncmap = 0; lcp_allowoptions[cfg_unit].neg_asyncmap = 0; return CFG_OK; } /* * noipaddr - Disable IP address negotiation. */ int noipaddr(buff, inso) char *buff; struct socket *inso; { ipcp_wantoptions[cfg_unit].neg_addr = 0; ipcp_allowoptions[cfg_unit].neg_addr = 0; return CFG_OK; } /* * nomagicnumber - Disable magic number negotiation. */ int nomagicnumber(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_magicnumber = 0; lcp_allowoptions[cfg_unit].neg_magicnumber = 0; return CFG_OK; } /* * nomru - Disable mru negotiation. */ int nomru(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_mru = 0; lcp_allowoptions[cfg_unit].neg_mru = 0; return CFG_OK; } #endif /* * setmru - Set MRU for negotiation. */ int setmru(opt_arg, inso) char *opt_arg; struct socket *inso; { long mru; /* PPP */ mru = atoi(opt_arg); #ifdef USE_PPP lcp_wantoptions[cfg_unit].mru = mru; lcp_wantoptions[cfg_unit].neg_mru = 1; #endif /* SLIP */ if_mru = mru; return CFG_OK; } /* * setmtu - Set the largest MTU we'll use. */ int setmtu(opt_arg, inso) char *opt_arg; struct socket *inso; { long mtu; /* PPP */ mtu = atoi(opt_arg); if (mtu < MIN_MRU || mtu > MAX_MRU) { lprint("mtu option value of %ld is too %s\r\n", mtu, (mtu < MIN_MRU? "small": "large")); return CFG_ERROR;; } #ifdef USE_PPP lcp_allowoptions[cfg_unit].mru = mtu; #endif /* SLIP XXXXX */ if_mtu = mtu; return CFG_OK; } #ifdef USE_PPP /* * nopcomp - Disable Protocol field compression negotiation. */ int nopcomp(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_pcompression = 0; lcp_allowoptions[cfg_unit].neg_pcompression = 0; return CFG_OK; } /* * setsilent - Set silent mode (don't start sending LCP configure-requests * until we get one from the peer). */ int setinitopt(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].silent = 0; return CFG_OK; } /* * nopap - Disable PAP authentication with peer. */ int nopap(buff, inso) char *buff; struct socket *inso; { lcp_allowoptions[cfg_unit].neg_upap = 0; return CFG_OK; } /* * reqpap - Require PAP authentication from peer. */ int reqpap(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_upap = 1; auth_required = 1; return CFG_OK; } /* * setupapfile - specifies UPAP info for authenticating with peer. */ int setupapfile(opt_arg, inso) char *opt_arg; struct socket *inso; { FILE * ufile; int l; lcp_allowoptions[cfg_unit].neg_upap = 1; /* open user info file */ if ((ufile = fopen(opt_arg, "r")) == NULL) { lprint("unable to open user login data file %s\r\n", opt_arg); return CFG_ERROR; } check_access(ufile, opt_arg); /* get username */ if (fgets(user, MAXNAMELEN - 1, ufile) == NULL || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){ lprint("Unable to read user login data file %s.\r\n", opt_arg); return CFG_ERROR; } fclose(ufile); /* get rid of newlines */ l = strlen(user); if (l > 0 && user[l-1] == '\n') user[l-1] = 0; l = strlen(passwd); if (l > 0 && passwd[l-1] == '\n') passwd[l-1] = 0; return CFG_OK; } /* * nochap - Disable CHAP authentication with peer. */ int nochap(buff, inso) char *buff; struct socket *inso; { lcp_allowoptions[cfg_unit].neg_chap = 0; return CFG_OK; } /* * reqchap - Require CHAP authentication from peer. */ int reqchap(buff, inso) char *buff; struct socket *inso; { lcp_wantoptions[cfg_unit].neg_chap = 1; auth_required = 1; return CFG_OK; } /* * setnovj - disable vj compression */ int setnovj(buff, inso) char *buff; struct socket *inso; { if_comp &= ~(IF_AUTOCOMP|IF_COMPRESS); if_comp |= IF_NOCOMPRESS; ipcp_wantoptions[cfg_unit].neg_vj = 0; ipcp_allowoptions[cfg_unit].neg_vj = 0; return CFG_OK; } /* * setnovjccomp - disable VJ connection-ID compression */ int setnovjccomp(buff, inso) char *buff; struct socket *inso; { ipcp_wantoptions[cfg_unit].cflag = 0; ipcp_allowoptions[cfg_unit].cflag = 0; return CFG_OK; } /* * setvjslots - set maximum number of connection slots for VJ compression */ int setvjslots(opt_arg, inso) char *opt_arg; struct socket *inso; { int value; if (int_option(opt_arg, &value) == CFG_ERROR) return CFG_ERROR; if (value < 2 || value > 16) { lprint("pppd: vj-max-slots value must be between 2 and 16\r\n"); return CFG_ERROR; } ipcp_wantoptions[cfg_unit].maxslotindex = ipcp_allowoptions[cfg_unit].maxslotindex = value - 1; return CFG_OK; } /* * setdomain - Set domain name to append to hostname */ int setdomain(opt_arg, inso) char *opt_arg; struct socket *inso; { strncat(hostname, opt_arg, MAXNAMELEN - strlen(hostname)); hostname[MAXNAMELEN-1] = 0; return CFG_OK; } /* * setasyncmap - add bits to asyncmap (what we request peer to escape). */ int setasyncmap(opt_arg, inso) char *opt_arg; struct socket *inso; { u_int32_t asyncmap; if (number_option(opt_arg, &asyncmap, 16) == CFG_ERROR) return CFG_ERROR; lcp_wantoptions[cfg_unit].asyncmap |= asyncmap; lcp_wantoptions[cfg_unit].neg_asyncmap = 1; return CFG_OK; } /* * setescape - add chars to the set we escape on transmission. */ int setescape(opt_arg, inso) char *opt_arg; struct socket *inso; { int n, n2, ret, num = 0; char *p, *endp; p = opt_arg; ret = CFG_OK; lprint("Escaping: "); while (*p) { n = strtoul(p, &endp, 16); if (p == endp) { lprint("\r\nError: invalid hex number: %s\r\n", p); return CFG_ERROR; } p = endp; if (*p == '-') { p++; n2 = strtoul(p, &endp, 16); if (p == endp) { lprint("\r\nError: invalid hex number: %s\r\n", p); return CFG_ERROR; } p = endp; if (n2 < n || n2 > 0xff) { lprint("\r\nError: bad second number in range\r\n"); return CFG_ERROR; } } else n2 = n; while (n <= n2) { if (n < 0 || (0x20 <= n && n <= 0x3F) || n == 0x5E || n > 0xFF) { lprint("\r\nError: can't escape character 0x%x\r\n", n); ret = CFG_ERROR; } else { if (num) lprint(", "); lprint("0x%x", n); num++; xmit_accm[cfg_unit][n >> 5] |= 1 << (n & 0x1F); } n++; } while (*p == ',' || *p == ' ' || *p == '\n' || *p == '\r') ++p; } lprint("\r\n"); if (!num) return CFG_BADARGS; else return ret; } /* * setipcpaccl - accept peer's idea of our address */ int setipcpaccl(buff, inso) char *buff; struct socket *inso; { ipcp_wantoptions[cfg_unit].accept_local = 1; return CFG_OK; } /* * setipcpaccr - accept peer's idea of its address */ int setipcpaccr(buff, inso) char *buff; struct socket *inso; { ipcp_wantoptions[cfg_unit].accept_remote = 1; return CFG_OK; } int setusehostname(buff, inso) char *buff; struct socket *inso; { usehostname = 1; return CFG_OK; } int setname(opt_arg, inso) char *opt_arg; struct socket *inso; { if (our_name[cfg_unit] == 0) { strncpy(our_name, opt_arg, MAXNAMELEN); our_name[MAXNAMELEN-1] = 0; } return CFG_OK; } int set_user(opt_arg, inso) char *opt_arg; struct socket *inso; { strncpy(user, opt_arg, MAXNAMELEN); user[MAXNAMELEN-1] = 0; return CFG_OK; } int setremote(opt_arg, inso) char *opt_arg; struct socket *inso; { strncpy(remote_name, opt_arg, MAXNAMELEN); remote_name[MAXNAMELEN-1] = 0; return CFG_OK; } int setauth(buff, inso) char *buff; struct socket *inso; { auth_required = 1; return CFG_OK; } int setproxyarp(buff, inso) char *buff; struct socket *inso; { ipcp_wantoptions[cfg_unit].proxy_arp = 1; return CFG_OK; } int setdologin(buff, inso) char *buff; struct socket *inso; { uselogin = 1; return CFG_OK; } /* * Functions to set the echo interval for modem-less monitors */ int setlcpechointv(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_echo_interval); } int setlcpechofails(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_echo_fails); } /* * Functions to set timeouts, max transmits, etc. */ int setlcptimeout(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_fsm[cfg_unit].timeouttime); } int setlcpterm(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_fsm[cfg_unit].maxtermtransmits); } int setlcpconf(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_fsm[cfg_unit].maxconfreqtransmits); } int setlcpfails(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_fsm[cfg_unit].maxnakloops); } int setipcptimeout(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &ipcp_fsm[cfg_unit].timeouttime); } int setipcpterm(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &ipcp_fsm[cfg_unit].maxtermtransmits); } int setipcpconf(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &ipcp_fsm[cfg_unit].maxconfreqtransmits); } int setipcpfails(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &lcp_fsm[cfg_unit].maxnakloops); } int setpaptimeout(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &upap[cfg_unit].us_timeouttime); } int setpapreqs(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &upap[cfg_unit].us_maxtransmits); } int setchaptimeout(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &chap[cfg_unit].timeouttime); } int setchapchal(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &chap[cfg_unit].max_transmits); } int setchapintv(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &chap[cfg_unit].chal_interval); } int setpapreqtime(opt_arg, inso) char *opt_arg; struct socket *inso; { return int_option(opt_arg, &upap[cfg_unit].us_reqtimeout); } int setbsdcomp(opt_arg, inso) char *opt_arg; struct socket *inso; { int rbits, abits; char *str, *endp; str = opt_arg; abits = rbits = strtol(str, &endp, 0); if (endp != str && *endp == ',') { str = endp + 1; abits = strtol(str, &endp, 0); } if ((*endp != 0 && *endp != '\n' && *endp != '\r') || endp == str) { lprint("Error: invalid argument format for bsdcomp option\n"); return CFG_ERROR; } if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { lprint("Error: bsdcomp option values must be 0 or %d .. %d\n", BSD_MIN_BITS, BSD_MAX_BITS); return CFG_ERROR; } if (rbits > 0) { ccp_wantoptions[cfg_unit].bsd_compress = 1; ccp_wantoptions[cfg_unit].bsd_bits = rbits; } else ccp_wantoptions[cfg_unit].bsd_compress = 0; if (abits > 0) { ccp_allowoptions[cfg_unit].bsd_compress = 1; ccp_allowoptions[cfg_unit].bsd_bits = abits; } else ccp_allowoptions[cfg_unit].bsd_compress = 0; return CFG_OK; } int setnobsdcomp(opt_arg, inso) char *opt_arg; struct socket *inso; { ccp_wantoptions[cfg_unit].bsd_compress = 0; ccp_allowoptions[cfg_unit].bsd_compress = 0; return CFG_OK; } int setpapcrypt(opt_arg, inso) char *opt_arg; struct socket *inso; { cryptpap = 1; return CFG_OK; } #endif struct cfgtab cfg[] = { { "redir X", 0, cfg_redir_x, CFG_ANY, 0, "[start RDISP] [ADDR][:DISPLAY[.SCREEN]]", "redirect a port for X" }, { "show X", 0, show_x, CFG_TELNET, 0, "", "show a previous redirection" }, { "redir", 0, cfg_redir, CFG_ANY, CFG_NEEDARG, "[once|time] [udp|tcp] PORT [to] [ADDR:]LPORT", "redirect a port" }, #ifndef FULL_BOLT { "baudrate", "-b", cfg_baudrate, CFG_ANY, CFG_NEEDARG, "BAUDRATE", "change the baudrate" }, #endif { "special addr", 0, cfg_sp_addr, CFG_ANY, CFG_NEEDARG, "ADDR", "set slirp's special address" }, { "control addr", 0, cfg_ctl_addr, CFG_ANY, CFG_NEEDARG, "ADDR", "set slirp's control address" }, { "compress", 0, cfg_compress, CFG_CMD_FILE, 0, "", "use VJ compression" }, { "host addr", 0, cfg_host_addr, CFG_ANY, CFG_NEEDARG, "ADDR", "set slirp's host address" }, { "add exec", 0, cfg_add_exec, CFG_ANY, CFG_NEEDARG, "| ptyexec PROGRAM:[ADDRESS:]PORT", "make slirp execute a program on connection to a specific host/port" }, { "add ptyexec", 0, cfg_add_ptyexec, CFG_ANY, CFG_NEEDARG, "| exec PROGRAM:[ADDRESS:]PORT", "make slirp execute a program on connection to a specific host/port" }, { "add emu", 0, cfg_add_emu, CFG_ANY, CFG_NEEDARG, "ftp|irc|none[:lowdelay|throughput] [LPORT:]FPORT", "add emulation to specific service/port" }, { "shell", 0, cfg_shell, CFG_CMD_FILE, CFG_NEEDARG, "PATH_TO_SHELL", "set your shell (same as add ptyexec PATH_TO_SHELL:23)" }, { "debug", "-d", cfg_debug, CFG_ANY, CFG_NEEDARG, "LEVEL", "start debugging to file slirp_debug" }, { "socket", "-s", cfg_socket, CFG_ANY, 0, "[PORT,PASSWORD]", "bind a socket and listen for other unit connections" }, { "log stats", "-S", cfg_logstats, CFG_CMD_FILE, 0, "", "log statistics to file slirp_stats upon exit" }, { "config", "-f", cfg_config, CFG_CMD_FILE, CFG_NEEDARG, "FILE", "read a configuration file" }, { "log start", 0, cfg_logstart, CFG_CMD_FILE, 0, "", "log startup info to ~/.slirp_start" }, { "dns", 0, cfg_dns, CFG_ANY, CFG_NEEDARG, "ADDR", "set dns address, for 10.0.2.3 as an alias for the real dns" }, { "help", 0, cfg_help, CFG_ANY, 0, "[COMMAND|START_OF_COMMAND]", "show help on given command" }, { "-h", 0, cfg_help, CFG_ANY, CFG_NEEDARG, "[COMMAND|START_OF_COMMAND]", "show help on given command" }, { "echo", 0, cfg_echo, CFG_TELNET, 0, "[on|off]", "set echo on or off, or show current state" }, { "kill", 0, cfg_kill, CFG_TELNET, CFG_NEEDARG, "SOCKET", "kill a socket" }, { "close", 0, cfg_close, CFG_TELNET, CFG_NEEDARG, "SOCKET", "close a socket" }, { "stats", 0, cfg_stats, CFG_TELNET, CFG_NEEDARG, "ip|socket|tcp|udp|icmp|mbuf|tty|alltty|vj", "show statistics" }, { "exec", 0, cfg_exec, CFG_TELNET, CFG_NEEDARG, "PATH_TO_PROGRAM", "execute a program" }, { "ptyexec", 0, cfg_ptyexec, CFG_TELNET, CFG_NEEDARG, "PATH_TO_PROGRAM", "execute a program in a pty" }, { "unit", 0, cfg_setunit, CFG_TELNET, CFG_NEEDARG, "N", "configure a different unit" }, { "wait", 0, cfg_wait, CFG_ANY, 0, "[MINUTES]", "set or show number of minutes slirp will linger after a disconnect" }, { "quit", 0, cfg_quit, CFG_TELNET, 0, "", "quit the command-line" }, { "password", 0, cfg_pass, CFG_CMD_FILE, CFG_NEEDARG, "PASSWORD", "make PASSWORD a password for telnet 10.0.2.0" }, { "keepalive", 0, cfg_keepalive, CFG_CMD_FILE, 0, "[SECONDS]", "make Slirp probe each TCP connection [every SECONDS seconds]" }, { "version", "-v", cfg_version, CFG_ANY, 0, "", "print Slirp's version" }, { "towrite_max", 0, cfg_towrite_max, CFG_ANY, CFG_NEEDARG, "NUM", "set the maximum towrite per tty (see slirp.doc for details)" }, { "tty", 0, cfg_tty, CFG_CMD_FILE, CFG_NEEDARG, "TTY", "Configure alternate TTY for slirp to use (Overrides SLIRP_TTY)" }, { "nozeros", 0, cfg_nozeros, CFG_CMD_FILE, 0, "", "Disable 5 0's to exit, 5 1's to detach" }, /* PPP options */ #ifndef USE_PPP { "ppp", "-P", cfg_ppp, CFG_CMD_FILE, 0, "", "PPP not compiled into this slirp executable" }, #else { "ppp", "-P", cfg_ppp, CFG_CMD_FILE, 0, "", "set unit to use PPP instead of SLIP" }, #endif #ifdef USE_PPP { "ppp_exit", 0, cfg_ppp_exit, CFG_ANY, 0, "", "make Slirp exit when PPP goes down" }, { "-all", 0, noopt, CFG_CMD_FILE, 0, "", "ppp: don't request/allow any options" }, { "-ac", 0, noaccomp, CFG_CMD_FILE, 0, "", "ppp: disable address/control compress" }, { "-am", 0, noasyncmap, CFG_CMD_FILE, 0, "", "ppp: disable asyncmap negotiation" }, { "asyncmap", "-as", setasyncmap, CFG_CMD_FILE, CFG_NEEDARG, "ASYNCMAP", "ppp: set the desired async map" }, { "debugppp", "-dppp", setdebug, CFG_ANY, 0, "FILE", "ppp: increase debugging level" }, { "-ip", 0, noipaddr, CFG_CMD_FILE, 0, "", "ppp: disable IP address negotiation" }, { "-mn", 0, nomagicnumber, CFG_CMD_FILE, 0, "", "ppp: disable magic number negotiation" }, { "-mru", 0, nomru, CFG_CMD_FILE, 0, "", "ppp: disable mru negotiation" }, { "-pc", 0, nopcomp, CFG_CMD_FILE, 0, "", "ppp: disable protocol field compress" }, { "+ua", 0, setupapfile, CFG_CMD_FILE, CFG_NEEDARG, "FILE", "ppp: get PAP user and password from file" }, { "+pap", 0, reqpap, CFG_CMD_FILE, 0, "", "ppp: require PAP auth from peer" }, { "-pap", 0, nopap, CFG_CMD_FILE, 0, "", "ppp: don't allow UPAP authentication with peer" }, { "+chap", 0, reqchap, CFG_CMD_FILE, 0, "", "ppp: require CHAP authentication from peer" }, { "-chap", 0, nochap, CFG_CMD_FILE, 0, "", "ppp: don't allow CHAP authentication with peer" }, { "-vj", 0, setnovj, CFG_CMD_FILE, 0, "", "ppp: disable VJ compression" }, { "-vjccomp", 0, setnovjccomp, CFG_CMD_FILE, 0, "", "ppp: disable VJ connection-ID compression" }, { "vj-max-slots", 0, setvjslots, CFG_CMD_FILE, CFG_NEEDARG, "SLOTS", "ppp: set maximum VJ header slots" }, { "escape", 0, setescape, CFG_CMD_FILE, CFG_NEEDARG, "NUM[,NUM|-NUM][...]", "ppp: set chars to escape on transmission" }, { "domain", 0, setdomain, CFG_CMD_FILE, CFG_NEEDARG, "ADDR", "ppp: add given domain name to hostname" }, #endif { "mru", 0, setmru, CFG_CMD_FILE, CFG_NEEDARG, "MRU", "set MRU" }, { "mtu", 0, setmtu, CFG_CMD_FILE, CFG_NEEDARG, "MTU", "set MTU" }, #ifdef USE_PPP { "initiate-options", 0, setinitopt, CFG_CMD_FILE, 0, "", "ppp: initiate the sending of options" }, { "name", 0, setname, CFG_CMD_FILE, CFG_NEEDARG, "NAME", "ppp: set local name for authentication" }, { "user", 0, set_user, CFG_CMD_FILE, CFG_NEEDARG, "USERNAME", "ppp: set username for PAP auth with peer" }, { "usehostname", 0, setusehostname, CFG_CMD_FILE, 0, "", "ppp: must use hostname for auth" }, { "remotename", 0, setremote, CFG_CMD_FILE, CFG_NEEDARG, "HOSTNAME", "ppp: set remote name for authentication" }, { "auth", 0, setauth, CFG_CMD_FILE, 0, "", "ppp: require authentication from peer" }, { "proxyarp", 0, setproxyarp, CFG_CMD_FILE, 0, "", "ppp: add proxy ARP entry" }, { "login", 0, setdologin, CFG_CMD_FILE, 0, "", "ppp: use system password database for UPAP" }, { "lcp-echo-failure", 0, setlcpechofails, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max number consecutive echo failures" }, { "lcp-echo-interval", 0, setlcpechointv, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: time for lcp echo events" }, { "lcp-restart", 0, setlcptimeout, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set timeout for LCP" }, { "lcp-max-terminate", 0, setlcpterm, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for term-reqs" }, { "lcp-max-configure", 0, setlcpconf, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for conf-reqs" }, { "lcp-max-failure", 0, setlcpfails, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #conf-naks for LCP" }, { "ipcp-restart", 0, setipcptimeout, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set timeout for IPCP" }, { "ipcp-max-terminate", 0, setipcpterm, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for term-reqs" }, { "ipcp-max-configure", 0, setipcpconf, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for conf-reqs" }, { "ipcp-max-failure", 0, setipcpfails, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #conf-naks for IPCP" }, { "pap-restart", 0, setpaptimeout, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set timeout for UPAP" }, { "pap-max-authreq", 0, setpapreqs, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for auth-reqs" }, { "pap-timeout", 0, setpapreqtime, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set PAP timeout" }, { "chap-restart", 0, setchaptimeout, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set timeout for CHAP" }, { "chap-max-challenge", 0, setchapchal, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set max #xmits for challenge" }, { "chap-interval", 0, setchapintv, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set interval for rechallenge" }, { "ipcp-accept-local", 0, setipcpaccl, CFG_CMD_FILE, 0, "", "ppp: accept peer's address for us" }, { "ipcp-accept-remote", 0, setipcpaccr, CFG_CMD_FILE, 0, "", "ppp: accept peer's address for it" }, { "bsdcomp", 0, setbsdcomp, CFG_CMD_FILE, CFG_NEEDARG, "N", "ppp: set bsdcomp" }, { "-bsdcomp", 0, setnobsdcomp, CFG_CMD_FILE, 0, "", "ppp: don't use bsdcomp" }, { "papcrypt", 0, setpapcrypt, CFG_CMD_FILE, 0, "", "ppp: crypt PAP authentication" }, #endif { NULL, NULL, NULL, 0, 0, NULL, NULL } }; slirp-1.0.17/src/options.h0000644000175000017500000000144510115276015014442 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _OPTIONS_H_ #define _OPTIONS_H_ struct cfgtab { char *command; char *command_line; int (*func) _P((char *, struct socket *)); u_char type; u_char flags; char *usage_args; char *help; }; #define CFG_CMD_FILE PRN_STDERR /* Can appear in config file or command line */ #define CFG_TELNET PRN_SPRINTF #define CFG_ANY CFG_CMD_FILE|CFG_TELNET #define CFG_NEEDARG 0x1 #define CFG_OK 0x0 #define CFG_BADARGS 0x1 #define CFG_ERROR 0x2 /* don't show usage on CFG_ERROR */ extern struct cfgtab cfg[]; extern int cfg_unit; extern int cfg_quitting; extern char *ctl_password; extern int ctl_password_ok; #endif slirp-1.0.17/src/options.p0000644000175000017500000001024710117211712014445 0ustar roverrovervoid config _P((char *, int)); int do_config _P((char *, struct socket *, int)); int get_port _P((char *, int)); int cfg_redir_x _P((char *, struct socket *)); int cfg_setunit _P((char *, struct socket *)); int cfg_redir _P((char *, struct socket *)); int cfg_baudrate _P((char *, struct socket *)); int cfg_wait _P((char *, struct socket *)); int cfg_sp_addr _P((char *, struct socket *)); int cfg_ctl_addr _P((char *, struct socket *)); int cfg_compress _P((char *, struct socket *)); int cfg_host_addr _P((char *, struct socket *)); int cfg_add_exec _P((char *, struct socket *)); int cfg_add_ptyexec _P((char *, struct socket *)); int cfg_shell _P((char *, struct socket *)); int cfg_debug _P((char *, struct socket *)); int cfg_logstart _P((char *, struct socket *)); int cfg_logstats _P((char *, struct socket *)); int cfg_config _P((char *, struct socket *)); int cfg_help _P((char *, struct socket *)); int cfg_stats _P((char *, struct socket *)); int cfg_echo _P((char *, struct socket *)); int cfg_kill_close _P((int, int)); int cfg_quit _P((char *, struct socket *)); int cfg_pass _P((char *, struct socket *)); int cfg_tty _P((char *, struct socket *)); int cfg_nozeros _P((char *, struct socket *)); int cfg_kill _P((char *, struct socket *)); int cfg_close _P((char *, struct socket *)); int cfg_exec _P((char *, struct socket *)); int cfg_ptyexec _P((char *, struct socket *)); int cfg_add_emu _P((char *, struct socket *)); int cfg_socket _P((char *, struct socket *)); int cfg_dns _P((char *, struct socket *)); int cfg_keepalive _P((char *, struct socket *)); int cfg_version _P((char *, struct socket *)); int cfg_towrite_max _P((char *, struct socket *)); int cfg_ppp_exit _P((char *, struct socket *)); void setipdefault _P((int)); int getword _P((FILE *, char *, int *, char *)); u_int32_t GetMask _P((u_int32_t)); u_int number_option _P((char *, u_int32_t *, int)); u_int int_option _P((char *, int *)); int cfg_ppp _P((char *, struct socket *)); int setdebug _P((char *, struct socket *)); int noopt _P((char *, struct socket *)); int noaccomp _P((char *, struct socket *)); int noasyncmap _P((char *, struct socket *)); int noipaddr _P((char *, struct socket *)); int nomagicnumber _P((char *, struct socket *)); int nomru _P((char *, struct socket *)); int setmru _P((char *, struct socket *)); int setmtu _P((char *, struct socket *)); int nopcomp _P((char *, struct socket *)); int setinitopt _P((char *, struct socket *)); int nopap _P((char *, struct socket *)); int reqpap _P((char *, struct socket *)); int setupapfile _P((char *, struct socket *)); int nochap _P((char *, struct socket *)); int reqchap _P((char *, struct socket *)); int setnovj _P((char *, struct socket *)); int setnovjccomp _P((char *, struct socket *)); int setvjslots _P((char *, struct socket *)); int setdomain _P((char *, struct socket *)); int setasyncmap _P((char *, struct socket *)); int setescape _P((char *, struct socket *)); int setipcpaccl _P((char *, struct socket *)); int setipcpaccr _P((char *, struct socket *)); int setusehostname _P((char *, struct socket *)); int setname _P((char *, struct socket *)); int set_user _P((char *, struct socket *)); int setremote _P((char *, struct socket *)); int setauth _P((char *, struct socket *)); int setproxyarp _P((char *, struct socket *)); int setdologin _P((char *, struct socket *)); int setlcpechointv _P((char *, struct socket *)); int setlcpechofails _P((char *, struct socket *)); int setlcptimeout _P((char *, struct socket *)); int setlcpterm _P((char *, struct socket *)); int setlcpconf _P((char *, struct socket *)); int setlcpfails _P((char *, struct socket *)); int setipcptimeout _P((char *, struct socket *)); int setipcpterm _P((char *, struct socket *)); int setipcpconf _P((char *, struct socket *)); int setipcpfails _P((char *, struct socket *)); int setpaptimeout _P((char *, struct socket *)); int setpapreqs _P((char *, struct socket *)); int setchaptimeout _P((char *, struct socket *)); int setchapchal _P((char *, struct socket *)); int setchapintv _P((char *, struct socket *)); int setpapreqtime _P((char *, struct socket *)); int setbsdcomp _P((char *, struct socket *)); int setnobsdcomp _P((char *, struct socket *)); int setpapcrypt _P((char *, struct socket *)); slirp-1.0.17/src/ppp/0000755000175000017500000000000010117224247013373 5ustar roverroverslirp-1.0.17/src/ppp/auth.c0000644000175000017500000005313310117211720014475 0ustar roverrover/* * auth.c - PPP authentication and phase control. * * Copyright (c) 1993 The Australian National 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 the Australian National 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. * * 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. */ #ifndef lint static char rcsid[] = "$Id: auth.c,v 1.15 1995/05/19 03:16:12 paulus Exp $"; #endif #include #include /* #include */ #include #include #include #include #include #ifdef HAS_SHADOW #include #include #ifndef PW_PPP #define PW_PPP PW_LOGIN #endif #endif #include "pppd.h" #include "fsm.h" #include "lcp.h" #include "upap.h" #include "chap.h" #include "ipcp.h" #include "ccp.h" #include "pathnames.h" #if defined(sun) && defined(sparc) #include #endif /*sparc*/ extern char *crypt _P((const char *, const char *)); /* Used for storing a sequence of words. Usually malloced. */ struct wordlist { struct wordlist *next; char word[1]; }; /* Bits in scan_authfile return value */ #define NONWILD_SERVER 1 #define NONWILD_CLIENT 2 #define ISWILD(word) (word[0] == '*' && word[1] == 0) #undef FALSE #define FALSE 0 #undef TRUE #define TRUE 1 #ifndef IN_LOOPBACKNET #define IN_LOOPBACKNET 127 #endif #ifndef IN_MULTICAST #define IN_MULTICAST(i) (((long)(i) & 0xf0000000) == 0xe0000000) #endif #ifndef IN_BADCLASS #define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) #endif /* Records which authentication operations haven't completed yet. */ static int auth_pending[NUM_PPP]; static int logged_in; static struct wordlist *addresses[NUM_PPP]; /* Bits in auth_pending[] */ #define UPAP_WITHPEER 1 #define UPAP_PEER 2 #define CHAP_WITHPEER 4 #define CHAP_PEER 8 /* Prototypes */ void check_access __P((FILE *, char *)); static void network_phase __P((int)); static int login __P((char *, char *, char **, int *)); static void logout __P((void)); static int null_login __P((int)); static int get_upap_passwd __P((void)); static int have_upap_secret __P((void)); static int have_chap_secret __P((char *, char *)); static int scan_authfile __P((FILE *, char *, char *, char *, int, struct wordlist **, char *)); static void free_wordlist __P((struct wordlist *)); /* * An Open on LCP has requested a change from Dead to Establish phase. * Do what's necessary to bring the physical layer up. */ void link_required(unit) int unit; { } /* * LCP has terminated the link; go to the Dead phase and take the * physical layer down. */ void link_terminated(unit) int unit; { if (phase == PHASE_DEAD) return; if (logged_in) logout(); phase = PHASE_DEAD; do_syslog(LOG_NOTICE, "Connection terminated."); if (ppp_exit) slirp_exit(0); } /* * LCP has gone down; it will either die or try to re-establish. */ void link_down(unit) int unit; { ipcp_close(0); ccp_close(0); phase = PHASE_TERMINATE; } /* * The link is established. * Proceed to the Dead, Authenticate or Network phase as appropriate. */ void link_established(unit) int unit; { int auth; lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *go = &lcp_gotoptions[unit]; lcp_options *ho = &lcp_hisoptions[unit]; if (auth_required && !(go->neg_chap || go->neg_upap)) { /* * We wanted the peer to authenticate itself, and it refused: * treat it as though it authenticated with PAP using a username * of "" and a password of "". If that's not OK, boot it out. */ if (!wo->neg_upap || !null_login(unit)) { do_syslog(LOG_WARNING, "peer refused to authenticate"); lcp_close(unit); phase = PHASE_TERMINATE; return; } } phase = PHASE_AUTHENTICATE; auth = 0; if (go->neg_chap) { ChapAuthPeer(unit, our_name, go->chap_mdtype); auth |= CHAP_PEER; } else if (go->neg_upap) { upap_authpeer(unit); auth |= UPAP_PEER; } if (ho->neg_chap) { ChapAuthWithPeer(unit, our_name, ho->chap_mdtype); auth |= CHAP_WITHPEER; } else if (ho->neg_upap) { upap_authwithpeer(unit, user, passwd); auth |= UPAP_WITHPEER; } auth_pending[unit] = auth; if (!auth) network_phase(unit); } /* * Proceed to the network phase. */ static void network_phase(unit) int unit; { phase = PHASE_NETWORK; ipcp_open(unit); ccp_open(unit); } /* * The peer has failed to authenticate himself using `protocol'. */ void auth_peer_fail(unit, protocol) int unit, protocol; { /* * Authentication failure: take the link down */ lcp_close(unit); phase = PHASE_TERMINATE; } /* * The peer has been successfully authenticated using `protocol'. */ void auth_peer_success(unit, protocol) int unit, protocol; { int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_PEER; break; case PPP_PAP: bit = UPAP_PEER; break; default: do_syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x", protocol); return; } /* * If there is no more authentication still to be done, * proceed to the network phase. */ if ((auth_pending[unit] &= ~bit) == 0) { phase = PHASE_NETWORK; ipcp_open(unit); ccp_open(unit); } } /* * We have failed to authenticate ourselves to the peer using `protocol'. */ void auth_withpeer_fail(unit, protocol) int unit, protocol; { /* * We've failed to authenticate ourselves to our peer. * He'll probably take the link down, and there's not much * we can do except wait for that. */ } /* * We have successfully authenticated ourselves with the peer using `protocol'. */ void auth_withpeer_success(unit, protocol) int unit, protocol; { int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_WITHPEER; break; case PPP_PAP: bit = UPAP_WITHPEER; break; default: do_syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x", protocol); bit = 0; } /* * If there is no more authentication still being done, * proceed to the network phase. */ if ((auth_pending[unit] &= ~bit) == 0) network_phase(unit); } /* * check_auth_options - called to check authentication options. */ void check_auth_options() { lcp_options *wo = &lcp_wantoptions[0]; lcp_options *ao = &lcp_allowoptions[0]; /* Default our_name to hostname, and user to our_name */ if (our_name[0] == 0 || usehostname) strncpy2(our_name, hostname, sizeof(our_name)); if (user[0] == 0) strncpy2(user, our_name, sizeof(user)); /* If authentication is required, ask peer for CHAP or PAP. */ if (auth_required && !wo->neg_chap && !wo->neg_upap) { wo->neg_chap = 1; wo->neg_upap = 1; } /* * Check whether we have appropriate secrets to use * to authenticate ourselves and/or the peer. */ if (ao->neg_upap && passwd[0] == 0 && !get_upap_passwd()) ao->neg_upap = 0; if (wo->neg_upap && !uselogin && !have_upap_secret()) wo->neg_upap = 0; if (ao->neg_chap && !have_chap_secret(our_name, remote_name)) ao->neg_chap = 0; if (wo->neg_chap && !have_chap_secret(remote_name, our_name)) wo->neg_chap = 0; if (auth_required && !wo->neg_chap && !wo->neg_upap) { fprintf(stderr, "\ pppd: peer authentication required but no authentication files accessible\n"); exit(1); } } /* * check_passwd - Check the user name and passwd against the PAP secrets * file. If requested, also check against the system password database, * and login the user if OK. * * returns: * UPAP_AUTHNAK: Authentication failed. * UPAP_AUTHACK: Authentication succeeded. * In either case, msg points to an appropriate message. */ int check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) int unit; char *auser; int userlen; char *apasswd; int passwdlen; char **msg; int *msglen; { int ret; char *filename; FILE *f; struct wordlist *addrs; char passwd[256], user[256]; char secret[MAXWORDLEN]; static int attempts = 0; /* * Make copies of apasswd and auser, then null-terminate them. */ BCOPY(apasswd, passwd, passwdlen); passwd[passwdlen] = '\0'; BCOPY(auser, user, userlen); user[userlen] = '\0'; /* * Open the file of upap secrets and scan for a suitable secret * for authenticating this user. */ filename = _PATH_UPAPFILE; addrs = NULL; ret = UPAP_AUTHACK; f = fopen(filename, "r"); if (f == NULL) { if (!uselogin) { do_syslog(LOG_ERR, "Can't open upap password file %s: %m", filename); ret = UPAP_AUTHNAK; } } else { check_access(f, filename); if (scan_authfile(f, user, our_name, secret, sizeof(secret), &addrs, filename) < 0 || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0) && strcmp(crypt(passwd, secret), secret) != 0)) { do_syslog(LOG_WARNING, "upap authentication failure for %s", user); ret = UPAP_AUTHNAK; } fclose(f); } if (uselogin && ret == UPAP_AUTHACK) { ret = login(user, passwd, msg, msglen); if (ret == UPAP_AUTHNAK) { do_syslog(LOG_WARNING, "upap login failure for %s", user); } } if (ret == UPAP_AUTHNAK) { *msg = "Login incorrect"; *msglen = strlen(*msg); /* * Frustrate passwd stealer programs. * Allow 10 tries, but start backing off after 3 (stolen from login). * On 10'th, drop the connection. */ if (attempts++ >= 10) { do_syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); quit(); } if (attempts > 3) sleep((u_int) (attempts - 3) * 5); if (addrs != NULL) free_wordlist(addrs); } else { attempts = 0; /* Reset count */ *msg = "Login ok"; *msglen = strlen(*msg); if (addresses[unit] != NULL) free_wordlist(addresses[unit]); addresses[unit] = addrs; } return ret; } /* * login - Check the user name and password against the system * password database, and login the user if OK. * * returns: * UPAP_AUTHNAK: Login failed. * UPAP_AUTHACK: Login succeeded. * In either case, msg points to an appropriate message. */ static int login(user, passwd, msg, msglen) char *user; char *passwd; char **msg; int *msglen; { struct passwd *pw; char *epasswd; char *tty; #ifdef HAS_SHADOW struct spwd *spwd; struct spwd *getspnam(); #endif if ((pw = getpwnam(user)) == NULL) { return (UPAP_AUTHNAK); } #ifdef HAS_SHADOW if ((spwd = getspnam(user)) == NULL) { pw->pw_passwd = ""; } else { pw->pw_passwd = spwd->sp_pwdp; } #endif /* * XXX If no passwd, let them login without one. */ if (pw->pw_passwd == '\0') { return (UPAP_AUTHACK); } #ifdef HAS_SHADOW if ((pw->pw_passwd && pw->pw_passwd[0] == '@' && pw_auth (pw->pw_passwd+1, pw->pw_name, PW_PPP, NULL)) || !valid (passwd, pw)) { return (UPAP_AUTHNAK); } #else epasswd = crypt(passwd, pw->pw_passwd); if (strcmp(epasswd, pw->pw_passwd)) { return (UPAP_AUTHNAK); } #endif do_syslog(LOG_INFO, "user %s logged in", user); /* * Write a wtmp entry for this user. */ tty = strrchr(devnam, '/'); if (tty == NULL) tty = devnam; else tty++; #ifdef LOGWTMP_WORKED logwtmp(tty, user, ""); /* Add wtmp login entry -- which just returned 1 */ #endif logged_in = TRUE; return (UPAP_AUTHACK); } /* * logout - Logout the user. */ static void logout() { char *tty; tty = strrchr(devnam, '/'); if (tty == NULL) tty = devnam; else tty++; #ifdef LOGWTMP_WORKED logwtmp(tty, "", ""); /* Wipe out wtmp logout entry */ #endif logged_in = FALSE; } /* * null_login - Check if a username of "" and a password of "" are * acceptable, and iff so, set the list of acceptable IP addresses * and return 1. */ static int null_login(unit) int unit; { char *filename; FILE *f; int i, ret; struct wordlist *addrs; char secret[MAXWORDLEN]; /* * Open the file of upap secrets and scan for a suitable secret. * We don't accept a wildcard client. */ filename = _PATH_UPAPFILE; addrs = NULL; f = fopen(filename, "r"); if (f == NULL) return 0; check_access(f, filename); i = scan_authfile(f, "", our_name, secret, sizeof(secret), &addrs, filename); ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0; if (ret) { if (addresses[unit] != NULL) free_wordlist(addresses[unit]); addresses[unit] = addrs; } fclose(f); return ret; } /* * get_upap_passwd - get a password for authenticating ourselves with * our peer using PAP. Returns 1 on success, 0 if no suitable password * could be found. */ static int get_upap_passwd() { char *filename; FILE *f; struct wordlist *addrs; char secret[MAXWORDLEN]; filename = _PATH_UPAPFILE; addrs = NULL; f = fopen(filename, "r"); if (f == NULL) return 0; check_access(f, filename); if (scan_authfile(f, user, remote_name, secret, sizeof(secret), NULL, filename) < 0) return 0; strncpy(passwd, secret, MAXSECRETLEN); passwd[MAXSECRETLEN-1] = 0; return 1; } /* * have_upap_secret - check whether we have a PAP file with any * secrets that we could possibly use for authenticating the peer. */ static int have_upap_secret() { FILE *f; int ret; char *filename; filename = _PATH_UPAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; ret = scan_authfile(f, NULL, our_name, NULL, 0, NULL, filename); fclose(f); if (ret < 0) return 0; return 1; } /* * have_chap_secret - check whether we have a CHAP file with a * secret that we could possibly use for authenticating `client' * on `server'. Either can be the null string, meaning we don't * know the identity yet. */ static int have_chap_secret(client, server) char *client; char *server; { FILE *f; int ret; char *filename; filename = _PATH_CHAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; if (client[0] == 0) client = NULL; else if (server[0] == 0) server = NULL; ret = scan_authfile(f, client, server, NULL, 0, NULL, filename); fclose(f); if (ret < 0) return 0; return 1; } /* * get_secret - open the CHAP secret file and return the secret * for authenticating the given client on the given server. * (We could be either client or server). */ int get_secret(unit, client, server, secret, secret_len, save_addrs) int unit; char *client; char *server; char *secret; int *secret_len; int save_addrs; { FILE *f; int ret, len; char *filename; struct wordlist *addrs; char secbuf[MAXWORDLEN]; filename = _PATH_CHAPFILE; addrs = NULL; secbuf[0] = 0; f = fopen(filename, "r"); if (f == NULL) { do_syslog(LOG_ERR, "Can't open chap secret file %s: %m", filename); return 0; } check_access(f, filename); ret = scan_authfile(f, client, server, secbuf, sizeof(secbuf), &addrs, filename); fclose(f); if (ret < 0) return 0; if (save_addrs) { if (addresses[unit] != NULL) free_wordlist(addresses[unit]); addresses[unit] = addrs; } len = strlen(secbuf); if (len > MAXSECRETLEN) { do_syslog(LOG_ERR, "Secret for %s on %s is too long", client, server); len = MAXSECRETLEN; } BCOPY(secbuf, secret, len); *secret_len = len; return 1; } /* * auth_ip_addr - check whether the peer is authorized to use * a given IP address. Returns 1 if authorized, 0 otherwise. */ int auth_ip_addr(unit, addr) int unit; u_int32_t addr; { u_int32_t a; struct hostent *hp; struct wordlist *addrs; /* don't allow loopback or multicast address */ if (bad_ip_adrs(addr)) return 0; if ((addrs = addresses[unit]) == NULL) return 1; /* no restriction */ for (; addrs != NULL; addrs = addrs->next) { /* "-" means no addresses authorized */ if (strcmp(addrs->word, "-") == 0) break; if ((a = inet_addr(addrs->word)) == -1) { if ((hp = gethostbyname(addrs->word)) == NULL) { do_syslog(LOG_WARNING, "unknown host %s in auth. address list", addrs->word); continue; } else a = *(u_int32_t *)hp->h_addr; } if (addr == a) return 1; } return 0; /* not in list => can't have it */ } /* * bad_ip_adrs - return 1 if the IP address is one we don't want * to use, such as an address in the loopback net or a multicast address. * addr is in network byte order. */ int bad_ip_adrs(addr) u_int32_t addr; { addr = ntohl(addr); return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || IN_MULTICAST(addr) || IN_BADCLASS(addr); } /* * check_access - complain if a secret file has too-liberal permissions. */ void check_access(f, filename) FILE *f; char *filename; { struct stat sbuf; if (fstat(fileno(f), &sbuf) < 0) { do_syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename); } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { do_syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename); } } /* * scan_authfile - Scan an authorization file for a secret suitable * for authenticating `client' on `server'. The return value is -1 * if no secret is found, otherwise >= 0. The return value has * NONWILD_CLIENT set if the secret didn't have "*" for the client, and * NONWILD_SERVER set if the secret didn't have "*" for the server. * Any following words on the line (i.e. address authorization * info) are placed in a wordlist and returned in *addrs. */ static int scan_authfile(f, client, server, secret, max_secret, addrs, filename) FILE *f; char *client; char *server; char *secret; int max_secret; struct wordlist **addrs; char *filename; { int newline, xxx; int got_flag, best_flag; FILE *sf; struct wordlist *ap, *addr_list, *addr_last; char word[MAXWORDLEN]; char atfile[MAXWORDLEN]; if (addrs != NULL) *addrs = NULL; addr_list = NULL; if (!getword(f, word, &newline, filename)) return -1; /* file is empty??? */ newline = 1; best_flag = -1; for (;;) { /* * Skip until we find a word at the start of a line. */ while (!newline && getword(f, word, &newline, filename)) ; if (!newline) break; /* got to end of file */ /* * Got a client - check if it's a match or a wildcard. */ got_flag = 0; if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { newline = 0; continue; } if (!ISWILD(word)) got_flag = NONWILD_CLIENT; /* * Now get a server and check if it matches. */ if (!getword(f, word, &newline, filename)) break; if (newline) continue; if (server != NULL && strcmp(word, server) != 0 && !ISWILD(word)) continue; if (!ISWILD(word)) got_flag |= NONWILD_SERVER; /* * Got some sort of a match - see if it's better than what * we have already. */ if (got_flag <= best_flag) continue; /* * Get the secret. */ if (!getword(f, word, &newline, filename)) break; if (newline) continue; /* * Special syntax: @filename means read secret from file. */ if (word[0] == '@') { strncpy2(atfile, word+1, sizeof(atfile)); if ((sf = fopen(atfile, "r")) == NULL) { do_syslog(LOG_WARNING, "can't open indirect secret file %s", atfile); continue; } check_access(sf, atfile); if (!getword(sf, word, &xxx, atfile)) { do_syslog(LOG_WARNING, "no secret in indirect secret file %s", atfile); fclose(sf); continue; } fclose(sf); } if (secret != NULL) strncpy2(secret, word, max_secret); best_flag = got_flag; /* * Now read address authorization info and make a wordlist. */ if (addr_list) free_wordlist(addr_list); addr_list = addr_last = NULL; for (;;) { if (!getword(f, word, &newline, filename) || newline) break; ap = (struct wordlist *) malloc(sizeof(struct wordlist) + strlen(word)); if (ap == NULL) novm("authorized addresses"); ap->next = NULL; /* TODO: check lengths should be ok, alloced correctly above.*/ strcpy(ap->word, word); if (addr_list == NULL) addr_list = ap; else addr_last->next = ap; addr_last = ap; } if (!newline) break; } if (addrs != NULL) *addrs = addr_list; else if (addr_list != NULL) free_wordlist(addr_list); return best_flag; } /* * free_wordlist - release memory allocated for a wordlist. */ static void free_wordlist(wp) struct wordlist *wp; { struct wordlist *next; while (wp != NULL) { next = wp->next; free(wp); wp = next; } } slirp-1.0.17/src/ppp/bsd-comp.c0000644000175000017500000006310010115276023015240 0ustar roverrover/* Because this code is derived from the 4.3BSD compress source: * * * Copyright (c) 1985, 1986 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * James A. Woods, derived from original work by Spencer Thomas * and Joseph Orost. * * 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. */ /* * This version is for use with mbufs on BSD-derived systems. * * $Id: bsd-comp.c,v 1.11 1995/07/04 03:35:11 paulus Exp $ */ #include #define M_INC_COMP 4096 /* XXXXX */ #include #if DO_BSD_COMPRESS /* * PPP "BSD compress" compression * The differences between this compression and the classic BSD LZW * source are obvious from the requirement that the classic code worked * with files while this handles arbitrarily long streams that * are broken into packets. They are: * * When the code size expands, a block of junk is not emitted by * the compressor and not expected by the decompressor. * * New codes are not necessarily assigned every time an old * code is output by the compressor. This is because a packet * end forces a code to be emitted, but does not imply that a * new sequence has been seen. * * The compression ratio is checked at the first end of a packet * after the appropriate gap. Besides simplifying and speeding * things up, this makes it more likely that the transmitter * and receiver will agree when the dictionary is cleared when * compression is not going well. */ #define BSD_OVHD 2 /* BSD compress overhead/packet */ #define BSD_INIT_BITS BSD_MIN_BITS static void *bsd_comp_alloc __P((u_char *options, int opt_len)); static void *bsd_decomp_alloc __P((u_char *options, int opt_len)); static void bsd_free __P((void *state)); static int bsd_comp_init __P((void *state, u_char *options, int opt_len, int unit, int hdrlen, int debug)); static int bsd_decomp_init __P((void *state, u_char *options, int opt_len, int unit, int hdrlen, int mru, int debug)); static int bsd_compress __P((void *state, struct mbuf **mret, struct mbuf *mp, int slen, int maxolen, int proto)); static void bsd_incomp __P((void *state, struct mbuf *dmsg, int proto)); static int bsd_decompress __P((void *state, struct mbuf *cmp, struct mbuf **dmpp)); static void bsd_reset __P((void *state)); static void bsd_comp_stats __P((void *state, struct compstat *stats)); #include "bsd-comp.h" /* * the next two codes should not be changed lightly, as they must not * lie within the contiguous general code space. */ #define CLEAR 256 /* table clear output code */ #define FIRST 257 /* first free entry */ #define LAST 255 #define MAXCODE(b) ((1 << (b)) - 1) #define BADCODEM1 MAXCODE(BSD_MAX_BITS) #define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \ ^ (u_int32_t)(prefix)) #define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \ + (u_int32_t)(prefix)) #define CHECK_GAP 10000 /* Ratio check interval */ #define RATIO_SCALE_LOG 8 #define RATIO_SCALE (1<>RATIO_SCALE_LOG) /* * Procedures exported to if_ppp.c. */ struct compressor ppp_bsd_compress = { CI_BSD_COMPRESS, /* compress_proto */ bsd_comp_alloc, /* comp_alloc */ bsd_free, /* comp_free */ bsd_comp_init, /* comp_init */ bsd_reset, /* comp_reset */ bsd_compress, /* compress */ bsd_comp_stats, /* comp_stat */ bsd_decomp_alloc, /* decomp_alloc */ bsd_free, /* decomp_free */ bsd_decomp_init, /* decomp_init */ bsd_reset, /* decomp_reset */ bsd_decompress, /* decompress */ bsd_incomp, /* incomp */ bsd_comp_stats, /* decomp_stat */ }; /* * clear the dictionary */ static void bsd_clear(db) struct bsd_db *db; { db->clear_count++; db->max_ent = FIRST-1; db->n_bits = BSD_INIT_BITS; db->ratio = 0; db->bytes_out = 0; db->in_count = 0; db->incomp_count = 0; db->checkpoint = CHECK_GAP; } /* * If the dictionary is full, then see if it is time to reset it. * * Compute the compression ratio using fixed-point arithmetic * with 8 fractional bits. * * Since we have an infinite stream instead of a single file, * watch only the local compression ratio. * * Since both peers must reset the dictionary at the same time even in * the absence of CLEAR codes (while packets are incompressible), they * must compute the same ratio. */ static int /* 1=output CLEAR */ bsd_check(db) struct bsd_db *db; { u_int new_ratio; if (db->in_count >= db->checkpoint) { /* age the ratio by limiting the size of the counts */ if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) { db->in_count -= db->in_count/4; db->bytes_out -= db->bytes_out/4; } db->checkpoint = db->in_count + CHECK_GAP; if (db->max_ent >= db->maxmaxcode) { /* Reset the dictionary only if the ratio is worse, * or if it looks as if it has been poisoned * by incompressible data. * * This does not overflow, because * db->in_count <= RATIO_MAX. */ new_ratio = db->in_count << RATIO_SCALE_LOG; if (db->bytes_out != 0) new_ratio /= db->bytes_out; if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) { bsd_clear(db); return 1; } db->ratio = new_ratio; } } return 0; } /* * Return statistics. */ static void bsd_comp_stats(state, stats) void *state; struct compstat *stats; { struct bsd_db *db = (struct bsd_db *) state; u_int out; stats->unc_bytes = db->uncomp_bytes; stats->unc_packets = db->uncomp_count; stats->comp_bytes = db->comp_bytes; stats->comp_packets = db->comp_count; stats->inc_bytes = db->incomp_bytes; stats->inc_packets = db->incomp_count; stats->ratio = db->in_count; out = db->bytes_out; if (stats->ratio <= 0x7fffff) stats->ratio <<= 8; else out >>= 8; if (out != 0) stats->ratio /= out; } /* * Reset state, as on a CCP ResetReq. */ static void bsd_reset(state) void *state; { struct bsd_db *db = (struct bsd_db *) state; db->seqno = 0; bsd_clear(db); db->clear_count = 0; } /* * Allocate space for a (de) compressor. */ static void * bsd_alloc(options, opt_len, decomp) u_char *options; int opt_len, decomp; { int bits; u_int newlen, hsize, hshift, maxmaxcode; struct bsd_db *db; if (opt_len != CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) return NULL; bits = BSD_NBITS(options[2]); switch (bits) { case 9: /* needs 82152 for both directions */ case 10: /* needs 84144 */ case 11: /* needs 88240 */ case 12: /* needs 96432 */ hsize = 5003; hshift = 4; break; case 13: /* needs 176784 */ hsize = 9001; hshift = 5; break; case 14: /* needs 353744 */ hsize = 18013; hshift = 6; break; case 15: /* needs 691440 */ hsize = 35023; hshift = 7; break; case 16: /* needs 1366160--far too much, */ /* hsize = 69001; */ /* and 69001 is too big for cptr */ /* hshift = 8; */ /* in struct bsd_db */ /* break; */ default: return NULL; } maxmaxcode = MAXCODE(bits); newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0])); db = (struct bsd_db *)malloc(newlen); if (!db) return NULL; memset(db, 0, sizeof(*db) - sizeof(db->dict)); if (!decomp) { db->lens = NULL; } else { db->lens = (u_short *)malloc((maxmaxcode+1) * sizeof(db->lens[0])); if (!db->lens) { free(db); return NULL; } } db->totlen = newlen; db->hsize = hsize; db->hshift = hshift; db->maxmaxcode = maxmaxcode; db->maxbits = bits; return (void *) db; } static void bsd_free(state) void *state; { struct bsd_db *db = (struct bsd_db *) state; if (db->lens) free(db->lens); free(db); } static void * bsd_comp_alloc(options, opt_len) u_char *options; int opt_len; { return bsd_alloc(options, opt_len, 0); } static void * bsd_decomp_alloc(options, opt_len) u_char *options; int opt_len; { return bsd_alloc(options, opt_len, 1); } /* * Initialize the database. */ static int bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp) struct bsd_db *db; u_char *options; int opt_len, unit, hdrlen, mru, debug, decomp; { int i; if (opt_len != CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION || BSD_NBITS(options[2]) != db->maxbits || decomp && db->lens == NULL) return 0; if (decomp) { i = LAST+1; while (i != 0) db->lens[--i] = 1; } i = db->hsize; while (i != 0) { db->dict[--i].codem1 = BADCODEM1; db->dict[i].cptr = 0; } db->unit = unit; db->hdrlen = hdrlen; db->mru = mru; #ifndef DEBUG if (debug) #endif db->debug = 1; bsd_reset(db); return 1; } static int bsd_comp_init(state, options, opt_len, unit, hdrlen, debug) void *state; u_char *options; int opt_len, unit, hdrlen, debug; { return bsd_init((struct bsd_db *) state, options, opt_len, unit, hdrlen, 0, debug, 0); } static int bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug) void *state; u_char *options; int opt_len, unit, hdrlen, mru, debug; { return bsd_init((struct bsd_db *) state, options, opt_len, unit, hdrlen, mru, debug, 1); } /* * compress a packet * One change from the BSD compress command is that when the * code size expands, we do not output a bunch of padding. */ int /* new slen */ bsd_compress(state, mret, mp, slen, maxolen, proto) void *state; struct mbuf **mret; /* return compressed mbuf chain here */ struct mbuf *mp; /* from here */ int slen; /* uncompressed length */ int maxolen; /* max compressed length */ int proto; { struct bsd_db *db = (struct bsd_db *) state; int hshift = db->hshift; u_int max_ent = db->max_ent; u_int n_bits = db->n_bits; u_int bitno = 32; u_int32_t accm = 0, fcode; struct bsd_dict *dictp; u_char c; int hval, disp, ent, ilen; struct mbuf *np; u_char *rptr, *wptr; u_char *cp_end; int olen; struct mbuf *m, **mnp; /* * XXXXX MUST check for end-of-buffer, and if it happens, bail! * (more efficient than mallocing then realising it's too big etc.) */ #define PUTBYTE(v) { \ ++olen; \ if (wptr) { \ *wptr++ = (v); \ if (wptr >= cp_end) { \ m_inc(m, M_INC_COMP); \ wptr = mtod(m, u_char *); \ cp_end = m->m_ext + m->m_size; \ } \ } \ } #define OUTPUT(ent) { \ bitno -= n_bits; \ accm |= ((ent) << bitno); \ do { \ PUTBYTE(accm >> 24); \ accm <<= 8; \ bitno += 8; \ } while (bitno <= 24); \ } /* * If the protocol is not in the range we're interested in, * just return without compressing the packet. If it is, * the protocol becomes the first byte to compress. */ rptr = mtod(mp, u_char *); ent = proto; if (ent < 0x21 || ent > 0xf9) { *mret = NULL; return slen; } /* Don't generate compressed packets which are larger than the uncompressed packet. */ if (maxolen > slen) maxolen = slen; /* Allocate one mbuf to start with. */ m = m_get(); m->m_data += if_maxlinkhdr; *mret = m; if (m != NULL) { m->m_data += db->hdrlen; wptr = mtod(m, u_char *); cp_end = wptr + M_TRAILINGSPACE(m); } else wptr = cp_end = NULL; /* * install the 2-byte packet sequence number. */ if (wptr) { *wptr++ = db->seqno >> 8; *wptr++ = db->seqno; } ++db->seqno; olen = 0; slen = mp->m_len; ilen = slen + 1; for (;;) { if (slen <= 0) break; slen--; c = *rptr++; fcode = BSD_KEY(ent, c); hval = BSD_HASH(ent, c, hshift); dictp = &db->dict[hval]; /* Validate and then check the entry. */ if (dictp->codem1 >= max_ent) goto nomatch; if (dictp->f.fcode == fcode) { ent = dictp->codem1+1; continue; /* found (prefix,suffix) */ } /* continue probing until a match or invalid entry */ disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->f.fcode != fcode); ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ continue; nomatch: OUTPUT(ent); /* output the prefix */ /* code -> hashtable */ if (max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; /* expand code size if needed */ if (max_ent >= MAXCODE(n_bits)) db->n_bits = ++n_bits; /* Invalidate old hash table entry using * this code, and then take it over. */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) db->dict[dictp2->cptr].codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; } ent = c; } OUTPUT(ent); /* output the last code */ db->bytes_out += olen; db->in_count += ilen; if (bitno < 32) ++db->bytes_out; /* count complete bytes */ if (bsd_check(db)) OUTPUT(CLEAR); /* do not count the CLEAR */ /* * Pad dribble bits of last code with ones. * Do not emit a completely useless byte of ones. */ if (bitno != 32) PUTBYTE((accm | (0xff << (bitno-8))) >> 24); if (m != NULL) m->m_len = wptr - mtod(m, u_char *); /* * Increase code size if we would have without the packet * boundary and as the decompressor will. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) db->n_bits++; db->uncomp_bytes += ilen; ++db->uncomp_count; if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) { /* throw away the compressed stuff if it is longer than uncompressed */ if (*mret != NULL) { m_freem(*mret); *mret = NULL; } ++db->incomp_count; db->incomp_bytes += ilen; } else { ++db->comp_count; db->comp_bytes += olen + BSD_OVHD; } return olen + BSD_OVHD; /* For stats */ #undef OUTPUT #undef PUTBYTE } /* * Update the "BSD Compress" dictionary on the receiver for * incompressible data by pretending to compress the incoming data. */ static void bsd_incomp(state, dmsg, proto) void *state; struct mbuf *dmsg; int proto; { struct bsd_db *db = (struct bsd_db *) state; u_int hshift = db->hshift; u_int max_ent = db->max_ent; u_int n_bits = db->n_bits; struct bsd_dict *dictp; u_int32_t fcode; u_char c; u_int32_t hval, disp; int slen, ilen; u_int bitno = 7; u_char *rptr; u_int ent; /* * If the protocol is not in the range we're interested in, * just return without looking at the packet. If it is, * the protocol becomes the first byte to "compress". */ rptr = mtod(dmsg, u_char *); ent = proto; if (ent < 0x21 || ent > 0xf9) return; db->incomp_count++; db->seqno++; ilen = 1; /* count the protocol as 1 byte */ slen = dmsg->m_len; for (;;) { if (slen <= 0) break; ilen += slen; do { c = *rptr++; fcode = BSD_KEY(ent, c); hval = BSD_HASH(ent, c, hshift); dictp = &db->dict[hval]; /* validate and then check the entry */ if (dictp->codem1 >= max_ent) goto nomatch; if (dictp->f.fcode == fcode) { ent = dictp->codem1+1; continue; /* found (prefix,suffix) */ } /* continue probing until a match or invalid entry */ disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->f.fcode != fcode); ent = dictp->codem1+1; continue; /* finally found (prefix,suffix) */ nomatch: /* output (count) the prefix */ bitno += n_bits; /* code -> hashtable */ if (max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; /* expand code size if needed */ if (max_ent >= MAXCODE(n_bits)) db->n_bits = ++n_bits; /* Invalidate previous hash table entry * assigned this code, and then take it over. */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) db->dict[dictp2->cptr].codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; db->lens[max_ent] = db->lens[ent]+1; } ent = c; } while (--slen != 0); } bitno += n_bits; /* output (count) the last code */ db->bytes_out += bitno/8; db->in_count += ilen; (void)bsd_check(db); ++db->incomp_count; db->incomp_bytes += ilen; ++db->uncomp_count; db->uncomp_bytes += ilen; /* Increase code size if we would have without the packet * boundary and as the decompressor will. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) db->n_bits++; } /* * Decompress "BSD Compress". * * Because of patent problems, we return DECOMP_ERROR for errors * found by inspecting the input data and for system problems, but * DECOMP_FATALERROR for any errors which could possibly be said to * be being detected "after" decompression. For DECOMP_ERROR, * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be * infringing a patent of Motorola's if we do, so we take CCP down * instead. * * Given that the frame has the correct sequence number and a good FCS, * errors such as invalid codes in the input most likely indicate a * bug, so we return DECOMP_FATALERROR for them in order to turn off * compression, even though they are detected by inspecting the input. */ int bsd_decompress(state, cmp, dmpp) void *state; struct mbuf *cmp, **dmpp; { struct bsd_db *db = (struct bsd_db *) state; u_int max_ent = db->max_ent; u_int32_t accm = 0; u_int bitno = 32; /* 1st valid bit in accm */ u_int n_bits = db->n_bits; u_int tgtbitno = 32-n_bits; /* bitno when we have a code */ struct bsd_dict *dictp; int explen, i, seq, len; u_int incode, oldcode, finchar; u_char *p, *rptr, *wptr; struct mbuf *m, *dmp, *mret; int adrs, ctrl, ilen; int space, codelen, extra; struct mbuf *last; *dmpp = NULL; rptr = mtod(cmp, u_char *); len = cmp->m_len; seq = 0; for (i = 0; i < 2; ++i) { if (len <= 0) return DECOMP_ERROR; seq = (seq << 8) + *rptr++; --len; } /* * Check the sequence number and give up if it differs from * the value we're expecting. */ if (seq != db->seqno) { if (db->debug) printf("bsd_decomp%d: bad sequence # %d, expected %d\n", db->unit, seq, db->seqno - 1); return DECOMP_ERROR; } ++db->seqno; /* * Allocate one mbuf to start with. */ dmp = m_get(); if (dmp == NULL) return DECOMP_ERROR; dmp->m_data += if_maxlinkhdr; mret = dmp; dmp->m_data += db->hdrlen; wptr = mtod(dmp, u_char *); space = M_TRAILINGSPACE(dmp); /* * Fill in the ppp header, but not the last byte of the protocol * (that comes from the decompressed data). */ ilen = len; oldcode = CLEAR; explen = 0; for (;;) { if (len == 0) break; /* * Accumulate bytes until we have a complete code. * Then get the next code, relying on the 32-bit, * unsigned accm to mask the result. */ bitno -= 8; accm |= *rptr++ << bitno; --len; if (tgtbitno < bitno) continue; incode = accm >> tgtbitno; accm <<= n_bits; bitno += n_bits; if (incode == CLEAR) { /* * The dictionary must only be cleared at * the end of a packet. But there could be an * empty mbuf at the end. */ if (len > 0) { m_freem(mret); if (db->debug) printf("bsd_decomp%d: bad CLEAR\n", db->unit); return DECOMP_FATALERROR; /* probably a bug */ } bsd_clear(db); explen = ilen = 0; break; } if (incode > max_ent + 2 || incode > db->maxmaxcode || incode > max_ent && oldcode == CLEAR) { m_freem(mret); if (db->debug) { printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", db->unit, incode, oldcode); printf("max_ent=0x%x explen=%d seqno=%d\n", max_ent, explen, db->seqno); } return DECOMP_FATALERROR; /* probably a bug */ } /* Special case for KwKwK string. */ if (incode > max_ent) { finchar = oldcode; extra = 1; } else { finchar = incode; extra = 0; } codelen = db->lens[finchar]; explen += codelen + extra; if (explen > db->mru + 1) { m_freem(mret); if (db->debug) { printf("bsd_decomp%d: ran out of mru\n", db->unit); } return DECOMP_FATALERROR; } /* * For simplicity, the decoded characters go in a single mbuf, * so we allocate a single extra cluster mbuf if necessary. */ if ((space -= codelen + extra) < 0) { m_inc(dmp, M_INC_COMP); space = M_TRAILINGSPACE(dmp) - (codelen + extra); if (space < 0) { /* now that's what I call *compression*. */ m_freem(mret); /* mret = dmp */ return DECOMP_ERROR; } wptr = mtod(dmp, u_char *); } /* * Decode this code and install it in the decompressed buffer. */ p = (wptr += codelen); while (finchar > LAST) { dictp = &db->dict[db->dict[finchar].cptr]; #ifdef DEBUG if (--codelen <= 0 || dictp->codem1 != finchar-1) goto bad; #endif *--p = dictp->f.hs.suffix; finchar = dictp->f.hs.prefix; } *--p = finchar; #ifdef DEBUG if (--codelen != 0) printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent); #endif if (extra) /* the KwKwK case again */ *wptr++ = finchar; /* * If not first code in a packet, and * if not out of code space, then allocate a new code. * * Keep the hash table correct so it can be used * with uncompressed packets. */ if (oldcode != CLEAR && max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; u_int32_t fcode; u_int32_t hval, disp; fcode = BSD_KEY(oldcode,finchar); hval = BSD_HASH(oldcode,finchar,db->hshift); dictp = &db->dict[hval]; /* look for a free hash table entry */ if (dictp->codem1 < max_ent) { disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; } while (dictp->codem1 < max_ent); } /* * Invalidate previous hash table entry * assigned this code, and then take it over */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) { db->dict[dictp2->cptr].codem1 = BADCODEM1; } dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; db->lens[max_ent] = db->lens[oldcode]+1; /* Expand code size if needed. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { db->n_bits = ++n_bits; tgtbitno = 32-n_bits; } } oldcode = incode; } dmp->m_len = wptr - mtod(dmp, u_char *); /* * Keep the checkpoint right so that incompressible packets * clear the dictionary at the right times. */ db->bytes_out += ilen; db->in_count += explen; if (bsd_check(db) && db->debug) { printf("bsd_decomp%d: peer should have cleared dictionary\n", db->unit); } ++db->comp_count; db->comp_bytes += ilen + BSD_OVHD; ++db->uncomp_count; db->uncomp_bytes += explen; *dmpp = mret; return DECOMP_OK; #ifdef DEBUG bad: if (codelen <= 0) { printf("bsd_decomp%d: fell off end of chain ", db->unit); printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, db->dict[finchar].cptr, max_ent); } else if (dictp->codem1 != finchar-1) { printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar); printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, db->dict[finchar].cptr, dictp->codem1); } m_freem(mret); return DECOMP_FATALERROR; #endif /* DEBUG */ } #endif /* DO_BSD_COMPRESS */ slirp-1.0.17/src/ppp/bsd-comp.h0000644000175000017500000000370710115276024015255 0ustar roverrover/* * A dictionary for doing BSD compress. */ struct bsd_db { int totlen; /* length of this structure */ u_int hsize; /* size of the hash table */ u_char hshift; /* used in hash function */ u_char n_bits; /* current bits/code */ u_char maxbits; u_char debug; u_char unit; u_int16_t seqno; /* sequence # of next packet */ u_int hdrlen; /* header length to preallocate */ u_int mru; u_int maxmaxcode; /* largest valid code */ u_int max_ent; /* largest code in use */ u_int in_count; /* uncompressed bytes, aged */ u_int bytes_out; /* compressed bytes, aged */ u_int ratio; /* recent compression ratio */ u_int checkpoint; /* when to next check the ratio */ u_int clear_count; /* times dictionary cleared */ u_int incomp_count; /* incompressible packets */ u_int incomp_bytes; /* incompressible bytes */ u_int uncomp_count; /* uncompressed packets */ u_int uncomp_bytes; /* uncompressed bytes */ u_int comp_count; /* compressed packets */ u_int comp_bytes; /* compressed bytes */ u_int16_t *lens; /* array of lengths of codes */ struct bsd_dict { union { /* hash value */ u_int32_t fcode; struct { #ifdef WORDS_BIGENDIAN u_char pad; u_char suffix; /* last character of new code */ u_int16_t prefix; /* preceding code */ #else u_int16_t prefix; /* preceding code */ u_char suffix; /* last character of new code */ u_char pad; #endif } hs; } f; u_int16_t codem1; /* output of hash table -1 */ u_int16_t cptr; /* map code to hash table entry */ } dict[1]; }; slirp-1.0.17/src/ppp/ccp.c0000644000175000017500000003473310115276023014313 0ustar roverrover/* * ccp.c - PPP Compression Control Protocol. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. */ #ifndef lint static char rcsid[] = "$Id: ccp.c,v 1.10 1995/06/06 01:52:23 paulus Exp $"; #endif #include #include #include "ppp-comp.h" #include "pppd.h" #include "fsm.h" #include "ccp.h" fsm ccp_fsm[NUM_PPP]; ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */ ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */ ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */ /* * Callbacks for fsm code. */ static void ccp_resetci __P((fsm *)); static int ccp_cilen __P((fsm *)); static void ccp_addci __P((fsm *, u_char *, int *)); static int ccp_ackci __P((fsm *, u_char *, int)); static int ccp_nakci __P((fsm *, u_char *, int)); static int ccp_rejci __P((fsm *, u_char *, int)); static int ccp_reqci __P((fsm *, u_char *, int *, int)); static void ccp_up __P((fsm *)); static void ccp_down __P((fsm *)); static int ccp_extcode __P((fsm *, int, int, u_char *, int)); static void ccp_rack_timeout __P(()); static fsm_callbacks ccp_callbacks = { ccp_resetci, ccp_cilen, ccp_addci, ccp_ackci, ccp_nakci, ccp_rejci, ccp_reqci, ccp_up, ccp_down, NULL, NULL, NULL, NULL, ccp_extcode, "CCP" }; /* * Do we want / did we get any compression? */ #define ANY_COMPRESS(opt) ((opt).bsd_compress) /* * Local state (mainly for handling reset-reqs and reset-acks */ static int ccp_localstate[NUM_PPP]; #define RACK_PENDING 1 /* waiting for reset-ack */ #define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ #define RACKTIMEOUT 1 /* second */ /* * ccp_init - initialize CCP. */ void ccp_init(unit) int unit; { fsm *f = &ccp_fsm[unit]; f->unit = unit; f->protocol = PPP_CCP; f->callbacks = &ccp_callbacks; fsm_init(f); memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options)); ccp_wantoptions[0].bsd_compress = 1; ccp_wantoptions[0].bsd_bits = 12; /* default value */ ccp_allowoptions[0].bsd_compress = 1; ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS; } /* * ccp_open - CCP is allowed to come up. */ void ccp_open(unit) int unit; { fsm *f = &ccp_fsm[unit]; if (f->state != OPENED) ccp_flags_set(unit, 1, 0); if (!ANY_COMPRESS(ccp_wantoptions[unit])) f->flags |= OPT_SILENT; fsm_open(f); } /* * ccp_close - Terminate CCP. */ void ccp_close(unit) int unit; { ccp_flags_set(unit, 0, 0); fsm_close(&ccp_fsm[unit]); } /* * ccp_lowerup - we may now transmit CCP packets. */ void ccp_lowerup(unit) int unit; { fsm_lowerup(&ccp_fsm[unit]); } /* * ccp_lowerdown - we may not transmit CCP packets. */ void ccp_lowerdown(unit) int unit; { fsm_lowerdown(&ccp_fsm[unit]); } /* * ccp_input - process a received CCP packet. */ void ccp_input(unit, p, len) int unit; u_char *p; int len; { fsm *f = &ccp_fsm[unit]; int oldstate; /* * Check for a terminate-request so we can print a message. */ oldstate = f->state; fsm_input(f, p, len); if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) do_syslog(LOG_NOTICE, "Compression disabled by peer."); /* * If we get a terminate-ack and we're not asking for compression, * close CCP. */ if (oldstate == REQSENT && p[0] == TERMACK && !ANY_COMPRESS(ccp_gotoptions[unit])) ccp_close(unit); } /* * Handle a CCP-specific code. */ static int ccp_extcode(f, code, id, p, len) fsm *f; int code, id; u_char *p; int len; { switch (code) { case CCP_RESETREQ: if (f->state != OPENED) break; /* send a reset-ack, which the transmitter will see and reset its compression state. */ fsm_sdata(f, CCP_RESETACK, id, NULL, 0); break; case CCP_RESETACK: if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) { ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT); UNTIMEOUT(ccp_rack_timeout, (caddr_t) f); } break; default: return 0; } return 1; } /* * ccp_protrej - peer doesn't talk CCP. */ void ccp_protrej(unit) int unit; { ccp_flags_set(unit, 0, 0); fsm_lowerdown(&ccp_fsm[unit]); } /* * ccp_resetci - initialize at start of negotiation. */ static void ccp_resetci(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; u_char opt_buf[16]; *go = ccp_wantoptions[f->unit]; if (go->bsd_compress) { opt_buf[0] = CI_BSD_COMPRESS; opt_buf[1] = CILEN_BSD_COMPRESS; opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0)) go->bsd_compress = 0; } } /* * ccp_cilen - Return total length of our configuration info. */ static int ccp_cilen(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; return (go->bsd_compress? CILEN_BSD_COMPRESS: 0); } /* * ccp_addci - put our requests in a packet. */ static void ccp_addci(f, p, lenp) fsm *f; u_char *p; int *lenp; { ccp_options *go = &ccp_gotoptions[f->unit]; u_char *p0 = p; if (go->bsd_compress) { p[0] = CI_BSD_COMPRESS; p[1] = CILEN_BSD_COMPRESS; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0)) p += CILEN_BSD_COMPRESS; else go->bsd_compress = 0; } *lenp = p - p0; } /* * ccp_ackci - process a received configure-ack, and return * 1 iff the packet was OK. */ static int ccp_ackci(f, p, len) fsm *f; u_char *p; int len; { ccp_options *go = &ccp_gotoptions[f->unit]; if (go->bsd_compress) { if (len < CILEN_BSD_COMPRESS || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; } if (len != 0) return 0; return 1; } /* * ccp_nakci - process received configure-nak. * Returns 1 iff the nak was OK. */ static int ccp_nakci(f, p, len) fsm *f; u_char *p; int len; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options no; /* options we've seen already */ ccp_options try; /* options to ask for next time */ memset(&no, 0, sizeof(no)); try = *go; if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { no.bsd_compress = 1; /* * Peer wants us to use a different number of bits * or a different version. */ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) try.bsd_compress = 0; else if (BSD_NBITS(p[2]) < go->bsd_bits) try.bsd_bits = BSD_NBITS(p[2]); p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; } /* * Have a look at any remaining options...??? */ if (len != 0) return 0; if (f->state != OPENED) *go = try; return 1; } /* * ccp_rejci - reject some of our suggested compression methods. */ static int ccp_rejci(f, p, len) fsm *f; u_char *p; int len; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options try; /* options to request next time */ try = *go; if (go->bsd_compress && len >= CILEN_BSD_COMPRESS && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; try.bsd_compress = 0; p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; } if (len != 0) return 0; if (f->state != OPENED) *go = try; return 1; } /* * ccp_reqci - processed a received configure-request. * Returns CONFACK, CONFNAK or CONFREJ and the packet modified * appropriately. */ static int ccp_reqci(f, p, lenp, dont_nak) fsm *f; u_char *p; int *lenp; int dont_nak; { int ret, newret; u_char *p0, *retp; int len, clen, type, nb; ccp_options *ho = &ccp_hisoptions[f->unit]; ccp_options *ao = &ccp_allowoptions[f->unit]; ret = CONFACK; retp = p0 = p; len = *lenp; memset(ho, 0, sizeof(ccp_options)); while (len > 0) { newret = CONFACK; if (len < 2 || p[1] < 2 || p[1] > len) { /* length is bad */ clen = len; newret = CONFREJ; } else { type = p[0]; clen = p[1]; switch (type) { case CI_BSD_COMPRESS: if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { newret = CONFREJ; break; } ho->bsd_compress = 1; ho->bsd_bits = nb = BSD_NBITS(p[2]); if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION || nb > ao->bsd_bits) { newret = CONFNAK; nb = ao->bsd_bits; } else if (nb < BSD_MIN_BITS) { newret = CONFREJ; } else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) { if (nb > BSD_MIN_BITS) { --nb; newret = CONFNAK; } else newret = CONFREJ; } if (newret == CONFNAK && !dont_nak) { p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); } break; default: newret = CONFREJ; } } if (newret == CONFNAK && dont_nak) newret = CONFREJ; if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) { /* we're returning this option */ if (newret == CONFREJ && ret == CONFNAK) retp = p0; ret = newret; if (p != retp) BCOPY(p, retp, clen); retp += clen; } p += clen; len -= clen; } if (ret != CONFACK) *lenp = retp - p0; return ret; } /* * CCP has come up - inform the kernel driver. */ static void ccp_up(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options *ho = &ccp_hisoptions[f->unit]; ccp_flags_set(f->unit, 1, 1); if (go->bsd_compress || ho->bsd_compress) do_syslog(LOG_NOTICE, "%s enabled", go->bsd_compress? ho->bsd_compress? "Compression": "Receive compression": "Transmit compression"); } /* * CCP has gone down - inform the kernel driver. */ static void ccp_down(f) fsm *f; { if (ccp_localstate[f->unit] & RACK_PENDING) UNTIMEOUT(ccp_rack_timeout, (caddr_t) f); ccp_localstate[f->unit] = 0; ccp_flags_set(f->unit, 1, 0); } /* * Print the contents of a CCP packet. */ char *ccp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej", NULL, NULL, NULL, NULL, NULL, NULL, "ResetReq", "ResetAck", }; int ccp_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) __P((void *, char *, ...)); void *arg; { u_char *p0, *optend; int code, id, len; int optlen; p0 = p; if (plen < HEADERLEN) return 0; code = p[0]; id = p[1]; len = (p[2] << 8) + p[3]; if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *) && ccp_codenames[code-1] != NULL) printer(arg, " %s", ccp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; p += HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print list of possible compression methods */ while (len >= 2) { code = p[0]; optlen = p[1]; if (optlen < 2 || optlen > len) break; printer(arg, " <"); len -= optlen; optend = p + optlen; switch (code) { case CI_BSD_COMPRESS: if (optlen >= CILEN_BSD_COMPRESS) { printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), BSD_NBITS(p[2])); p += CILEN_BSD_COMPRESS; } break; } while (p < optend) printer(arg, " %.2x", *p++); printer(arg, ">"); } break; } /* dump out the rest of the packet in hex */ while (--len >= 0) printer(arg, " %.2x", *p++); return p - p0; } /* * We have received a packet that the decompressor failed to * decompress. Here we would expect to issue a reset-request, but * Motorola has a patent on resetting the compressor as a result of * detecting an error in the decompressed data after decompression. * (See US patent 5,130,993; international patent publication number * WO 91/10289; Australian patent 73296/91.) * * So we ask the kernel whether the error was detected after * decompression; if it was, we take CCP down, thus disabling * compression :-(, otherwise we issue the reset-request. */ void ccp_datainput(unit, pkt, len) int unit; u_char *pkt; int len; { fsm *f; f = &ccp_fsm[unit]; if (f->state == OPENED) { if (ccp_fatal_error(unit)) { /* * Disable compression by taking CCP down. */ do_syslog(LOG_ERR, "Lost compression sync: disabling compression"); ccp_close(unit); } else { /* * Send a reset-request to reset the peer's compressor. * We don't do that if we are still waiting for an * acknowledgement to a previous reset-request. */ if (!(ccp_localstate[f->unit] & RACK_PENDING)) { fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT); ccp_localstate[f->unit] |= RACK_PENDING; } else ccp_localstate[f->unit] |= RREQ_REPEAT; } } } /* * Timeout waiting for reset-ack. */ static void ccp_rack_timeout(arg) caddr_t arg; { fsm *f = (fsm *) arg; if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) { fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT); ccp_localstate[f->unit] &= ~RREQ_REPEAT; } else ccp_localstate[f->unit] &= ~RACK_PENDING; } slirp-1.0.17/src/ppp/ccp.h0000644000175000017500000000377210115276024014320 0ustar roverrover/* * ccp.h - Definitions for PPP Compression Control Protocol. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * * $Id: ccp.h,v 1.4 1995/04/24 06:00:54 paulus Exp $ */ typedef struct ccp_options { u_int bsd_compress: 1; /* do BSD Compress? */ u_short bsd_bits; /* # bits/code for BSD Compress */ } ccp_options; extern fsm ccp_fsm[]; extern ccp_options ccp_wantoptions[]; extern ccp_options ccp_gotoptions[]; extern ccp_options ccp_allowoptions[]; extern ccp_options ccp_hisoptions[]; void ccp_init __P((int unit)); void ccp_open __P((int unit)); void ccp_close __P((int unit)); void ccp_lowerup __P((int unit)); void ccp_lowerdown __P((int)); void ccp_input __P((int unit, u_char *pkt, int len)); void ccp_protrej __P((int unit)); int ccp_printpkt __P((u_char *pkt, int len, void (*printer) __P((void *, char *, ...)), void *arg)); void ccp_datainput __P((int unit, u_char *pkt, int len)); slirp-1.0.17/src/ppp/chap.c0000644000175000017500000004714210117211720014452 0ustar roverrover/* * chap.c - Cryptographic Handshake Authentication Protocol. * * Copyright (c) 1991 Gregory M. Christy. * 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 Gregory M. Christy. 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. */ #ifndef lint static char rcsid[] = "$Id: chap.c,v 1.7 1995/04/24 05:59:12 paulus Exp $"; #endif /* * TODO: */ #include #include #include #include #include #include "pppd.h" #include "chap.h" #include "md5.h" chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ static void ChapChallengeTimeout __P((caddr_t)); static void ChapResponseTimeout __P((caddr_t)); static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int)); static void ChapReceiveResponse __P((chap_state *, u_char *, int, int)); static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int)); static void ChapReceiveFailure __P((chap_state *, u_char *, int, int)); static void ChapSendStatus __P((chap_state *, int)); static void ChapSendChallenge __P((chap_state *)); static void ChapSendResponse __P((chap_state *)); static void ChapGenChallenge __P((chap_state *)); extern double drand48 __P((void)); extern void srand48 __P((long)); /* * ChapInit - Initialize a CHAP unit. */ void ChapInit(unit) int unit; { chap_state *cstate = &chap[unit]; BZERO(cstate, sizeof(*cstate)); cstate->unit = unit; cstate->clientstate = CHAPCS_INITIAL; cstate->serverstate = CHAPSS_INITIAL; cstate->timeouttime = CHAP_DEFTIMEOUT; cstate->max_transmits = CHAP_DEFTRANSMITS; /* random number generator is initialized in magic_init */ } /* * ChapAuthWithPeer - Authenticate us with our peer (start client). * */ void ChapAuthWithPeer(unit, our_name, digest) int unit; char *our_name; int digest; { chap_state *cstate = &chap[unit]; cstate->resp_name = our_name; cstate->resp_type = digest; if (cstate->clientstate == CHAPCS_INITIAL || cstate->clientstate == CHAPCS_PENDING) { /* lower layer isn't up - wait until later */ cstate->clientstate = CHAPCS_PENDING; return; } /* * We get here as a result of LCP coming up. * So even if CHAP was open before, we will * have to re-authenticate ourselves. */ cstate->clientstate = CHAPCS_LISTEN; } /* * ChapAuthPeer - Authenticate our peer (start server). */ void ChapAuthPeer(unit, our_name, digest) int unit; char *our_name; int digest; { chap_state *cstate = &chap[unit]; cstate->chal_name = our_name; cstate->chal_type = digest; if (cstate->serverstate == CHAPSS_INITIAL || cstate->serverstate == CHAPSS_PENDING) { /* lower layer isn't up - wait until later */ cstate->serverstate = CHAPSS_PENDING; return; } ChapGenChallenge(cstate); ChapSendChallenge(cstate); /* crank it up dude! */ cstate->serverstate = CHAPSS_INITIAL_CHAL; } /* * ChapChallengeTimeout - Timeout expired on sending challenge. */ static void ChapChallengeTimeout(arg) caddr_t arg; { chap_state *cstate = (chap_state *) arg; /* if we aren't sending challenges, don't worry. then again we */ /* probably shouldn't be here either */ if (cstate->serverstate != CHAPSS_INITIAL_CHAL && cstate->serverstate != CHAPSS_RECHALLENGE) return; if (cstate->chal_transmits >= cstate->max_transmits) { /* give up on peer */ do_syslog(LOG_ERR, "Peer failed to respond to CHAP challenge"); cstate->serverstate = CHAPSS_BADAUTH; auth_peer_fail(cstate->unit, PPP_CHAP); return; } ChapSendChallenge(cstate); /* Re-send challenge */ } /* * ChapResponseTimeout - Timeout expired on sending response. */ static void ChapResponseTimeout(arg) caddr_t arg; { chap_state *cstate = (chap_state *) arg; /* if we aren't sending a response, don't worry. */ if (cstate->clientstate != CHAPCS_RESPONSE) return; ChapSendResponse(cstate); /* re-send response */ } /* * ChapRechallenge - Time to challenge the peer again. */ static void ChapRechallenge(arg) caddr_t arg; { chap_state *cstate = (chap_state *) arg; /* if we aren't sending a response, don't worry. */ if (cstate->serverstate != CHAPSS_OPEN) return; ChapGenChallenge(cstate); ChapSendChallenge(cstate); cstate->serverstate = CHAPSS_RECHALLENGE; } /* * ChapLowerUp - The lower layer is up. * * Start up if we have pending requests. */ void ChapLowerUp(unit) int unit; { chap_state *cstate = &chap[unit]; if (cstate->clientstate == CHAPCS_INITIAL) cstate->clientstate = CHAPCS_CLOSED; else if (cstate->clientstate == CHAPCS_PENDING) cstate->clientstate = CHAPCS_LISTEN; if (cstate->serverstate == CHAPSS_INITIAL) cstate->serverstate = CHAPSS_CLOSED; else if (cstate->serverstate == CHAPSS_PENDING) { ChapGenChallenge(cstate); ChapSendChallenge(cstate); cstate->serverstate = CHAPSS_INITIAL_CHAL; } } /* * ChapLowerDown - The lower layer is down. * * Cancel all timeouts. */ void ChapLowerDown(unit) int unit; { chap_state *cstate = &chap[unit]; /* Timeout(s) pending? Cancel if so. */ if (cstate->serverstate == CHAPSS_INITIAL_CHAL || cstate->serverstate == CHAPSS_RECHALLENGE) UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate); else if (cstate->serverstate == CHAPSS_OPEN && cstate->chal_interval != 0) UNTIMEOUT(ChapRechallenge, (caddr_t) cstate); if (cstate->clientstate == CHAPCS_RESPONSE) UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); cstate->clientstate = CHAPCS_INITIAL; cstate->serverstate = CHAPSS_INITIAL; } /* * ChapProtocolReject - Peer doesn't grok CHAP. */ void ChapProtocolReject(unit) int unit; { chap_state *cstate = &chap[unit]; if (cstate->serverstate != CHAPSS_INITIAL && cstate->serverstate != CHAPSS_CLOSED) auth_peer_fail(unit, PPP_CHAP); if (cstate->clientstate != CHAPCS_INITIAL && cstate->clientstate != CHAPCS_CLOSED) auth_withpeer_fail(unit, PPP_CHAP); ChapLowerDown(unit); /* shutdown chap */ } /* * ChapInput - Input CHAP packet. */ void ChapInput(unit, inpacket, packet_len) int unit; u_char *inpacket; int packet_len; { chap_state *cstate = &chap[unit]; u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (packet_len < CHAP_HEADERLEN) { CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.")); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < CHAP_HEADERLEN) { CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.")); return; } if (len > packet_len) { CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.")); return; } len -= CHAP_HEADERLEN; /* * Action depends on code (as in fact it usually does :-). */ switch (code) { case CHAP_CHALLENGE: ChapReceiveChallenge(cstate, inp, id, len); break; case CHAP_RESPONSE: ChapReceiveResponse(cstate, inp, id, len); break; case CHAP_FAILURE: ChapReceiveFailure(cstate, inp, id, len); break; case CHAP_SUCCESS: ChapReceiveSuccess(cstate, inp, id, len); break; default: /* Need code reject? */ do_syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code); break; } } /* * ChapReceiveChallenge - Receive Challenge and send Response. */ static void ChapReceiveChallenge(cstate, inp, id, len) chap_state *cstate; u_char *inp; int id; int len; { int rchallenge_len; u_char *rchallenge; int secret_len; char secret[MAXSECRETLEN]; char rhostname[256]; MD5_CTX mdContext; CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id)); if (cstate->clientstate == CHAPCS_CLOSED || cstate->clientstate == CHAPCS_PENDING) { CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d", cstate->clientstate)); return; } if (len < 2) { CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); return; } GETCHAR(rchallenge_len, inp); len -= sizeof (u_char) + rchallenge_len; /* now name field length */ if (len < 0) { CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); return; } rchallenge = inp; INCPTR(rchallenge_len, inp); if (len >= sizeof(rhostname)) len = sizeof(rhostname) - 1; BCOPY(inp, rhostname, len); rhostname[len] = '\000'; CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s", rhostname)); /* get secret for authenticating ourselves with the specified host */ if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) { secret_len = 0; /* assume null secret if can't find one */ do_syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s", rhostname); } /* cancel response send timeout if necessary */ if (cstate->clientstate == CHAPCS_RESPONSE) UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); cstate->resp_id = id; cstate->resp_transmits = 0; /* generate MD based on negotiated type */ switch (cstate->resp_type) { case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ MD5Init(&mdContext); MD5Update(&mdContext, &cstate->resp_id, 1); MD5Update(&mdContext, secret, secret_len); MD5Update(&mdContext, rchallenge, rchallenge_len); MD5Final(&mdContext); BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE); cstate->resp_length = MD5_SIGNATURE_SIZE; break; default: CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type)); return; } ChapSendResponse(cstate); } /* * ChapReceiveResponse - Receive and process response. */ static void ChapReceiveResponse(cstate, inp, id, len) chap_state *cstate; u_char *inp; int id; int len; { u_char *remmd, remmd_len; int secret_len, old_state; int code; char rhostname[256]; u_char buf[256]; MD5_CTX mdContext; u_char msg[256]; char secret[MAXSECRETLEN]; CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id)); if (cstate->serverstate == CHAPSS_CLOSED || cstate->serverstate == CHAPSS_PENDING) { CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d", cstate->serverstate)); return; } if (id != cstate->chal_id) return; /* doesn't match ID of last challenge */ /* * If we have received a duplicate or bogus Response, * we have to send the same answer (Success/Failure) * as we did for the first Response we saw. */ if (cstate->serverstate == CHAPSS_OPEN) { ChapSendStatus(cstate, CHAP_SUCCESS); return; } if (cstate->serverstate == CHAPSS_BADAUTH) { ChapSendStatus(cstate, CHAP_FAILURE); return; } if (len < 2) { CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); return; } GETCHAR(remmd_len, inp); /* get length of MD */ remmd = inp; /* get pointer to MD */ INCPTR(remmd_len, inp); len -= sizeof (u_char) + remmd_len; if (len < 0) { CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); return; } UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate); if (len >= sizeof(rhostname)) len = sizeof(rhostname) - 1; BCOPY(inp, rhostname, len); rhostname[len] = '\000'; CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s", rhostname)); /* * Get secret for authenticating them with us, * do the hash ourselves, and compare the result. */ code = CHAP_FAILURE; if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) { do_syslog(LOG_WARNING, "No CHAP secret found for authenticating %s", rhostname); } else { /* generate MD based on negotiated type */ switch (cstate->chal_type) { case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ if (remmd_len != MD5_SIGNATURE_SIZE) break; /* it's not even the right length */ MD5Init(&mdContext); MD5Update(&mdContext, &cstate->chal_id, 1); MD5Update(&mdContext, secret, secret_len); MD5Update(&mdContext, cstate->challenge, cstate->chal_len); MD5Final(&mdContext); /* compare local and remote MDs and send the appropriate status */ if (memcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0) code = CHAP_SUCCESS; /* they are the same! */ break; default: CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type)); } } ChapSendStatus(cstate, code); if (code == CHAP_SUCCESS) { old_state = cstate->serverstate; cstate->serverstate = CHAPSS_OPEN; if (old_state == CHAPSS_INITIAL_CHAL) { auth_peer_success(cstate->unit, PPP_CHAP); } if (cstate->chal_interval != 0) TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval); } else { do_syslog(LOG_ERR, "CHAP peer authentication failed"); cstate->serverstate = CHAPSS_BADAUTH; auth_peer_fail(cstate->unit, PPP_CHAP); } } /* * ChapReceiveSuccess - Receive Success */ static void ChapReceiveSuccess(cstate, inp, id, len) chap_state *cstate; u_char *inp; u_char id; int len; { CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id)); if (cstate->clientstate == CHAPCS_OPEN) /* presumably an answer to a duplicate response */ return; if (cstate->clientstate != CHAPCS_RESPONSE) { /* don't know what this is */ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate)); return; } UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); /* * Print message. */ if (len > 0) PRINTMSG(inp, len); cstate->clientstate = CHAPCS_OPEN; auth_withpeer_success(cstate->unit, PPP_CHAP); } /* * ChapReceiveFailure - Receive failure. */ static void ChapReceiveFailure(cstate, inp, id, len) chap_state *cstate; u_char *inp; u_char id; int len; { u_char msglen; u_char *msg; CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id)); if (cstate->clientstate != CHAPCS_RESPONSE) { /* don't know what this is */ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate)); return; } UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate); /* * Print message. */ if (len > 0) PRINTMSG(inp, len); do_syslog(LOG_ERR, "CHAP authentication failed"); auth_withpeer_fail(cstate->unit, PPP_CHAP); } /* * ChapSendChallenge - Send an Authenticate challenge. */ static void ChapSendChallenge(cstate) chap_state *cstate; { u_char *outp; int chal_len, name_len; int outlen; chal_len = cstate->chal_len; name_len = strlen(cstate->chal_name); outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; outp = outpacket_buf; MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */ PUTCHAR(CHAP_CHALLENGE, outp); PUTCHAR(cstate->chal_id, outp); PUTSHORT(outlen, outp); PUTCHAR(chal_len, outp); /* put length of challenge */ BCOPY(cstate->challenge, outp, chal_len); INCPTR(chal_len, outp); BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id)); TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime); ++cstate->chal_transmits; } /* * ChapSendStatus - Send a status response (ack or nak). */ static void ChapSendStatus(cstate, code) chap_state *cstate; int code; { u_char *outp; int outlen, msglen; char msg[256]; if (code == CHAP_SUCCESS) snprintf(msg, sizeof(msg), "Welcome to %s.", hostname); else sprintf(msg, "I don't like you. Go 'way."); msglen = strlen(msg); outlen = CHAP_HEADERLEN + msglen; outp = outpacket_buf; MAKEHEADER(outp, PPP_CHAP); /* paste in a header */ PUTCHAR(code, outp); PUTCHAR(cstate->chal_id, outp); PUTSHORT(outlen, outp); BCOPY(msg, outp, msglen); output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, cstate->chal_id)); } /* * ChapGenChallenge is used to generate a pseudo-random challenge string of * a pseudo-random length between min_len and max_len. The challenge * string and its length are stored in *cstate, and various other fields of * *cstate are initialized. */ static void ChapGenChallenge(cstate) chap_state *cstate; { int chal_len; u_char *ptr = cstate->challenge; unsigned int i; /* pick a random challenge length between MIN_CHALLENGE_LENGTH and MAX_CHALLENGE_LENGTH */ chal_len = (unsigned) ((drand48() * (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) + MIN_CHALLENGE_LENGTH); cstate->chal_len = chal_len; cstate->chal_id = ++cstate->id; cstate->chal_transmits = 0; /* generate a random string */ for (i = 0; i < chal_len; i++ ) *ptr++ = (char) (drand48() * 0xff); } /* * ChapSendResponse - send a response packet with values as specified * in *cstate. */ /* ARGSUSED */ static void ChapSendResponse(cstate) chap_state *cstate; { u_char *outp; int outlen, md_len, name_len; md_len = cstate->resp_length; name_len = strlen(cstate->resp_name); outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; outp = outpacket_buf; MAKEHEADER(outp, PPP_CHAP); PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */ PUTSHORT(outlen, outp); /* packet length */ PUTCHAR(md_len, outp); /* length of MD */ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ INCPTR(md_len, outp); BCOPY(cstate->resp_name, outp, name_len); /* append our name */ /* send the packet */ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); cstate->clientstate = CHAPCS_RESPONSE; TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime); ++cstate->resp_transmits; } /* * ChapPrintPkt - print the contents of a CHAP packet. */ char *ChapCodenames[] = { "Challenge", "Response", "Success", "Failure" }; int ChapPrintPkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) __P((void *, char *, ...)); void *arg; { int code, id, len; int clen, nlen; u_char x; if (plen < CHAP_HEADERLEN) return 0; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < CHAP_HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) printer(arg, " %s", ChapCodenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= CHAP_HEADERLEN; switch (code) { case CHAP_CHALLENGE: case CHAP_RESPONSE: if (len < 1) break; clen = p[0]; if (len < clen + 1) break; ++p; nlen = len - clen - 1; printer(arg, " <"); for (; clen > 0; --clen) { GETCHAR(x, p); printer(arg, "%.2x", x); } printer(arg, ">, name = "); print_string((char *)p, nlen, printer, arg); break; case CHAP_FAILURE: case CHAP_SUCCESS: printer(arg, " "); print_string((char *)p, len, printer, arg); break; default: for (clen = len; clen > 0; --clen) { GETCHAR(x, p); printer(arg, " %.2x", x); } } return len + CHAP_HEADERLEN; } slirp-1.0.17/src/ppp/chap.h0000644000175000017500000000741510115276024014464 0ustar roverrover/* * chap.h - Cryptographic Handshake Authentication Protocol definitions. * * Copyright (c) 1991 Gregory M. Christy * 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 author. * * 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.3 1994/09/21 06:47:37 paulus Exp $ */ #ifndef __CHAP_INCLUDE__ /* Code + ID + length */ #define CHAP_HEADERLEN 4 /* * CHAP codes. */ #define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */ #define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ #define CHAP_CHALLENGE 1 #define CHAP_RESPONSE 2 #define CHAP_SUCCESS 3 #define CHAP_FAILURE 4 /* * Challenge lengths (for challenges we send) and other limits. */ #define MIN_CHALLENGE_LENGTH 32 #define MAX_CHALLENGE_LENGTH 64 #define MAX_RESPONSE_LENGTH 16 /* sufficient for MD5 */ /* * Each interface is described by a chap structure. */ typedef struct chap_state { int unit; /* Interface unit number */ int clientstate; /* Client state */ int serverstate; /* Server state */ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */ u_char chal_len; /* challenge length */ u_char chal_id; /* ID of last challenge */ u_char chal_type; /* hash algorithm for challenges */ u_char id; /* Current id */ char *chal_name; /* Our name to use with challenge */ int chal_interval; /* Time until we challenge peer again */ int timeouttime; /* Timeout time in seconds */ int max_transmits; /* Maximum # of challenge transmissions */ int chal_transmits; /* Number of transmissions of challenge */ int resp_transmits; /* Number of transmissions of response */ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */ u_char resp_length; /* length of response */ u_char resp_id; /* ID for response messages */ u_char resp_type; /* hash algorithm for responses */ char *resp_name; /* Our name to send with response */ } chap_state; /* * Client (peer) states. */ #define CHAPCS_INITIAL 0 /* Lower layer down, not opened */ #define CHAPCS_CLOSED 1 /* Lower layer up, not opened */ #define CHAPCS_PENDING 2 /* Auth us to peer when lower up */ #define CHAPCS_LISTEN 3 /* Listening for a challenge */ #define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */ #define CHAPCS_OPEN 5 /* We've received Success */ /* * Server (authenticator) states. */ #define CHAPSS_INITIAL 0 /* Lower layer down, not opened */ #define CHAPSS_CLOSED 1 /* Lower layer up, not opened */ #define CHAPSS_PENDING 2 /* Auth peer when lower up */ #define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */ #define CHAPSS_OPEN 4 /* We've sent a Success msg */ #define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */ #define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */ /* * Timeouts. */ #define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */ #define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ extern chap_state chap[]; void ChapInit __P((int)); void ChapAuthWithPeer __P((int, char *, int)); void ChapAuthPeer __P((int, char *, int)); void ChapLowerUp __P((int)); void ChapLowerDown __P((int)); void ChapInput __P((int, u_char *, int)); void ChapProtocolReject __P((int)); int ChapPrintPkt __P((u_char *, int, void (*) __P((void *, char *, ...)), void *)); #define __CHAP_INCLUDE__ #endif /* __CHAP_INCLUDE__ */ slirp-1.0.17/src/ppp/fsm.c0000644000175000017500000004117710115276023014333 0ustar roverrover/* * fsm.c - {Link, IP} Control Protocol Finite State Machine. * * 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. */ #ifndef lint static char rcsid[] = "$Id: fsm.c,v 1.8 1994/11/10 01:52:05 paulus Exp $"; #endif /* * TODO: * Randomize fsm id on link/init. * Deal with variable outgoing MTU. */ #include #include #include #include #include "pppd.h" #include "fsm.h" extern char *proto_name(); static void fsm_timeout __P((caddr_t)); static void fsm_rconfreq __P((fsm *, int, u_char *, int)); static void fsm_rconfack __P((fsm *, int, u_char *, int)); static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int)); static void fsm_rtermreq __P((fsm *, int)); static void fsm_rtermack __P((fsm *)); static void fsm_rcoderej __P((fsm *, u_char *, int)); static void fsm_sconfreq __P((fsm *, int)); #define PROTO_NAME(f) ((f)->callbacks->proto_name) int peer_mru[NUM_PPP]; /* * fsm_init - Initialize fsm. * * Initialize fsm state. */ void fsm_init(f) fsm *f; { f->state = INITIAL; f->flags = 0; f->id = 0; /* XXX Start with random id? */ f->timeouttime = DEFTIMEOUT; f->maxconfreqtransmits = DEFMAXCONFREQS; f->maxtermtransmits = DEFMAXTERMREQS; f->maxnakloops = DEFMAXNAKLOOPS; } /* * fsm_lowerup - The lower layer is up. */ void fsm_lowerup(f) fsm *f; { switch( f->state ){ case INITIAL: f->state = CLOSED; break; case STARTING: if( f->flags & OPT_SILENT ) f->state = STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = REQSENT; } break; default: FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", PROTO_NAME(f), f->state)); } } /* * fsm_lowerdown - The lower layer is down. * * Cancel all timeouts and inform upper layers. */ void fsm_lowerdown(f) fsm *f; { switch( f->state ){ case CLOSED: f->state = INITIAL; break; case STOPPED: f->state = STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case CLOSING: f->state = INITIAL; UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ break; case STOPPING: case REQSENT: case ACKRCVD: case ACKSENT: f->state = STARTING; UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ break; case OPENED: if( f->callbacks->down ) (*f->callbacks->down)(f); f->state = STARTING; break; default: FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", PROTO_NAME(f), f->state)); } } /* * fsm_open - Link is allowed to come up. */ void fsm_open(f) fsm *f; { switch( f->state ){ case INITIAL: f->state = STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case CLOSED: if( f->flags & OPT_SILENT ) f->state = STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = REQSENT; } break; case CLOSING: f->state = STOPPING; /* fall through */ case STOPPED: case OPENED: if( f->flags & OPT_RESTART ){ fsm_lowerdown(f); fsm_lowerup(f); } break; } } /* * fsm_close - Start closing connection. * * Cancel timeouts and either initiate close or possibly go directly to * the CLOSED state. */ void fsm_close(f) fsm *f; { switch( f->state ){ case STARTING: f->state = INITIAL; break; case STOPPED: f->state = CLOSED; break; case STOPPING: f->state = CLOSING; break; case REQSENT: case ACKRCVD: case ACKSENT: case OPENED: if( f->state != OPENED ) UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ else if( f->callbacks->down ) (*f->callbacks->down)(f); /* Inform upper layers we're down */ /* Init restart counter, send Terminate-Request */ f->retransmits = f->maxtermtransmits; fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); --f->retransmits; f->state = CLOSING; break; } } /* * fsm_timeout - Timeout expired. */ static void fsm_timeout(arg) caddr_t arg; { fsm *f = (fsm *) arg; switch (f->state) { case CLOSING: case STOPPING: if( f->retransmits <= 0 ){ /* * We've waited for an ack long enough. Peer probably heard us. */ f->state = (f->state == CLOSING)? CLOSED: STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Send Terminate-Request */ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); --f->retransmits; } break; case REQSENT: case ACKRCVD: case ACKSENT: if (f->retransmits <= 0) { do_syslog(LOG_WARNING, "%s: timeout sending Config-Requests", PROTO_NAME(f)); f->state = STOPPED; if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Retransmit the configure-request */ if (f->callbacks->retransmit) (*f->callbacks->retransmit)(f); fsm_sconfreq(f, 1); /* Re-send Configure-Request */ if( f->state == ACKRCVD ) f->state = REQSENT; } break; default: FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); } } /* * fsm_input - Input packet. */ void fsm_input(f, inpacket, l) fsm *f; u_char *inpacket; int l; { u_char *inp, *outp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < HEADERLEN) { FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", f->protocol)); return; } if (len > l) { FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == INITIAL || f->state == STARTING ){ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state)); return; } /* * Action depends on code. */ switch (code) { case CONFREQ: fsm_rconfreq(f, id, inp, len); break; case CONFACK: fsm_rconfack(f, id, inp, len); break; case CONFNAK: case CONFREJ: fsm_rconfnakrej(f, code, id, inp, len); break; case TERMREQ: fsm_rtermreq(f, id); break; case TERMACK: fsm_rtermack(f); break; case CODEREJ: fsm_rcoderej(f, inp, len); break; default: if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); break; } } /* * fsm_rconfreq - Receive Configure-Request. */ static void fsm_rconfreq(f, id, inp, len) fsm *f; u_char id; u_char *inp; int len; { u_char *outp; int code, reject_if_disagree; FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); switch( f->state ){ case CLOSED: /* Go away, we're closed */ fsm_sdata(f, TERMACK, id, NULL, 0); return; case CLOSING: case STOPPING: return; case OPENED: /* Go down and restart negotiation */ if( f->callbacks->down ) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ break; case STOPPED: /* Negotiation started by our peer */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = REQSENT; break; } /* * Pass the requested configuration options * to protocol-specific code for checking. */ if (f->callbacks->reqci){ /* Check CI */ reject_if_disagree = (f->nakloops >= f->maxnakloops); code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); } else if (len) code = CONFREJ; /* Reject all CI */ else code = CONFACK; /* send the Ack, Nak or Rej to the peer */ fsm_sdata(f, code, id, inp, len); if (code == CONFACK) { if (f->state == ACKRCVD) { UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ f->state = OPENED; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ } else f->state = ACKSENT; f->nakloops = 0; } else { /* we sent CONFACK or CONFREJ */ if (f->state != ACKRCVD) f->state = REQSENT; if( code == CONFNAK ) ++f->nakloops; } } /* * fsm_rconfack - Receive Configure-Ack. */ static void fsm_rconfack(f, id, inp, len) fsm *f; int id; u_char *inp; int len; { FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.", PROTO_NAME(f), id)); if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){ /* Ack is bad - ignore it */ FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)", PROTO_NAME(f), len)); return; } f->seen_ack = 1; switch (f->state) { case CLOSED: case STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case REQSENT: f->state = ACKRCVD; f->retransmits = f->maxconfreqtransmits; break; case ACKRCVD: /* Huh? an extra valid Ack? oh well... */ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = REQSENT; break; case ACKSENT: UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ f->state = OPENED; f->retransmits = f->maxconfreqtransmits; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ break; case OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = REQSENT; break; } } /* * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. */ static void fsm_rconfnakrej(f, code, id, inp, len) fsm *f; int code, id; u_char *inp; int len; { int (*proc)(); FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.", PROTO_NAME(f), id)); if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; if (!proc || !proc(f, inp, len)) { /* Nak/reject is bad - ignore it */ FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)", PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); return; } f->seen_ack = 1; switch (f->state) { case CLOSED: case STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case REQSENT: case ACKSENT: /* They didn't agree to what we wanted - try another request */ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ fsm_sconfreq(f, 0); /* Send Configure-Request */ break; case ACKRCVD: /* Got a Nak/reject when we had already had an Ack?? oh well... */ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = REQSENT; break; case OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = REQSENT; break; } } /* * fsm_rtermreq - Receive Terminate-Req. */ static void fsm_rtermreq(f, id) fsm *f; int id; { FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); switch (f->state) { case ACKRCVD: case ACKSENT: f->state = REQSENT; /* Start over but keep trying */ break; case OPENED: do_syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f)); if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ f->retransmits = 0; f->state = STOPPING; TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); break; } fsm_sdata(f, TERMACK, id, NULL, 0); } /* * fsm_rtermack - Receive Terminate-Ack. */ static void fsm_rtermack(f) fsm *f; { FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); switch (f->state) { case CLOSING: UNTIMEOUT(fsm_timeout, (caddr_t) f); f->state = CLOSED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case STOPPING: UNTIMEOUT(fsm_timeout, (caddr_t) f); f->state = STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case ACKRCVD: f->state = REQSENT; break; case OPENED: if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); break; } } /* * fsm_rcoderej - Receive an Code-Reject. */ static void fsm_rcoderej(f, inp, len) fsm *f; u_char *inp; int len; { u_char code, id; FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); if (len < HEADERLEN) { FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); return; } GETCHAR(code, inp); GETCHAR(id, inp); do_syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); if( f->state == ACKRCVD ) f->state = REQSENT; } /* * fsm_protreject - Peer doesn't speak this protocol. * * Treat this as a catastrophic error (RXJ-). */ void fsm_protreject(f) fsm *f; { switch( f->state ){ case CLOSING: UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ /* fall through */ case CLOSED: f->state = CLOSED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case STOPPING: case REQSENT: case ACKRCVD: case ACKSENT: UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */ /* fall through */ case STOPPED: f->state = STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case OPENED: if( f->callbacks->down ) (*f->callbacks->down)(f); /* Init restart counter, send Terminate-Request */ f->retransmits = f->maxtermtransmits; fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0); TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); --f->retransmits; f->state = STOPPING; break; default: FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", PROTO_NAME(f), f->state)); } } /* * fsm_sconfreq - Send a Configure-Request. */ static void fsm_sconfreq(f, retransmit) fsm *f; int retransmit; { u_char *outp; int outlen, cilen; if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ /* Not currently negotiating - reset options */ if( f->callbacks->resetci ) (*f->callbacks->resetci)(f); f->nakloops = 0; } if( !retransmit ){ /* New request - reset retransmission counter, use new ID */ f->retransmits = f->maxconfreqtransmits; f->reqid = ++f->id; } f->seen_ack = 0; /* * Make up the request packet */ outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; if( f->callbacks->cilen && f->callbacks->addci ){ cilen = (*f->callbacks->cilen)(f); if( cilen > peer_mru[f->unit] - HEADERLEN ) cilen = peer_mru[f->unit] - HEADERLEN; if (f->callbacks->addci) (*f->callbacks->addci)(f, outp, &cilen); } else cilen = 0; /* send the request to our peer */ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); /* start the retransmit timer */ --f->retransmits; TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime); FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d", PROTO_NAME(f), f->reqid)); } /* * fsm_sdata - Send some data. * * Used for all packets sent to our peer by this module. */ void fsm_sdata(f, code, id, data, datalen) fsm *f; u_char code, id; u_char *data; int datalen; { u_char *outp; int outlen; /* Adjust length to be smaller than MTU */ outp = outpacket_buf; if (datalen > peer_mru[f->unit] - HEADERLEN) datalen = peer_mru[f->unit] - HEADERLEN; if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); outlen = datalen + HEADERLEN; MAKEHEADER(outp, f->protocol); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", PROTO_NAME(f), code, id)); } slirp-1.0.17/src/ppp/fsm.h0000644000175000017500000001117010115276024014327 0ustar roverrover/* * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. * * 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: fsm.h,v 1.5 1995/05/19 03:17:35 paulus Exp $ */ /* * Packet header = Code, id, length. */ #define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) /* * CP (LCP, IPCP, etc.) codes. */ #define CONFREQ 1 /* Configuration Request */ #define CONFACK 2 /* Configuration Ack */ #define CONFNAK 3 /* Configuration Nak */ #define CONFREJ 4 /* Configuration Reject */ #define TERMREQ 5 /* Termination Request */ #define TERMACK 6 /* Termination Ack */ #define CODEREJ 7 /* Code Reject */ /* * Each FSM is described by a fsm_callbacks and a fsm structure. */ typedef struct fsm_callbacks { void (*resetci)(); /* Reset our Configuration Information */ int (*cilen)(); /* Length of our Configuration Information */ void (*addci)(); /* Add our Configuration Information */ int (*ackci)(); /* ACK our Configuration Information */ int (*nakci)(); /* NAK our Configuration Information */ int (*rejci)(); /* Reject our Configuration Information */ int (*reqci)(); /* Request peer's Configuration Information */ void (*up)(); /* Called when fsm reaches OPENED state */ void (*down)(); /* Called when fsm leaves OPENED state */ void (*starting)(); /* Called when we want the lower layer */ void (*finished)(); /* Called when we don't want the lower layer */ void (*protreject)(); /* Called when Protocol-Reject received */ void (*retransmit)(); /* Retransmission is necessary */ int (*extcode)(); /* Called when unknown code received */ char *proto_name; /* String name for protocol (for messages) */ } fsm_callbacks; typedef struct fsm { int unit; /* Interface unit number */ int protocol; /* Data Link Layer Protocol field value */ int state; /* State */ int flags; /* Contains option bits */ u_char id; /* Current id */ u_char reqid; /* Current request id */ u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */ int timeouttime; /* Timeout time in milliseconds */ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */ int retransmits; /* Number of retransmissions left */ int maxtermtransmits; /* Maximum Terminate-Request transmissions */ int nakloops; /* Number of nak loops since last ack */ int maxnakloops; /* Maximum number of nak loops tolerated */ fsm_callbacks *callbacks; /* Callback routines */ } fsm; /* * Link states. */ #define INITIAL 0 /* Down, hasn't been opened */ #define STARTING 1 /* Down, been opened */ #define CLOSED 2 /* Up, hasn't been opened */ #define STOPPED 3 /* Open, waiting for down event */ #define CLOSING 4 /* Terminating the connection, not open */ #define STOPPING 5 /* Terminating, but open */ #define REQSENT 6 /* We've sent a Config Request */ #define ACKRCVD 7 /* We've received a Config Ack */ #define ACKSENT 8 /* We've sent a Config Ack */ #define OPENED 9 /* Connection available */ /* * Flags - indicate options controlling FSM operation */ #define OPT_PASSIVE 1 /* Don't die if we don't get a response */ #define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ #define OPT_SILENT 4 /* Wait for peer to speak first */ /* * Timeouts. */ #define DEFTIMEOUT 3 /* Timeout time in seconds */ #define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ #define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ #define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ /* * Prototypes */ void fsm_init __P((fsm *)); void fsm_lowerup __P((fsm *)); void fsm_lowerdown __P((fsm *)); void fsm_open __P((fsm *)); void fsm_close __P((fsm *)); void fsm_input __P((fsm *, u_char *, int)); void fsm_protreject __P((fsm *)); void fsm_sdata __P((fsm *, int, int, u_char *, int)); /* * Variables */ extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ slirp-1.0.17/src/ppp/ipcp.c0000644000175000017500000007735610117211720014504 0ustar roverrover/* * ipcp.c - PPP IP Control Protocol. * * 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. */ #ifndef lint static char rcsid[] = "$Id: ipcp.c,v 1.19 1995/06/01 01:30:38 paulus Exp $"; #endif /* * TODO: */ #include #include #include #include #include "pppd.h" #include "fsm.h" #include "ipcp.h" #include "pathnames.h" /* global vars */ ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ /* local vars */ static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ /* * Callbacks for fsm code. (CI = Configuration Information) */ static void ipcp_resetci __P((fsm *)); /* Reset our CI */ static int ipcp_cilen __P((fsm *)); /* Return length of our CI */ static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ static void ipcp_up __P((fsm *)); /* We're UP */ static void ipcp_down __P((fsm *)); /* We're DOWN */ static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */ fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_resetci, /* Reset our Configuration Information */ ipcp_cilen, /* Length of our Configuration Information */ ipcp_addci, /* Add our Configuration Information */ ipcp_ackci, /* ACK our Configuration Information */ ipcp_nakci, /* NAK our Configuration Information */ ipcp_rejci, /* Reject our Configuration Information */ ipcp_reqci, /* Request peer's Configuration Information */ ipcp_up, /* Called when fsm reaches OPENED state */ ipcp_down, /* Called when fsm leaves OPENED state */ NULL, /* Called when we want the lower layer up */ NULL, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ NULL, /* Called to handle protocol-specific codes */ "IPCP" /* String name of protocol */ }; /* * Lengths of configuration options. */ #define CILEN_VOID 2 #define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ #define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ #define CILEN_ADDR 6 /* new-style single address option */ #define CILEN_ADDRS 10 /* old-style dual address option */ #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") /* * Make a string representation of a network IP address. */ char * ip_ntoa(ipaddr) u_int32_t ipaddr; { static char b[64]; ipaddr = ntohl(ipaddr); sprintf(b, "%d.%d.%d.%d", (u_char)(ipaddr >> 24), (u_char)(ipaddr >> 16), (u_char)(ipaddr >> 8), (u_char)(ipaddr)); return b; } /* * ipcp_init - Initialize IPCP. */ void ipcp_init(unit) int unit; { fsm *f = &ipcp_fsm[unit]; ipcp_options *wo = &ipcp_wantoptions[unit]; ipcp_options *ao = &ipcp_allowoptions[unit]; f->unit = unit; f->protocol = PPP_IPCP; f->callbacks = &ipcp_callbacks; fsm_init(&ipcp_fsm[unit]); wo->neg_addr = 1; wo->old_addrs = 0; wo->ouraddr = 0; wo->hisaddr = 0; #ifdef USE_MS_DNS wo->dnsaddr[0] = wo->dnsaddr[1] = 0; wo->winsaddr[0] = wo->winsaddr[1] = 0; #endif wo->neg_vj = 1; wo->old_vj = 0; wo->vj_protocol = IPCP_VJ_COMP; wo->maxslotindex = MAX_STATES - 1; /* really max index */ wo->cflag = 1; /* max slots and slot-id compression are currently hardwired in */ /* ppp_if.c to 16 and 1, this needs to be changed (among other */ /* things) gmc */ ao->neg_addr = 1; ao->neg_vj = 1; ao->maxslotindex = MAX_STATES - 1; ao->cflag = 1; /* * XXX These control whether the user may use the proxyarp * and defaultroute options. */ ao->proxy_arp = 1; ao->default_route = 1; } /* * ipcp_open - IPCP is allowed to come up. */ void ipcp_open(unit) int unit; { fsm_open(&ipcp_fsm[unit]); } /* * ipcp_close - Take IPCP down. */ void ipcp_close(unit) int unit; { fsm_close(&ipcp_fsm[unit]); } /* * ipcp_lowerup - The lower layer is up. */ void ipcp_lowerup(unit) int unit; { fsm_lowerup(&ipcp_fsm[unit]); } /* * ipcp_lowerdown - The lower layer is down. */ void ipcp_lowerdown(unit) int unit; { fsm_lowerdown(&ipcp_fsm[unit]); } /* * ipcp_input - Input IPCP packet. */ void ipcp_input(unit, p, len) int unit; u_char *p; int len; { fsm_input(&ipcp_fsm[unit], p, len); } /* * ipcp_protrej - A Protocol-Reject was received for IPCP. * * Pretend the lower layer went down, so we shut up. */ void ipcp_protrej(unit) int unit; { fsm_lowerdown(&ipcp_fsm[unit]); } /* * ipcp_resetci - Reset our CI. */ static void ipcp_resetci(f) fsm *f; { ipcp_options *wo = &ipcp_wantoptions[f->unit]; wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; if (wo->ouraddr == 0) wo->accept_local = 1; if (wo->hisaddr == 0) wo->accept_remote = 1; ipcp_gotoptions[f->unit] = *wo; cis_received[f->unit] = 0; } /* * ipcp_cilen - Return length of our CI. */ static int ipcp_cilen(f) fsm *f; { ipcp_options *go = &ipcp_gotoptions[f->unit]; #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) return (LENCIADDR(go->neg_addr, go->old_addrs) + LENCIVJ(go->neg_vj, go->old_vj)); } /* * ipcp_addci - Add our desired CIs to a packet. */ static void ipcp_addci(f, ucp, lenp) fsm *f; u_char *ucp; int *lenp; { ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; ipcp_options *ho = &ipcp_hisoptions[f->unit]; int len = *lenp; #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ if (neg) { \ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ if (len >= vjlen) { \ PUTCHAR(opt, ucp); \ PUTCHAR(vjlen, ucp); \ PUTSHORT(val, ucp); \ if (!old) { \ PUTCHAR(maxslotindex, ucp); \ PUTCHAR(cflag, ucp); \ } \ len -= vjlen; \ } else \ neg = 0; \ } #define ADDCIADDR(opt, neg, old, val1, val2) \ if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ if (len >= addrlen) { \ u_int32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(addrlen, ucp); \ l = ntohl(val1); \ PUTLONG(l, ucp); \ if (old) { \ l = ntohl(val2); \ PUTLONG(l, ucp); \ } \ len -= addrlen; \ } else \ neg = 0; \ } /* * First see if we want to change our options to the old * forms because we have received old forms from the peer. */ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { /* use the old style of address negotiation */ go->neg_addr = 1; go->old_addrs = 1; } if (wo->neg_vj && !go->neg_vj && !go->old_vj) { /* try an older style of VJ negotiation */ if (cis_received[f->unit] == 0) { /* keep trying the new style until we see some CI from the peer */ go->neg_vj = 1; } else { /* use the old style only if the peer did */ if (ho->neg_vj && ho->old_vj) { go->neg_vj = 1; go->old_vj = 1; go->vj_protocol = ho->vj_protocol; } } } ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); *lenp -= len; } /* * ipcp_ackci - Ack our CIs. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */ static int ipcp_ackci(f, p, len) fsm *f; u_char *p; int len; { ipcp_options *go = &ipcp_gotoptions[f->unit]; u_short cilen, citype, cishort; u_int32_t cilong; u_char cimaxslotindex, cicflag; /* * CIs must be in exactly the same order that we sent... * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ if (neg) { \ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ if ((len -= vjlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != vjlen || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ if (!old) { \ GETCHAR(cimaxslotindex, p); \ if (cimaxslotindex != maxslotindex) \ goto bad; \ GETCHAR(cicflag, p); \ if (cicflag != cflag) \ goto bad; \ } \ } #define ACKCIADDR(opt, neg, old, val1, val2) \ if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ u_int32_t l; \ if ((len -= addrlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != addrlen || \ citype != opt) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (val1 != cilong) \ goto bad; \ if (old) { \ GETLONG(l, p); \ cilong = htonl(l); \ if (val2 != cilong) \ goto bad; \ } \ } ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1); bad: IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!")); return (0); } /* * ipcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPCP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */ static int ipcp_nakci(f, p, len) fsm *f; u_char *p; int len; { ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; u_int32_t ciaddr1, ciaddr2, l; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ BZERO(&no, sizeof(no)); try = *go; /* * Any Nak'd CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define NAKCIADDR(opt, neg, old, code) \ if (go->neg && \ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \ p[1] == cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ ciaddr1 = htonl(l); \ if (old) { \ GETLONG(l, p); \ ciaddr2 = htonl(l); \ no.old_addrs = 1; \ } else \ ciaddr2 = 0; \ no.neg = 1; \ code \ } #define NAKCIVJ(opt, neg, code) \ if (go->neg && \ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ } /* * Accept the peer's idea of {our,his} address, if different * from our idea, only if the accept_{local,remote} flag is set. */ NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, if (go->accept_local && ciaddr1) { /* Do we know our address? */ try.ouraddr = ciaddr1; IPCPDEBUG((LOG_INFO, "local IP address %s", ip_ntoa(ciaddr1))); } if (go->accept_remote && ciaddr2) { /* Does he know his? */ try.hisaddr = ciaddr2; IPCPDEBUG((LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr2))); } ); /* * Accept the peer's value of maxslotindex provided that it * is less than what we asked for. Turn off slot-ID compression * if the peer wants. Send old-style compress-type option if * the peer wants. */ NAKCIVJ(CI_COMPRESSTYPE, neg_vj, if (cilen == CILEN_VJ) { GETCHAR(cimaxslotindex, p); GETCHAR(cicflag, p); if (cishort == IPCP_VJ_COMP) { try.old_vj = 0; if (cimaxslotindex < go->maxslotindex) try.maxslotindex = cimaxslotindex; if (!cicflag) try.cflag = 0; } else { try.neg_vj = 0; } } else { if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { try.old_vj = 1; try.vj_protocol = cishort; } else { try.neg_vj = 0; } } ); /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If they want to negotiate about IP addresses, we comply. * If they want us to ask for compression, we refuse. */ while (len > CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if( (len -= cilen) < 0 ) goto bad; next = p + cilen - 2; switch (citype) { case CI_COMPRESSTYPE: if (go->neg_vj || no.neg_vj || (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) goto bad; no.neg_vj = 1; break; case CI_ADDRS: if (go->neg_addr && go->old_addrs || no.old_addrs || cilen != CILEN_ADDRS) goto bad; try.neg_addr = 1; try.old_addrs = 1; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; GETLONG(l, p); ciaddr2 = htonl(l); if (ciaddr2 && go->accept_remote) try.hisaddr = ciaddr2; no.old_addrs = 1; break; case CI_ADDR: if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) goto bad; try.old_addrs = 0; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; if (try.ouraddr != 0) try.neg_addr = 1; no.neg_addr = 1; break; } p = next; } /* If there is still anything left, this packet is bad. */ if (len != 0) goto bad; /* * OK, the Nak is good. Now we can update state. */ if (f->state != OPENED) *go = try; return 1; bad: IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!")); return 0; } /* * ipcp_rejci - Reject some of our CIs. */ static int ipcp_rejci(f, p, len) fsm *f; u_char *p; int len; { ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char cimaxslotindex, ciflag, cilen; u_short cishort; u_int32_t cilong; ipcp_options try; /* options to request next time */ try = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define REJCIADDR(opt, neg, old, val1, val2) \ if (go->neg && \ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ p[1] == cilen && \ p[0] == opt) { \ u_int32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != val1) \ goto bad; \ if (old) { \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != val2) \ goto bad; \ } \ try.neg = 0; \ } #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ if (go->neg && \ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ len >= p[1] && \ p[0] == opt) { \ len -= p[1]; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ if (!old) { \ GETCHAR(cimaxslotindex, p); \ if (cimaxslotindex != maxslot) \ goto bad; \ GETCHAR(ciflag, p); \ if (ciflag != cflag) \ goto bad; \ } \ try.neg = 0; \ } REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != OPENED) *go = try; return 1; bad: IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!")); return 0; } /* * ipcp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. */ static int ipcp_reqci(f, inp, len, reject_if_disagree) fsm *f; u_char *inp; /* Requested CIs */ int *len; /* Length of requested CIs */ int reject_if_disagree; { ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *ho = &ipcp_hisoptions[f->unit]; ipcp_options *ao = &ipcp_allowoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *ucp = inp; /* Pointer to current output char */ int l = *len; /* Length left */ u_char maxslotindex, cflag; extern struct in_addr dns_addr, dns2_addr; /* @@Hack */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_ADDRS: IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS ")); if (!ao->neg_addr || cilen != CILEN_ADDRS) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } /* * If he has no address, or if we both have his address but * disagree about it, then NAK it with our idea. * In particular, if we don't know his address, but he does, * then accept it. */ GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1))); if (ciaddr1 != wo->hisaddr && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } } else if (ciaddr1 == 0 && wo->hisaddr == 0) { /* * If neither we nor he knows his address, reject the option. */ orc = CONFREJ; wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ break; } /* * If he doesn't know our address, or if we both have our address * but disagree about it, then NAK it with our idea. */ GETLONG(tl, p); /* Parse destination address (ours) */ ciaddr2 = htonl(tl); IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2))); if (ciaddr2 != wo->ouraddr) { if (ciaddr2 == 0 || !wo->accept_local) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->ouraddr); PUTLONG(tl, p); } } else { go->ouraddr = ciaddr2; /* accept peer's idea */ } } ho->neg_addr = 1; ho->old_addrs = 1; ho->hisaddr = ciaddr1; ho->ouraddr = ciaddr2; break; case CI_ADDR: IPCPDEBUG((LOG_INFO, "ipcp: received ADDR ")); if (!ao->neg_addr || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } /* * If he has no address, or if we both have his address but * disagree about it, then NAK it with our idea. * In particular, if we don't know his address, but he does, * then accept it. */ GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1))); if (ciaddr1 != wo->hisaddr && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } } else if (ciaddr1 == 0 && wo->hisaddr == 0) { /* * Don't ACK an address of 0.0.0.0 - reject it instead. */ orc = CONFREJ; wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ break; } ho->neg_addr = 1; ho->hisaddr = ciaddr1; break; #ifdef USE_MS_DNS /* Handle Microsoft DNS Stuff */ case CI_MS_DNS1: IPCPDEBUG((LOG_INFO, "ipcp: received DNS Request ")); /* If we do not have a DNS address then we cannot send it */ wo->dnsaddr[0]=dns_addr.s_addr; wo->dnsaddr[1]=dns2_addr.s_addr; if (wo->dnsaddr[0] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ IPCPDEBUG((LOG_INFO, "DNS failed due to %d, %d, %d", wo->dnsaddr[0], cilen, CILEN_ADDR)); orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl,p); if (htonl(tl) != wo->dnsaddr[0]) { DECPTR(sizeof (long),p); tl = ntohl(wo->dnsaddr[0]); PUTLONG(tl, p); orc = CONFNAK; } break; case CI_MS_WINS1: IPCPDEBUG((LOG_INFO, "ipcp: received WINS Request ")); /* If we do not have a WINS address then we cannot send it */ if (wo->winsaddr[0] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl,p); if (htonl(tl) != wo->winsaddr[0]) { DECPTR(sizeof (long),p); tl = ntohl(wo->winsaddr[0]); PUTLONG(tl, p); orc = CONFNAK; } break; case CI_MS_DNS2: IPCPDEBUG((LOG_INFO, "ipcp: received DNS Request ")); /* If we do not have a DNS address then we cannot send it */ if (wo->dnsaddr[0] == 0 || /* Yes, this is the first one! */ cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl,p); if (htonl(tl) != wo->dnsaddr[1]) { /* and this is the 2nd one */ DECPTR(sizeof (long),p); tl = ntohl(wo->dnsaddr[1]); PUTLONG(tl, p); orc = CONFNAK; } break; case CI_MS_WINS2: IPCPDEBUG((LOG_INFO, "ipcp: received WINS Request ")); /* If we do not have a WINS address then we cannot send it */ if (wo->winsaddr[0] == 0 || /* Yes, this is the first one! */ cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl,p); if (htonl(tl) != wo->winsaddr[1]) { /* and this is the 2nd one */ DECPTR(sizeof (long),p); tl = ntohl(wo->winsaddr[1]); PUTLONG(tl, p); orc = CONFNAK; } break; #endif case CI_COMPRESSTYPE: IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE ")); if (!ao->neg_vj || (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { orc = CONFREJ; break; } GETSHORT(cishort, p); IPCPDEBUG((LOG_INFO, "(%d)", cishort)); if (!(cishort == IPCP_VJ_COMP || (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { orc = CONFREJ; break; } ho->neg_vj = 1; ho->vj_protocol = cishort; if (cilen == CILEN_VJ) { GETCHAR(maxslotindex, p); if (maxslotindex > ao->maxslotindex) { orc = CONFNAK; if (!reject_if_disagree){ DECPTR(1, p); PUTCHAR(ao->maxslotindex, p); } } GETCHAR(cflag, p); if (cflag && !ao->cflag) { orc = CONFNAK; if (!reject_if_disagree){ DECPTR(1, p); PUTCHAR(wo->cflag, p); } } ho->maxslotindex = maxslotindex; ho->cflag = cflag; } else { ho->old_vj = 1; ho->maxslotindex = MAX_STATES - 1; ho->cflag = 1; } break; default: orc = CONFREJ; break; } endswitch: IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc))); if (orc == CONFACK && /* Good CI */ rc != CONFACK) /* but prior CI wasn't? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree) /* Getting fed up with sending NAKs? */ orc = CONFREJ; /* Get tough if so */ else { if (rc == CONFREJ) /* Rejecting prior CI? */ continue; /* Don't send this one */ if (rc == CONFACK) { /* Ack'd all prior CIs? */ rc = CONFNAK; /* Not anymore... */ ucp = inp; /* Backup */ } } } if (orc == CONFREJ && /* Reject this CI */ rc != CONFREJ) { /* but no prior ones? */ rc = CONFREJ; ucp = inp; /* Backup */ } /* Need to move CI? */ if (ucp != cip) BCOPY(cip, ucp, cilen); /* Move it */ /* Update output pointer */ INCPTR(cilen, ucp); } /* * If we aren't rejecting this packet, and we want to negotiate * their address, and they didn't send their address, then we * send a NAK with a CI_ADDR option appended. We assume the * input buffer is long enough that we can append the extra * option safely. */ if (rc != CONFREJ && !ho->neg_addr && wo->req_addr && !reject_if_disagree) { if (rc == CONFACK) { rc = CONFNAK; ucp = inp; /* reset pointer */ wo->req_addr = 0; /* don't ask again */ } PUTCHAR(CI_ADDR, ucp); PUTCHAR(CILEN_ADDR, ucp); tl = ntohl(wo->hisaddr); PUTLONG(tl, ucp); } *len = ucp - inp; /* Compute output length */ IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc))); return (rc); /* Return final code */ } /* * ipcp_up - IPCP has come UP. * * Configure the IP network interface appropriately and bring it up. */ static void ipcp_up(f) fsm *f; { u_int32_t mask; ipcp_options *ho = &ipcp_hisoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; IPCPDEBUG((LOG_INFO, "ipcp: up")); go->default_route = 0; go->proxy_arp = 0; /* * We must have a non-zero IP address for both ends of the link. */ if (!ho->neg_addr) ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr; if (ho->hisaddr == 0) { do_syslog(LOG_ERR, "Could not determine remote IP address"); ipcp_close(f->unit); return; } if (go->ouraddr == 0) { do_syslog(LOG_ERR, "Could not determine local IP address"); ipcp_close(f->unit); return; } /* * Check that the peer is allowed to use the IP address it wants. */ if (!auth_ip_addr(f->unit, ho->hisaddr)) { do_syslog(LOG_ERR, "Peer is not authorized to use remote address %s", ip_ntoa(ho->hisaddr)); ipcp_close(f->unit); return; } do_syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr)); do_syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr)); /* * Set IP addresses and (if specified) netmask. */ mask = GetMask(go->ouraddr); if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { IPCPDEBUG((LOG_WARNING, "sifaddr failed")); ipcp_close(f->unit); return; } /* set tcp compression */ sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); /* bring the interface up for IP */ if (!sifup(f->unit)) { IPCPDEBUG((LOG_WARNING, "sifup failed")); ipcp_close(f->unit); return; } /* assign a default route through the interface if required */ if (ipcp_wantoptions[f->unit].default_route) if (sifdefaultroute(f->unit, ho->hisaddr)) go->default_route = 1; /* Make a proxy ARP entry if requested. */ if (ipcp_wantoptions[f->unit].proxy_arp) if (sifproxyarp(f->unit, ho->hisaddr)) go->proxy_arp = 1; /* * Execute the ip-up script, like this: * /etc/ppp/ip-up interface tty speed local-IP remote-IP */ ipcp_script(f, _PATH_IPUP); } /* * ipcp_down - IPCP has gone DOWN. * * Take the IP network interface down, clear its addresses * and delete routes through it. */ static void ipcp_down(f) fsm *f; { u_int32_t ouraddr, hisaddr; IPCPDEBUG((LOG_INFO, "ipcp: down")); ouraddr = ipcp_gotoptions[f->unit].ouraddr; hisaddr = ipcp_hisoptions[f->unit].hisaddr; if (ipcp_gotoptions[f->unit].proxy_arp) cifproxyarp(f->unit, hisaddr); if (ipcp_gotoptions[f->unit].default_route) cifdefaultroute(f->unit, hisaddr); sifdown(f->unit); cifaddr(f->unit, ouraddr, hisaddr); /* Execute the ip-down script */ ipcp_script(f, _PATH_IPDOWN); } /* * ipcp_script - Execute a script with arguments * interface-name tty-name speed local-IP remote-IP. */ static void ipcp_script(f, script) fsm *f; char *script; { char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; snprintf(strspeed, sizeof(strspeed), "%d", baud_rate); strncpy2(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr), sizeof(strlocal)); strncpy2(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr), sizeof(strremote)); argv[0] = script; argv[1] = ifname; argv[2] = devnam; argv[3] = strspeed; argv[4] = strlocal; argv[5] = strremote; argv[6] = ipparam; argv[7] = NULL; run_program(script, argv, 0); } /* * ipcp_printpkt - print the contents of an IPCP packet. */ char *ipcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej" }; int ipcp_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer)(); void *arg; { int code, id, len, olen; u_char *pstart, *optend; u_short cishort; u_int32_t cilong; if (plen < HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *)) printer(arg, " %s", ipcp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print option list */ while (len >= 2) { GETCHAR(code, p); GETCHAR(olen, p); p -= 2; if (olen < 2 || olen > len) { break; } printer(arg, " <"); len -= olen; optend = p + olen; switch (code) { case CI_ADDRS: if (olen == CILEN_ADDRS) { p += 2; GETLONG(cilong, p); printer(arg, "addrs %s", ip_ntoa(htonl(cilong))); GETLONG(cilong, p); printer(arg, " %s", ip_ntoa(htonl(cilong))); } break; case CI_COMPRESSTYPE: if (olen >= CILEN_COMPRESS) { p += 2; GETSHORT(cishort, p); printer(arg, "compress "); switch (cishort) { case IPCP_VJ_COMP: printer(arg, "VJ"); break; case IPCP_VJ_COMP_OLD: printer(arg, "old-VJ"); break; default: printer(arg, "0x%x", cishort); } } break; case CI_ADDR: if (olen == CILEN_ADDR) { p += 2; GETLONG(cilong, p); printer(arg, "addr %s", ip_ntoa(htonl(cilong))); } break; } while (p < optend) { GETCHAR(code, p); printer(arg, " %.2x", code); } printer(arg, ">"); } break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } slirp-1.0.17/src/ppp/ipcp.h0000644000175000017500000000612410115276024014500 0ustar roverrover/* * ipcp.h - IP Control Protocol definitions. * * 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: ipcp.h,v 1.5 1994/09/21 06:47:37 paulus Exp $ */ /* * Options. */ #define CI_ADDRS 1 /* IP Addresses */ #define CI_COMPRESSTYPE 2 /* Compression Type */ #define CI_ADDR 3 #define CI_MS_DNS1 129 /* Primary DNS value */ #define CI_MS_WINS1 130 /* Primary WINS value */ #define CI_MS_DNS2 131 /* Secondary DNS value */ #define CI_MS_WINS2 132 /* Secondary WINS value */ #define MAX_STATES 16 /* from slcompress.h */ #define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ #define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ #define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ /* maxslot and slot number compression) */ #define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ #define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ /* compression option*/ typedef struct ipcp_options { int neg_addr : 1; /* Negotiate IP Address? */ int old_addrs : 1; /* Use old (IP-Addresses) option? */ int req_addr : 1; /* Ask peer to send IP address? */ int default_route : 1; /* Assign default route through interface? */ int proxy_arp : 1; /* Make proxy ARP entry for peer? */ int neg_vj : 1; /* Van Jacobson Compression? */ int old_vj : 1; /* use old (short) form of VJ option? */ int accept_local : 1; /* accept peer's value for ouraddr */ int accept_remote : 1; /* accept peer's value for hisaddr */ u_short vj_protocol; /* protocol value to use in VJ option */ u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */ u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ #ifdef USE_MS_DNS u_int32_t dnsaddr[2]; /* Primary and secondary DNS entries */ u_int32_t winsaddr[2]; /* Primary and secondary WINS entries */ #endif } ipcp_options; extern fsm ipcp_fsm[]; extern ipcp_options ipcp_wantoptions[]; extern ipcp_options ipcp_gotoptions[]; extern ipcp_options ipcp_allowoptions[]; extern ipcp_options ipcp_hisoptions[]; void ipcp_init __P((int)); void ipcp_open __P((int)); void ipcp_close __P((int)); void ipcp_lowerup __P((int)); void ipcp_lowerdown __P((int)); void ipcp_input __P((int, u_char *, int)); void ipcp_protrej __P((int)); int ipcp_printpkt __P((u_char *, int, void (*)(), void *)); slirp-1.0.17/src/ppp/lcp.c0000644000175000017500000012352510115276024014323 0ustar roverrover/* * lcp.c - PPP Link Control Protocol. * * 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. */ #ifndef lint static char rcsid[] = "$Id: lcp.c,v 1.20 1995/06/30 01:47:15 paulus Exp $"; #endif /* * TODO: */ #include #include #include #include #include #include #include "pppd.h" #include "fsm.h" #include "lcp.h" #include "magic.h" #include "chap.h" #include "upap.h" #include "ipcp.h" /* global vars */ fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */ static u_int32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ static u_int32_t lcp_echo_number = 0; /* ID number of next echo frame */ static u_int32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ /* * Callbacks for fsm code. (CI = Configuration Information) */ static void lcp_resetci __P((fsm *)); /* Reset our CI */ static int lcp_cilen __P((fsm *)); /* Return length of our CI */ static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */ static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */ static void lcp_up __P((fsm *)); /* We're UP */ static void lcp_down __P((fsm *)); /* We're DOWN */ static void lcp_starting __P((fsm *)); /* We need lower layer up */ static void lcp_finished __P((fsm *)); /* We need lower layer down */ static int lcp_extcode __P((fsm *, int, int, u_char *, int)); static void lcp_rprotrej __P((fsm *, u_char *, int)); /* * routines to send LCP echos to peer */ static void lcp_echo_lowerup __P((int)); static void lcp_echo_lowerdown __P((int)); static void LcpEchoTimeout __P((caddr_t)); static void lcp_received_echo_reply __P((fsm *, int, u_char *, int)); static void LcpSendEchoRequest __P((fsm *)); static void LcpLinkFailure __P((fsm *)); static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ lcp_resetci, /* Reset our Configuration Information */ lcp_cilen, /* Length of our Configuration Information */ lcp_addci, /* Add our Configuration Information */ lcp_ackci, /* ACK our Configuration Information */ lcp_nakci, /* NAK our Configuration Information */ lcp_rejci, /* Reject our Configuration Information */ lcp_reqci, /* Request peer's Configuration Information */ lcp_up, /* Called when fsm reaches OPENED state */ lcp_down, /* Called when fsm leaves OPENED state */ lcp_starting, /* Called when we want the lower layer up */ lcp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ lcp_extcode, /* Called to handle LCP-specific codes */ "LCP" /* String name of protocol */ }; int lcp_loopbackfail = DEFLOOPBACKFAIL; /* * Length of each type of configuration option (in octets) */ #define CILEN_VOID 2 #define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ #define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ #define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ #define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") /* * lcp_init - Initialize LCP. */ void lcp_init(unit) int unit; { fsm *f = &lcp_fsm[unit]; lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *ao = &lcp_allowoptions[unit]; f->unit = unit; f->protocol = PPP_LCP; f->callbacks = &lcp_callbacks; fsm_init(f); wo->passive = 0; wo->silent = 1; /* Silent by default */ wo->restart = 0; /* Set to 1 in kernels or multi-line implementations */ wo->neg_mru = 1; wo->mru = DEFMRU; wo->neg_asyncmap = 0; wo->asyncmap = 0; wo->neg_chap = 0; /* Set to 1 on server */ wo->neg_upap = 0; /* Set to 1 on server */ wo->chap_mdtype = CHAP_DIGEST_MD5; wo->neg_magicnumber = 1; wo->neg_pcompression = 1; wo->neg_accompression = 1; wo->neg_lqr = 0; /* no LQR implementation yet */ ao->neg_mru = 1; ao->mru = MAXMRU; ao->neg_asyncmap = 1; ao->asyncmap = 0; ao->neg_chap = 1; ao->chap_mdtype = CHAP_DIGEST_MD5; ao->neg_upap = 1; ao->neg_magicnumber = 1; ao->neg_pcompression = 1; ao->neg_accompression = 1; ao->neg_lqr = 0; /* no LQR implementation yet */ memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); xmit_accm[unit][3] = 0x60000000; } /* * lcp_open - LCP is allowed to come up. */ void lcp_open(unit) int unit; { fsm *f = &lcp_fsm[unit]; lcp_options *wo = &lcp_wantoptions[unit]; f->flags = 0; if (wo->passive) f->flags |= OPT_PASSIVE; if (wo->silent) f->flags |= OPT_SILENT; fsm_open(f); } /* * lcp_close - Take LCP down. */ void lcp_close(unit) int unit; { fsm *f = &lcp_fsm[unit]; if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { /* * This action is not strictly according to the FSM in RFC1548, * but it does mean that the program terminates if you do a * lcp_close(0) in passive/silent mode when a connection hasn't * been established. */ f->state = CLOSED; lcp_finished(f); } else fsm_close(&lcp_fsm[unit]); } /* * lcp_lowerup - The lower layer is up. */ void lcp_lowerup(unit) int unit; { sifdown(unit); ppp_set_xaccm(unit, xmit_accm[unit]); ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0); ppp_recv_config(unit, PPP_MRU, 0x00000000, 0, 0); peer_mru[unit] = PPP_MRU; lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0]; fsm_lowerup(&lcp_fsm[unit]); } /* * lcp_lowerdown - The lower layer is down. */ void lcp_lowerdown(unit) int unit; { fsm_lowerdown(&lcp_fsm[unit]); } /* * lcp_input - Input LCP packet. */ void lcp_input(unit, p, len) int unit; u_char *p; int len; { int oldstate; fsm *f = &lcp_fsm[unit]; lcp_options *go = &lcp_gotoptions[f->unit]; oldstate = f->state; fsm_input(f, p, len); if (oldstate == REQSENT && f->state == ACKSENT) { /* * The peer will probably send us an ack soon and then * immediately start sending packets with the negotiated * options. So as to be ready when that happens, we set * our receive side to accept packets as negotiated now. */ ppp_recv_config(f->unit, PPP_MRU, go->neg_asyncmap? go->asyncmap: 0x00000000, go->neg_pcompression, go->neg_accompression); } } /* * lcp_extcode - Handle a LCP-specific code. */ static int lcp_extcode(f, code, id, inp, len) fsm *f; int code, id; u_char *inp; int len; { u_char *magp; switch( code ){ case PROTREJ: lcp_rprotrej(f, inp, len); break; case ECHOREQ: if (f->state != OPENED) break; LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id)); magp = inp; PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); fsm_sdata(f, ECHOREP, id, inp, len); break; case ECHOREP: lcp_received_echo_reply(f, id, inp, len); break; case DISCREQ: break; default: return 0; } return 1; } /* * lcp_rprotrej - Receive an Protocol-Reject. * * Figure out which protocol is rejected and inform it. */ static void lcp_rprotrej(f, inp, len) fsm *f; u_char *inp; int len; { u_short prot; LCPDEBUG((LOG_INFO, "lcp_rprotrej.")); if (len < sizeof (u_short)) { LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!")); return; } GETSHORT(prot, inp); LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!", prot)); /* * Protocol-Reject packets received in any state other than the LCP * OPENED state SHOULD be silently discarded. */ if( f->state != OPENED ){ LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d", f->state)); return; } DEMUXPROTREJ(f->unit, prot); /* Inform protocol */ } /* * lcp_protrej - A Protocol-Reject was received. */ /*ARGSUSED*/ void lcp_protrej(unit) int unit; { /* * Can't reject LCP! */ LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!")); fsm_protreject(&lcp_fsm[unit]); } /* * lcp_sprotrej - Send a Protocol-Reject for some protocol. */ void lcp_sprotrej(unit, p, len) int unit; u_char *p; int len; { /* * Send back the protocol and the information field of the * rejected packet. We only get here if LCP is in the OPENED state. */ p += 2; len -= 2; fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); } /* * lcp_resetci - Reset our CI. */ static void lcp_resetci(f) fsm *f; { lcp_wantoptions[f->unit].magicnumber = magic(); lcp_wantoptions[f->unit].numloops = 0; lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; peer_mru[f->unit] = PPP_MRU; } /* * lcp_cilen - Return length of our CI. */ static int lcp_cilen(f) fsm *f; { lcp_options *go = &lcp_gotoptions[f->unit]; #define LENCIVOID(neg) (neg ? CILEN_VOID : 0) #define LENCICHAP(neg) (neg ? CILEN_CHAP : 0) #define LENCISHORT(neg) (neg ? CILEN_SHORT : 0) #define LENCILONG(neg) (neg ? CILEN_LONG : 0) #define LENCILQR(neg) (neg ? CILEN_LQR: 0) /* * NB: we only ask for one of CHAP and UPAP, even if we will * accept either. */ return (LENCISHORT(go->neg_mru) + LENCILONG(go->neg_asyncmap) + LENCICHAP(go->neg_chap) + LENCISHORT(!go->neg_chap && go->neg_upap) + LENCILQR(go->neg_lqr) + LENCILONG(go->neg_magicnumber) + LENCIVOID(go->neg_pcompression) + LENCIVOID(go->neg_accompression)); } /* * lcp_addci - Add our desired CIs to a packet. */ static void lcp_addci(f, ucp, lenp) fsm *f; u_char *ucp; int *lenp; { lcp_options *go = &lcp_gotoptions[f->unit]; u_char *start_ucp = ucp; #define ADDCIVOID(opt, neg) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_VOID, ucp); \ } #define ADDCISHORT(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_SHORT, ucp); \ PUTSHORT(val, ucp); \ } #define ADDCICHAP(opt, neg, val, digest) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_CHAP, ucp); \ PUTSHORT(val, ucp); \ PUTCHAR(digest, ucp); \ } #define ADDCILONG(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LONG, ucp); \ PUTLONG(val, ucp); \ } #define ADDCILQR(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LQR, ucp); \ PUTSHORT(PPP_LQR, ucp); \ PUTLONG(val, ucp); \ } ADDCISHORT(CI_MRU, go->neg_mru, go->mru); ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap); ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); if (ucp - start_ucp != *lenp) { /* this should never happen, because peer_mtu should be 1500 */ do_syslog(LOG_ERR, "Bug in lcp_addci: wrong length"); } } /* * lcp_ackci - Ack our CIs. * This should not modify any state if the Ack is bad. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */ static int lcp_ackci(f, p, len) fsm *f; u_char *p; int len; { lcp_options *go = &lcp_gotoptions[f->unit]; u_char cilen, citype, cichar; u_short cishort; u_int32_t cilong; /* * CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define ACKCIVOID(opt, neg) \ if (neg) { \ if ((len -= CILEN_VOID) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_VOID || \ citype != opt) \ goto bad; \ } #define ACKCISHORT(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_SHORT) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_SHORT || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ } #define ACKCICHAP(opt, neg, val, digest) \ if (neg) { \ if ((len -= CILEN_CHAP) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_CHAP || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ GETCHAR(cichar, p); \ if (cichar != digest) \ goto bad; \ } #define ACKCILONG(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_LONG) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_LONG || \ citype != opt) \ goto bad; \ GETLONG(cilong, p); \ if (cilong != val) \ goto bad; \ } #define ACKCILQR(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_LQR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_LQR || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != PPP_LQR) \ goto bad; \ GETLONG(cilong, p); \ if (cilong != val) \ goto bad; \ } ACKCISHORT(CI_MRU, go->neg_mru, go->mru); ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap); ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1); bad: LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!")); return (0); } /* * lcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */ static int lcp_nakci(f, p, len) fsm *f; u_char *p; int len; { lcp_options *go = &lcp_gotoptions[f->unit]; lcp_options *wo = &lcp_wantoptions[f->unit]; u_char citype, cichar, *next; u_short cishort; u_int32_t cilong; lcp_options no; /* options we've seen Naks for */ lcp_options try; /* options to request next time */ int looped_back = 0; int cilen; BZERO(&no, sizeof(no)); try = *go; /* * Any Nak'd CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define NAKCIVOID(opt, neg, code) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ no.neg = 1; \ code \ } #define NAKCICHAP(opt, neg, code) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ no.neg = 1; \ code \ } #define NAKCISHORT(opt, neg, code) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ } #define NAKCILONG(opt, neg, code) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ no.neg = 1; \ code \ } #define NAKCILQR(opt, neg, code) \ if (go->neg && \ len >= CILEN_LQR && \ p[1] == CILEN_LQR && \ p[0] == opt) { \ len -= CILEN_LQR; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETLONG(cilong, p); \ no.neg = 1; \ code \ } /* * We don't care if they want to send us smaller packets than * we want. Therefore, accept any MRU less than what we asked for, * but then ignore the new value when setting the MRU in the kernel. * If they send us a bigger MRU than what we asked, accept it, up to * the limit of the default MRU we'd get if we didn't negotiate. */ NAKCISHORT(CI_MRU, neg_mru, if (cishort <= wo->mru || cishort < DEFMRU) try.mru = cishort; ); /* * Add any characters they want to our (receive-side) asyncmap. */ NAKCILONG(CI_ASYNCMAP, neg_asyncmap, try.asyncmap = go->asyncmap | cilong; ); /* * If they've nak'd our authentication-protocol, check whether * they are proposing a different protocol, or a different * hash algorithm for CHAP. */ if ((go->neg_chap || go->neg_upap) && len >= CILEN_SHORT && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT) { cilen = p[1]; INCPTR(2, p); GETSHORT(cishort, p); if (cishort == PPP_PAP && cilen == CILEN_SHORT) { /* * If they are asking for PAP, then they don't want to do CHAP. * If we weren't asking for CHAP, then we were asking for PAP, * in which case this Nak is bad. */ if (!go->neg_chap) goto bad; go->neg_chap = 0; } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { GETCHAR(cichar, p); if (go->neg_chap) { /* * We were asking for CHAP/MD5; they must want a different * algorithm. If they can't do MD5, we'll have to stop * asking for CHAP. */ if (cichar != go->chap_mdtype) go->neg_chap = 0; } else { /* * Stop asking for PAP if we were asking for it. */ go->neg_upap = 0; } } else { /* * We don't recognize what they're suggesting. * Stop asking for what we were asking for. */ if (go->neg_chap) go->neg_chap = 0; else go->neg_upap = 0; p += cilen - CILEN_SHORT; } } /* * Peer shouldn't send Nak for protocol compression or * address/control compression requests; they should send * a Reject instead. If they send a Nak, treat it as a Reject. */ if (!go->neg_chap ){ NAKCISHORT(CI_AUTHTYPE, neg_upap, try.neg_upap = 0; ); } /* * If they can't cope with our link quality protocol, we'll have * to stop asking for LQR. We haven't got any other protocol. * If they Nak the reporting period, take their value XXX ? */ NAKCILQR(CI_QUALITY, neg_lqr, if (cishort != PPP_LQR) try.neg_lqr = 0; else try.lqr_period = cilong; ); /* * Check for a looped-back line. */ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, try.magicnumber = magic(); looped_back = 1; ); NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, try.neg_pcompression = 0; ); NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, try.neg_accompression = 0; ); /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If we see an option that we requested, or one we've already seen * in this packet, then this packet is bad. * If we wanted to respond by starting to negotiate on the requested * option(s), we could, but we don't, because except for the * authentication type and quality protocol, if we are not negotiating * an option, it is because we were told not to. * For the authentication type, the Nak from the peer means * `let me authenticate myself with you' which is a bit pointless. * For the quality protocol, the Nak means `ask me to send you quality * reports', but if we didn't ask for them, we don't want them. */ while (len > CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if( (len -= cilen) < 0 ) goto bad; next = p + cilen - 2; switch (citype) { case CI_MRU: if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT) goto bad; break; case CI_ASYNCMAP: if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG) goto bad; break; case CI_AUTHTYPE: if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) goto bad; break; case CI_MAGICNUMBER: if (go->neg_magicnumber || no.neg_magicnumber || cilen != CILEN_LONG) goto bad; break; case CI_PCOMPRESSION: if (go->neg_pcompression || no.neg_pcompression || cilen != CILEN_VOID) goto bad; break; case CI_ACCOMPRESSION: if (go->neg_accompression || no.neg_accompression || cilen != CILEN_VOID) goto bad; break; case CI_QUALITY: if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) goto bad; break; } p = next; } /* If there is still anything left, this packet is bad. */ if (len != 0) goto bad; /* * OK, the Nak is good. Now we can update state. */ if (f->state != OPENED) { if (looped_back) { if (++try.numloops >= lcp_loopbackfail) { do_syslog(LOG_NOTICE, "Serial line is looped back."); lcp_close(f->unit); } } else try.numloops = 0; *go = try; } return 1; bad: LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!")); return 0; } /* * lcp_rejci - Peer has Rejected some of our CIs. * This should not modify any state if the Reject is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Reject was bad. * 1 - Reject was good. */ static int lcp_rejci(f, p, len) fsm *f; u_char *p; int len; { lcp_options *go = &lcp_gotoptions[f->unit]; u_char cichar; u_short cishort; u_int32_t cilong; u_char *start = p; int plen = len; lcp_options try; /* options to request next time */ try = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define REJCIVOID(opt, neg) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ try.neg = 0; \ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \ } #define REJCISHORT(opt, neg, val) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \ } #define REJCICHAP(opt, neg, val, digest) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if (cishort != val || cichar != digest) \ goto bad; \ try.neg = 0; \ try.neg_upap = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \ } #define REJCILONG(opt, neg, val) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cilong != val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \ } #define REJCILQR(opt, neg, val) \ if (go->neg && \ len >= CILEN_LQR && \ p[1] == CILEN_LQR && \ p[0] == opt) { \ len -= CILEN_LQR; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cishort != PPP_LQR || cilong != val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \ } REJCISHORT(CI_MRU, neg_mru, go->mru); REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); if (!go->neg_chap) { REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); } REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); REJCIVOID(CI_PCOMPRESSION, neg_pcompression); REJCIVOID(CI_ACCOMPRESSION, neg_accompression); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != OPENED) *go = try; return 1; bad: LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!")); LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d", plen, len, p - start)); return 0; } /* * lcp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. */ static int lcp_reqci(f, inp, lenp, reject_if_disagree) fsm *f; u_char *inp; /* Requested CIs */ int *lenp; /* Length of requested CIs */ int reject_if_disagree; { lcp_options *go = &lcp_gotoptions[f->unit]; lcp_options *ho = &lcp_hisoptions[f->unit]; lcp_options *ao = &lcp_allowoptions[f->unit]; u_char *cip, *next; /* Pointer to current and next CIs */ u_char cilen, citype, cichar;/* Parsed len, type, char value */ u_short cishort; /* Parsed short value */ u_int32_t cilong; /* Parse long value */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *rejp; /* Pointer to next char in reject frame */ u_char *nakp; /* Pointer to next char in Nak frame */ int l = *lenp; /* Length left */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; nakp = nak_buffer; rejp = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_MRU: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU")); if (!ao->neg_mru || /* Allow option? */ cilen != CILEN_SHORT) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETSHORT(cishort, p); /* Parse MRU */ LCPDEBUG((LOG_INFO, "(%d)", cishort)); /* * He must be able to receive at least our minimum. * No need to check a maximum. If he sends a large number, * we'll just ignore it. */ if (cishort < MINMRU) { orc = CONFNAK; /* Nak CI */ PUTCHAR(CI_MRU, nakp); PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(MINMRU, nakp); /* Give him a hint */ break; } ho->neg_mru = 1; /* Remember he sent MRU */ ho->mru = cishort; /* And remember value */ break; case CI_ASYNCMAP: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP")); if (!ao->neg_asyncmap || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong)); /* * Asyncmap must have set at least the bits * which are set in lcp_allowoptions[unit].asyncmap. */ if ((ao->asyncmap & ~cilong) != 0) { orc = CONFNAK; PUTCHAR(CI_ASYNCMAP, nakp); PUTCHAR(CILEN_LONG, nakp); PUTLONG(ao->asyncmap | cilong, nakp); break; } ho->neg_asyncmap = 1; ho->asyncmap = cilong; break; case CI_AUTHTYPE: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE")); if (cilen < CILEN_SHORT || !(ao->neg_upap || ao->neg_chap)) { /* * Reject the option if we're not willing to authenticate. */ orc = CONFREJ; break; } GETSHORT(cishort, p); LCPDEBUG((LOG_INFO, "(%x)", cishort)); /* * Authtype must be UPAP or CHAP. * * Note: if both ao->neg_upap and ao->neg_chap are set, * and the peer sends a Configure-Request with two * authenticate-protocol requests, one for CHAP and one * for UPAP, then we will reject the second request. * Whether we end up doing CHAP or UPAP depends then on * the ordering of the CIs in the peer's Configure-Request. */ if (cishort == PPP_PAP) { if (ho->neg_chap || /* we've already accepted CHAP */ cilen != CILEN_SHORT) { LCPDEBUG((LOG_WARNING, "lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_upap) { /* we don't want to do PAP */ orc = CONFNAK; /* NAK it and suggest CHAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); break; } ho->neg_upap = 1; break; } if (cishort == PPP_CHAP) { if (ho->neg_upap || /* we've already accepted PAP */ cilen != CILEN_CHAP) { LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_chap) { /* we don't want to do CHAP */ orc = CONFNAK; /* NAK it and suggest PAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); break; } GETCHAR(cichar, p); /* get digest type*/ if (cichar != ao->chap_mdtype) { orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); break; } ho->chap_mdtype = cichar; /* save md type */ ho->neg_chap = 1; break; } /* * We don't recognize the protocol they're asking for. * Nak it with something we're willing to do. * (At this point we know ao->neg_upap || ao->neg_chap.) */ orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); if (ao->neg_chap) { PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); } else { PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); } break; case CI_QUALITY: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY")); if (!ao->neg_lqr || cilen != CILEN_LQR) { orc = CONFREJ; break; } GETSHORT(cishort, p); GETLONG(cilong, p); LCPDEBUG((LOG_INFO, "(%x %x)", cishort, (unsigned int) cilong)); /* * Check the protocol and the reporting period. * XXX When should we Nak this, and what with? */ if (cishort != PPP_LQR) { orc = CONFNAK; PUTCHAR(CI_QUALITY, nakp); PUTCHAR(CILEN_LQR, nakp); PUTSHORT(PPP_LQR, nakp); PUTLONG(ao->lqr_period, nakp); break; } break; case CI_MAGICNUMBER: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER")); if (!(ao->neg_magicnumber || go->neg_magicnumber) || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong)); /* * He must have a different magic number. */ if (go->neg_magicnumber && cilong == go->magicnumber) { cilong = magic(); /* Don't put magic() inside macro! */ orc = CONFNAK; PUTCHAR(CI_MAGICNUMBER, nakp); PUTCHAR(CILEN_LONG, nakp); PUTLONG(cilong, nakp); break; } ho->neg_magicnumber = 1; ho->magicnumber = cilong; break; case CI_PCOMPRESSION: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION")); if (!ao->neg_pcompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_pcompression = 1; break; case CI_ACCOMPRESSION: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION")); if (!ao->neg_accompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_accompression = 1; break; default: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d", citype)); orc = CONFREJ; break; } endswitch: LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc))); if (orc == CONFACK && /* Good CI */ rc != CONFACK) /* but prior CI wasn't? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree /* Getting fed up with sending NAKs? */ && citype != CI_MAGICNUMBER) { orc = CONFREJ; /* Get tough if so */ } else { if (rc == CONFREJ) /* Rejecting prior CI? */ continue; /* Don't send this one */ rc = CONFNAK; } } if (orc == CONFREJ) { /* Reject this CI */ rc = CONFREJ; if (cip != rejp) /* Need to move rejected CI? */ BCOPY(cip, rejp, cilen); /* Move it */ INCPTR(cilen, rejp); /* Update output pointer */ } } /* * If we wanted to send additional NAKs (for unsent CIs), the * code would go here. The extra NAKs would go at *nakp. * At present there are no cases where we want to ask the * peer to negotiate an option. */ switch (rc) { case CONFACK: *lenp = next - inp; break; case CONFNAK: /* * Copy the Nak'd options from the nak_buffer to the caller's buffer. */ *lenp = nakp - nak_buffer; BCOPY(nak_buffer, inp, *lenp); break; case CONFREJ: *lenp = rejp - inp; break; } LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc))); return (rc); /* Return final code */ } /* * lcp_up - LCP has come UP. * * Start UPAP, IPCP, etc. */ static void lcp_up(f) fsm *f; { lcp_options *wo = &lcp_wantoptions[f->unit]; lcp_options *ho = &lcp_hisoptions[f->unit]; lcp_options *go = &lcp_gotoptions[f->unit]; lcp_options *ao = &lcp_allowoptions[f->unit]; if (!go->neg_magicnumber) go->magicnumber = 0; if (!ho->neg_magicnumber) ho->magicnumber = 0; /* * Set our MTU to the smaller of the MTU we wanted and * the MRU our peer wanted. If we negotiated an MRU, * set our MRU to the larger of value we wanted and * the value we got in the negotiation. */ ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), ho->neg_pcompression, ho->neg_accompression); /* * If the asyncmap hasn't been negotiated, we really should * set the receive asyncmap to ffffffff, but we set it to 0 * for backwards contemptibility. */ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU), (go->neg_asyncmap? go->asyncmap: 0x00000000), go->neg_pcompression, go->neg_accompression); if (ho->neg_mru) peer_mru[f->unit] = ho->mru; ChapLowerUp(f->unit); /* Enable CHAP */ upap_lowerup(f->unit); /* Enable UPAP */ ipcp_lowerup(f->unit); /* Enable IPCP */ ccp_lowerup(f->unit); /* Enable CCP */ lcp_echo_lowerup(f->unit); /* Enable echo messages */ link_established(f->unit); } /* * lcp_down - LCP has gone DOWN. * * Alert other protocols. */ static void lcp_down(f) fsm *f; { lcp_echo_lowerdown(f->unit); ccp_lowerdown(f->unit); ipcp_lowerdown(f->unit); ChapLowerDown(f->unit); upap_lowerdown(f->unit); sifdown(f->unit); ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0); ppp_recv_config(f->unit, PPP_MRU, 0x00000000, 0, 0); peer_mru[f->unit] = PPP_MRU; link_down(f->unit); } /* * lcp_starting - LCP needs the lower layer up. */ static void lcp_starting(f) fsm *f; { link_required(f->unit); } /* * lcp_finished - LCP has finished with the lower layer. */ static void lcp_finished(f) fsm *f; { link_terminated(f->unit); } /* * lcp_printpkt - print the contents of an LCP packet. */ char *lcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej", "ProtRej", "EchoReq", "EchoRep", "DiscReq" }; int lcp_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) __P((void *, char *, ...)); void *arg; { int code, id, len, olen; u_char *pstart, *optend; u_short cishort; u_int32_t cilong; if (plen < HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) printer(arg, " %s", lcp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print option list */ while (len >= 2) { GETCHAR(code, p); GETCHAR(olen, p); p -= 2; if (olen < 2 || olen > len) { break; } printer(arg, " <"); len -= olen; optend = p + olen; switch (code) { case CI_MRU: if (olen == CILEN_SHORT) { p += 2; GETSHORT(cishort, p); printer(arg, "mru %d", cishort); } break; case CI_ASYNCMAP: if (olen == CILEN_LONG) { p += 2; GETLONG(cilong, p); printer(arg, "asyncmap 0x%x", cilong); } break; case CI_AUTHTYPE: if (olen >= CILEN_SHORT) { p += 2; printer(arg, "auth "); GETSHORT(cishort, p); switch (cishort) { case PPP_PAP: printer(arg, "upap"); break; case PPP_CHAP: printer(arg, "chap"); break; default: printer(arg, "0x%x", cishort); } } break; case CI_QUALITY: if (olen >= CILEN_SHORT) { p += 2; printer(arg, "quality "); GETSHORT(cishort, p); switch (cishort) { case PPP_LQR: printer(arg, "lqr"); break; default: printer(arg, "0x%x", cishort); } } break; case CI_MAGICNUMBER: if (olen == CILEN_LONG) { p += 2; GETLONG(cilong, p); printer(arg, "magic 0x%x", cilong); } break; case CI_PCOMPRESSION: if (olen == CILEN_VOID) { p += 2; printer(arg, "pcomp"); } break; case CI_ACCOMPRESSION: if (olen == CILEN_VOID) { p += 2; printer(arg, "accomp"); } break; } while (p < optend) { GETCHAR(code, p); printer(arg, " %.2x", code); } printer(arg, ">"); } break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } /* * Time to shut down the link because there is nothing out there. */ static void LcpLinkFailure (f) fsm *f; { if (f->state == OPENED) { do_syslog(LOG_NOTICE, "Excessive lack of response to LCP echo frames."); lcp_close(f->unit); /* Reset connection */ } } /* * Timer expired for the LCP echo requests from this process. */ static void LcpEchoCheck (f) fsm *f; { long int delta; LcpSendEchoRequest (f); delta = (int) lcp_echo_interval; /* * Start the timer for the next interval. */ assert (lcp_echo_timer_running==0); TIMEOUT (LcpEchoTimeout, (caddr_t) f, (u_int32_t) delta); lcp_echo_timer_running = 1; } /* * LcpEchoTimeout - Timer expired on the LCP echo */ static void LcpEchoTimeout (arg) caddr_t arg; { if (lcp_echo_timer_running != 0) { lcp_echo_timer_running = 0; LcpEchoCheck ((fsm *) arg); } } /* * LcpEchoReply - LCP has received a reply to the echo */ static void lcp_received_echo_reply (f, id, inp, len) fsm *f; int id; u_char *inp; int len; { u_int32_t magic; /* Check the magic number - don't count replies from ourselves. */ if (len < 4) { do_syslog(LOG_DEBUG, "lcp: received short Echo-Reply, length %d", len); return; } GETLONG(magic, inp); if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { do_syslog(LOG_WARNING, "appear to have received our own echo-reply!"); return; } /* Reset the number of outstanding echo frames */ lcp_echos_pending = 0; } /* * LcpSendEchoRequest - Send an echo request frame to the peer */ static void LcpSendEchoRequest (f) fsm *f; { u_int32_t lcp_magic; u_char pkt[4], *pktp; /* * Detect the failure of the peer at this point. */ if (lcp_echo_fails != 0) { if (lcp_echos_pending++ >= lcp_echo_fails) { LcpLinkFailure(f); lcp_echos_pending = 0; } } /* * Make and send the echo request frame. */ if (f->state == OPENED) { lcp_magic = lcp_gotoptions[f->unit].neg_magicnumber ? lcp_gotoptions[f->unit].magicnumber : 0L; pktp = pkt; PUTLONG(lcp_magic, pktp); fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt); } } /* * lcp_echo_lowerup - Start the timer for the LCP frame */ static void lcp_echo_lowerup (unit) int unit; { fsm *f = &lcp_fsm[unit]; /* Clear the parameters for generating echo frames */ lcp_echos_pending = 0; lcp_echo_number = 0; lcp_echo_timer_running = 0; /* If a timeout interval is specified then start the timer */ if (lcp_echo_interval != 0) LcpEchoCheck (f); } /* * lcp_echo_lowerdown - Stop the timer for the LCP frame */ static void lcp_echo_lowerdown (unit) int unit; { fsm *f = &lcp_fsm[unit]; if (lcp_echo_timer_running != 0) { UNTIMEOUT (LcpEchoTimeout, (caddr_t) f); lcp_echo_timer_running = 0; } } slirp-1.0.17/src/ppp/lcp.h0000644000175000017500000000655110115276024014327 0ustar roverrover/* * lcp.h - Link Control Protocol definitions. * * 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: lcp.h,v 1.8 1995/06/12 11:22:47 paulus Exp $ */ /* * Options. */ #define CI_MRU 1 /* Maximum Receive Unit */ #define CI_ASYNCMAP 2 /* Async Control Character Map */ #define CI_AUTHTYPE 3 /* Authentication Type */ #define CI_QUALITY 4 /* Quality Protocol */ #define CI_MAGICNUMBER 5 /* Magic Number */ #define CI_PCOMPRESSION 7 /* Protocol Field Compression */ #define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ /* * LCP-specific packet types. */ #define PROTREJ 8 /* Protocol Reject */ #define ECHOREQ 9 /* Echo Request */ #define ECHOREP 10 /* Echo Reply */ #define DISCREQ 11 /* Discard Request */ /* * The state of options is described by an lcp_options structure. */ typedef struct lcp_options { int passive : 1; /* Don't die if we don't get a response */ int silent : 1; /* Wait for the other end to start first */ int restart : 1; /* Restart vs. exit after close */ int neg_mru : 1; /* Negotiate the MRU? */ int neg_asyncmap : 1; /* Negotiate the async map? */ int neg_upap : 1; /* Ask for UPAP authentication? */ int neg_chap : 1; /* Ask for CHAP authentication? */ int neg_magicnumber : 1; /* Ask for magic number? */ int neg_pcompression : 1; /* HDLC Protocol Field Compression? */ int neg_accompression : 1; /* HDLC Address/Control Field Compression? */ int neg_lqr : 1; /* Negotiate use of Link Quality Reports */ u_short mru; /* Value of MRU */ u_char chap_mdtype; /* which MD type (hashing algorithm) */ u_int32_t asyncmap; /* Value of async map */ u_int32_t magicnumber; int numloops; /* Number of loops during magic number neg. */ u_int32_t lqr_period; /* Reporting period for LQR 1/100ths second */ } lcp_options; extern fsm lcp_fsm[]; extern lcp_options lcp_wantoptions[]; extern lcp_options lcp_gotoptions[]; extern lcp_options lcp_allowoptions[]; extern lcp_options lcp_hisoptions[]; extern u_int32_t xmit_accm[][8]; #define DEFMRU 1500 /* Try for this */ #define MINMRU 128 /* No MRUs below this */ #define MAXMRU 16384 /* Normally limit MRU to this */ void lcp_init __P((int)); void lcp_open __P((int)); void lcp_close __P((int)); void lcp_lowerup __P((int)); void lcp_lowerdown __P((int)); void lcp_input __P((int, u_char *, int)); void lcp_protrej __P((int)); void lcp_sprotrej __P((int, u_char *, int)); int lcp_printpkt __P((u_char *, int, void (*) __P((void *, char *, ...)), void *)); /* Default number of times we receive our magic number from the peer before deciding the link is looped-back. */ #define DEFLOOPBACKFAIL 5 slirp-1.0.17/src/ppp/magic.c0000644000175000017500000000366510115276024014627 0ustar roverrover/* * magic.c - PPP Magic Number routines. * * 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. */ #ifndef lint static char rcsid[] = "$Id: magic.c,v 1.5 1995/06/06 01:52:25 paulus Exp $"; #endif #include #include #include #include "pppd.h" #include "magic.h" static u_int32_t next; /* Next value to return */ extern long mrand48 __P((void)); extern void srand48 __P((long)); /* * magic_init - Initialize the magic number generator. * * Attempts to compute a random number seed which will not repeat. * The current method uses the current hostid, current process ID * and current time, currently. */ void magic_init() { long seed; struct timeval t; gettimeofday(&t, NULL); seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid(); srand48(seed); } /* * magic - Returns the next magic number. */ u_int32_t magic() { return (u_int32_t) mrand48(); } #ifndef HAVE_DRAND48 /* * Substitute procedures for those systems which don't have * drand48 et al. */ double drand48() { return (double)random() / (double)0x7fffffffL; /* 2**31-1 */ } long mrand48() { return random(); } void srand48(seedval) long seedval; { srandom((int)seedval); } #endif slirp-1.0.17/src/ppp/magic.h0000644000175000017500000000201710115276024014622 0ustar roverrover/* * magic.h - PPP Magic Number definitions. * * 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: magic.h,v 1.3 1994/09/21 06:47:37 paulus Exp $ */ void magic_init __P((void)); /* Initialize the magic number generator */ u_int32_t magic __P((void)); /* Returns the next magic number */ slirp-1.0.17/src/ppp/md5.c0000644000175000017500000002631410115276024014230 0ustar roverrover /* *********************************************************************** ** md5.c -- the source code for MD5 routines ** ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** ** Created: 2/17/90 RLR ** ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** *********************************************************************** */ /* *********************************************************************** ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** ** ** ** License to copy and use this software is granted provided that ** ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** ** Digest Algorithm" in all material mentioning or referencing this ** ** software or this function. ** ** ** ** License is also granted to make and use derivative works ** ** provided that such works are identified as "derived from the RSA ** ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** ** material mentioning or referencing the derived work. ** ** ** ** RSA Data Security, Inc. makes no representations concerning ** ** either the merchantability of this software or the suitability ** ** of this software for any particular purpose. It is provided "as ** ** is" without express or implied warranty of any kind. ** ** ** ** These notices must be retained in any copies of any part of this ** ** documentation and/or software. ** *********************************************************************** */ #include "md5.h" /* *********************************************************************** ** Message-digest routines: ** ** To form the message digest for a message M ** ** (1) Initialize a context buffer mdContext using MD5Init ** ** (2) Call MD5Update on mdContext and M ** ** (3) Call MD5Final on mdContext ** ** The message digest is now in mdContext->digest[0...15] ** *********************************************************************** */ /* forward declaration */ static void Transform (); static unsigned char PADDING[64] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* F, G, H and I are basic MD5 functions */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ /* Rotation is separate from addition to prevent recomputation */ #define FF(a, b, c, d, x, s, ac) \ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) \ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) \ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) \ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #ifdef __STDC__ #define UL(x) x##U #else #define UL(x) x #endif /* The routine MD5Init initializes the message-digest context mdContext. All fields are set to zero. */ void MD5Init (mdContext) MD5_CTX *mdContext; { mdContext->i[0] = mdContext->i[1] = (UINT4)0; /* Load magic initialization constants. */ mdContext->buf[0] = (UINT4)0x67452301; mdContext->buf[1] = (UINT4)0xefcdab89; mdContext->buf[2] = (UINT4)0x98badcfe; mdContext->buf[3] = (UINT4)0x10325476; } /* The routine MD5Update updates the message-digest context to account for the presence of each of the characters inBuf[0..inLen-1] in the message whose digest is being computed. */ void MD5Update (mdContext, inBuf, inLen) MD5_CTX *mdContext; unsigned char *inBuf; unsigned int inLen; { UINT4 in[16]; int mdi; unsigned int i, ii; /* compute number of bytes mod 64 */ mdi = (int)((mdContext->i[0] >> 3) & 0x3F); /* update number of bits */ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) mdContext->i[1]++; mdContext->i[0] += ((UINT4)inLen << 3); mdContext->i[1] += ((UINT4)inLen >> 29); while (inLen--) { /* add new character to buffer, increment mdi */ mdContext->in[mdi++] = *inBuf++; /* transform if necessary */ if (mdi == 0x40) { for (i = 0, ii = 0; i < 16; i++, ii += 4) in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | (((UINT4)mdContext->in[ii+2]) << 16) | (((UINT4)mdContext->in[ii+1]) << 8) | ((UINT4)mdContext->in[ii]); Transform (mdContext->buf, in); mdi = 0; } } } /* The routine MD5Final terminates the message-digest computation and ends with the desired message digest in mdContext->digest[0...15]. */ void MD5Final (mdContext) MD5_CTX *mdContext; { UINT4 in[16]; int mdi; unsigned int i, ii; unsigned int padLen; /* save number of bits */ in[14] = mdContext->i[0]; in[15] = mdContext->i[1]; /* compute number of bytes mod 64 */ mdi = (int)((mdContext->i[0] >> 3) & 0x3F); /* pad out to 56 mod 64 */ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); MD5Update (mdContext, PADDING, padLen); /* append length in bits and transform */ for (i = 0, ii = 0; i < 14; i++, ii += 4) in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | (((UINT4)mdContext->in[ii+2]) << 16) | (((UINT4)mdContext->in[ii+1]) << 8) | ((UINT4)mdContext->in[ii]); Transform (mdContext->buf, in); /* store buffer in digest */ for (i = 0, ii = 0; i < 4; i++, ii += 4) { mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); mdContext->digest[ii+1] = (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); mdContext->digest[ii+2] = (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); mdContext->digest[ii+3] = (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); } } /* Basic MD5 step. Transforms buf based on in. */ static void Transform (buf, in) UINT4 *buf; UINT4 *in; { UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; /* Round 1 */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ /* Round 2 */ #define S21 5 #define S22 9 #define S23 14 #define S24 20 GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ /* Round 3 */ #define S31 4 #define S32 11 #define S33 16 #define S34 23 HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ /* Round 4 */ #define S41 6 #define S42 10 #define S43 15 #define S44 21 II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* *********************************************************************** ** End of md5.c ** ******************************** (cut) ******************************** */ slirp-1.0.17/src/ppp/md5.h0000644000175000017500000000565610115276024014243 0ustar roverrover/* *********************************************************************** ** md5.h -- header file for implementation of MD5 ** ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** ** Created: 2/17/90 RLR ** ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** ** Revised (for MD5): RLR 4/27/91 ** ** -- G modified to have y&~z instead of y&z ** ** -- FF, GG, HH modified to add in last register done ** ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** ** -- distinct additive constant for each step ** ** -- round 4 added, working mod 7 ** *********************************************************************** */ /* *********************************************************************** ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** ** ** ** License to copy and use this software is granted provided that ** ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** ** Digest Algorithm" in all material mentioning or referencing this ** ** software or this function. ** ** ** ** License is also granted to make and use derivative works ** ** provided that such works are identified as "derived from the RSA ** ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** ** material mentioning or referencing the derived work. ** ** ** ** RSA Data Security, Inc. makes no representations concerning ** ** either the merchantability of this software or the suitability ** ** of this software for any particular purpose. It is provided "as ** ** is" without express or implied warranty of any kind. ** ** ** ** These notices must be retained in any copies of any part of this ** ** documentation and/or software. ** *********************************************************************** */ #ifndef __MD5_INCLUDE__ /* typedef a 32-bit type */ typedef unsigned int UINT4; /* Data structure for MD5 (Message-Digest) computation */ typedef struct { UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ UINT4 buf[4]; /* scratch buffer */ unsigned char in[64]; /* input buffer */ unsigned char digest[16]; /* actual digest after MD5Final call */ } MD5_CTX; void MD5Init (); void MD5Update (); void MD5Final (); #define __MD5_INCLUDE__ #endif /* __MD5_INCLUDE__ */ slirp-1.0.17/src/ppp/options.h0000644000175000017500000000556310115276024015246 0ustar roverrover/* * Prototypes */ /* void setdebug _P((char *, struct socket *)); void setkdebug _P((char *, struct socket *)); void setpassive _P((char *, struct socket *)); void setinitopt _P((char *, struct socket *)); void noopt _P((char *, struct socket *)); void setnovj _P((char *, struct socket *)); void setnovjccomp _P((char *, struct socket *)); void setvjslots _P((char *, struct socket *)); void reqpap _P((char *, struct socket *)); void nopap _P((char *, struct socket *)); void setupapfile _P((char *, struct socket *)); void nochap _P((char *, struct socket *)); void reqchap _P((char *, struct socket *)); void setspeed _P((char *, struct socket *)); void noaccomp _P((char *, struct socket *)); void noasyncmap _P((char *, struct socket *)); void noipaddr _P((char *, struct socket *)); void nomagicnumber _P((char *, struct socket *)); void setasyncmap _P((char *, struct socket *)); void setescape _P((char *, struct socket *)); void setmru _P((char *, struct socket *)); void setmtu _P((char *, struct socket *)); void nomru _P((char *, struct socket *)); void nopcomp _P((char *, struct socket *)); void setconnector _P((char *, struct socket *)); void setdisconnector _P((char *, struct socket *)); void setdomain _P((char *, struct socket *)); void setnetmask _P((char *, struct socket *)); void setcrtscts _P((char *, struct socket *)); void setxonxoff _P((char *, struct socket *)); void setnodetach _P((char *, struct socket *)); void setmodem _P((char *, struct socket *)); void setlocal _P((char *, struct socket *)); void setlock _P((char *, struct socket *)); void setname _P((char *, struct socket *)); void set_user _P((char *, struct socket *)); void setremote _P((char *, struct socket *)); void setauth _P((char *, struct socket *)); void readfile _P((char *, struct socket *)); void setdefaultroute _P((char *, struct socket *)); void setproxyarp _P((char *, struct socket *)); void setpersist _P((char *, struct socket *)); void setdologin _P((char *, struct socket *)); void setusehostname _P((char *, struct socket *)); void setnoipdflt _P((char *, struct socket *)); void setlcptimeout _P((char *, struct socket *)); void setlcpterm _P((char *, struct socket *)); void setlcpconf _P((char *, struct socket *)); void setlcpfails _P((char *, struct socket *)); void setipcptimeout _P((char *, struct socket *)); void setipcpterm _P((char *, struct socket *)); void setipcpconf _P((char *, struct socket *)); void setipcpfails _P((char *, struct socket *)); void setpaptimeout _P((char *, struct socket *)); void setpapreqs _P((char *, struct socket *)); void setchaptimeout _P((char *, struct socket *)); void setchapchal _P((char *, struct socket *)); void setchapintv _P((char *, struct socket *)); void setipcpaccl _P((char *, struct socket *)); void setipcpaccr _P((char *, struct socket *)); void setlcpechointv _P((char *, struct socket *)); void setlcpechofails _P((char *, struct socket *)); */ slirp-1.0.17/src/ppp/patchlevel.h0000644000175000017500000000024410115276024015671 0ustar roverrover/* $Id: patchlevel.h,v 1.14 1995/06/12 11:22:52 paulus Exp $ */ #define PATCHLEVEL 0 #define VERSION "2.2" #define IMPLEMENTATION "" #define DATE "17 August 95" slirp-1.0.17/src/ppp/pathnames.h0000644000175000017500000000124710115276024015526 0ustar roverrover/* * define path names * * $Id: pathnames.h,v 1.6 1995/06/12 11:22:53 paulus Exp $ */ #ifdef HAVE_PATHS_H #include #else /* #define _PATH_VARRUN "/etc/ppp/" */ #define _PATH_DEVNULL "/dev/null" #endif /* #define _PATH_UPAPFILE "/etc/ppp/pap-secrets" #define _PATH_CHAPFILE "/etc/ppp/chap-secrets" */ extern char *path_upap; extern char *path_chap; #define _PATH_UPAPFILE path_upap #define _PATH_CHAPFILE path_chap #define _PATH_SYSOPTIONS "/etc/ppp/options" #define _PATH_IPUP "/etc/ppp/ip-up" #define _PATH_IPDOWN "/etc/ppp/ip-down" #define _PATH_TTYOPT "/etc/ppp/options." #define _PATH_CONNERRS "/etc/ppp/connect-errors" #define _PATH_USEROPT ".ppprc" slirp-1.0.17/src/ppp/ppp-comp.h0000644000175000017500000001122110115276024015272 0ustar roverrover/* * ppp-comp.h - Definitions for doing PPP packet compression. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * * $Id: ppp-comp.h,v 1.7 1995/05/01 01:43:37 paulus Exp $ */ #ifndef _NET_PPP_COMP_H #define _NET_PPP_COMP_H /* * The following symbols control whether we include code for * various compression methods. */ #ifndef DO_BSD_COMPRESS #define DO_BSD_COMPRESS 0 /* by default, include BSD-Compress */ #endif /* * Structure giving methods for compression/decompression. */ #define PACKETPTR struct mbuf * struct compressor { int compress_proto; /* CCP compression protocol number */ /* Allocate space for a compressor (transmit side) */ void *(*comp_alloc) __P((u_char *options, int opt_len)); /* Free space used by a compressor */ void (*comp_free) __P((void *state)); /* Initialize a compressor */ int (*comp_init) __P((void *state, u_char *options, int opt_len, int unit, int hdrlen, int debug)); /* Reset a compressor */ void (*comp_reset) __P((void *state)); /* Compress a packet */ int (*compress) __P((void *state, PACKETPTR *mret, PACKETPTR mp, int orig_len, int max_len, int proto)); /* Return compression statistics */ void (*comp_stat) __P((void *state, struct compstat *stats)); /* Allocate space for a decompressor (receive side) */ void *(*decomp_alloc) __P((u_char *options, int opt_len)); /* Free space used by a decompressor */ void (*decomp_free) __P((void *state)); /* Initialize a decompressor */ int (*decomp_init) __P((void *state, u_char *options, int opt_len, int unit, int hdrlen, int mru, int debug)); /* Reset a decompressor */ void (*decomp_reset) __P((void *state)); /* Decompress a packet. */ int (*decompress) __P((void *state, PACKETPTR mp, PACKETPTR *dmpp)); /* Update state for an incompressible packet received */ void (*incomp) __P((void *state, PACKETPTR mp, int proto)); /* Return decompression statistics */ void (*decomp_stat) __P((void *state, struct compstat *stats)); }; /* * Return values for decompress routine. * We need to make these distinctions so that we can disable certain * useful functionality, namely sending a CCP reset-request as a result * of an error detected after decompression. This is to avoid infringing * a patent held by Motorola. * Don't you just lurve software patents. */ #define DECOMP_OK 0 /* everything went OK */ #define DECOMP_ERROR 1 /* error detected before decomp. */ #define DECOMP_FATALERROR 2 /* error detected after decomp. */ /* * CCP codes. */ #define CCP_CONFREQ 1 #define CCP_CONFACK 2 #define CCP_TERMREQ 5 #define CCP_TERMACK 6 #define CCP_RESETREQ 14 #define CCP_RESETACK 15 /* * Max # bytes for a CCP option */ #define CCP_MAX_OPTION_LENGTH 32 /* * Parts of a CCP packet. */ #define CCP_CODE(dp) ((dp)[0]) #define CCP_ID(dp) ((dp)[1]) #define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) #define CCP_HDRLEN 4 #define CCP_OPT_CODE(dp) ((dp)[0]) #define CCP_OPT_LENGTH(dp) ((dp)[1]) #define CCP_OPT_MINLEN 2 /* * Definitions for BSD-Compress. */ #define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ #define CILEN_BSD_COMPRESS 3 /* length of config. option */ /* Macros for handling the 3rd byte of the BSD-Compress config option. */ #define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ #define BSD_VERSION(x) ((x) >> 5) /* version of option format */ #define BSD_CURRENT_VERSION 1 /* current version number */ #define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) #define BSD_MIN_BITS 9 /* smallest code size supported */ #define BSD_MAX_BITS 15 /* largest code size supported */ #endif /* _NET_PPP_COMP_H */ slirp-1.0.17/src/ppp/ppp.h0000644000175000017500000000356110115276024014346 0ustar roverrover/* * ppp.h - PPP global declarations. * * 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: ppp.h,v 1.1 1993/11/11 03:54:25 paulus Exp $ */ /* * Modified for use with SLiRP by Juha Pirkola 8-May-1995 */ #include #ifndef __PPP_H__ #define __PPP_H__ /* * Data Link Layer header = Address, Control, Protocol. */ #define ALLSTATIONS 0xff /* All-Stations Address */ #define UI 0x03 /* Unnumbered Information */ #define LCP 0xc021 /* Link Control Protocol */ #define IPCP 0x8021 /* IP Control Protocol */ #define UPAP 0xc023 /* User/Password Authentication Protocol */ #define CHAP 0xc223 /* Cryptographic Handshake Protocol */ #define LQR 0xc025 /* Link Quality Report protocol */ #define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */ #define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) #define MTU 1500 /* Default MTU */ #ifdef __STDC__ void real_do_syslog _P((int priority, const char *format, ...)); #else void real_do_syslog (); #endif #define do_syslog if(debug)real_do_syslog void print_string _P((char *, int, void (*) _P((void *, char *, ...)), void *)); #endif /* __PPP_H__ */ slirp-1.0.17/src/ppp/ppp_defs.h0000644000175000017500000001164110115276024015345 0ustar roverrover/* $Id: ppp_defs.h,v 1.6 1995/04/24 02:42:06 paulus Exp $ */ /* * ppp_defs.h - PPP definitions. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. */ #ifndef _PPP_DEFS_H_ #define _PPP_DEFS_H_ /* * The basic PPP frame. */ #define PPP_HDRLEN 4 /* octets for standard ppp header */ #define PPP_FCSLEN 2 /* octets for FCS */ #define PPP_MRU 1500 /* default MRU = max length of info field */ #define PPP_ADDRESS(p) (((u_char *)(p))[0]) #define PPP_CONTROL(p) (((u_char *)(p))[1]) #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) /* * Significant octet values. */ #define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ #define PPP_UI 0x03 /* Unnumbered Information */ #define PPP_FLAG 0x7e /* Flag Sequence */ #define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ #define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ /* * Protocol field values. */ #define PPP_IP 0x21 /* Internet Protocol */ #define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ #define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ #define PPP_COMP 0xfd /* compressed packet */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_CCP 0x80fd /* Compression Control Protocol */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ /* * Values for FCS calculations. */ #define PPP_INITFCS 0xffff /* Initial FCS value */ #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) /* * A 32-bit unsigned integral type. */ /* * Extended asyncmap - allows any character to be escaped. */ typedef u_int32_t ext_accm[8]; /* * What to do with network protocol (NP) packets. */ enum NPmode { NPMODE_PASS, /* pass the packet through */ NPMODE_DROP, /* silently drop the packet */ NPMODE_ERROR, /* return an error */ NPMODE_QUEUE /* save it up for later. */ }; /* * Statistics. */ struct pppstat { u_int ppp_ibytes; /* bytes received */ u_int ppp_ipackets; /* packets received */ u_int ppp_ierrors; /* receive errors */ u_int ppp_obytes; /* bytes sent */ u_int ppp_opackets; /* packets sent */ u_int ppp_oerrors; /* transmit errors */ }; struct vjstat { u_int vjs_packets; /* outbound packets */ u_int vjs_compressed; /* outbound compressed packets */ u_int vjs_searches; /* searches for connection state */ u_int vjs_misses; /* times couldn't find conn. state */ u_int vjs_uncompressedin; /* inbound uncompressed packets */ u_int vjs_compressedin; /* inbound compressed packets */ u_int vjs_errorin; /* inbound unknown type packets */ u_int vjs_tossed; /* inbound packets tossed because of error */ }; struct ppp_stats { struct pppstat p; /* basic PPP statistics */ struct vjstat vj; /* VJ header compression statistics */ }; struct compstat { u_int unc_bytes; /* total uncompressed bytes */ u_int unc_packets; /* total uncompressed packets */ u_int comp_bytes; /* compressed bytes */ u_int comp_packets; /* compressed packets */ u_int inc_bytes; /* incompressible bytes */ u_int inc_packets; /* incompressible packets */ u_int ratio; /* recent compression ratio << 8 */ }; struct ppp_comp_stats { struct compstat c; /* packet compression statistics */ struct compstat d; /* packet decompression statistics */ }; /* * The following structure records the time in seconds since * the last NP packet was sent or received. */ struct ppp_idle { time_t xmit_idle; /* time since last NP packet sent */ time_t recv_idle; /* time since last NP packet received */ }; #ifndef __P #ifdef __STDC__ #define __P(x) x #else #define __P(x) () #endif #endif #endif /* _PPP_DEFS_H_ */ slirp-1.0.17/src/ppp/pppd.h0000644000175000017500000001634210117211720014505 0ustar roverrover/* * pppd.h - PPP daemon global declarations. * * 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: pppd.h,v 1.8 1995/04/26 06:46:31 paulus Exp $ */ /* * TODO: */ #ifndef __PPPD_H__ #define __PPPD_H__ #include "ppp.h" #define NUM_PPP MAX_PPP_INTERFACES #include /* for MAXPATHLEN and BSD4_4, if defined */ #include /* for u_int32_t, if defined */ #include /* * Limits. */ #define MAXWORDLEN 1024 /* max length of word in file (incl null) */ #define MAXARGS 1 /* max # args to a command */ #define MAXNAMELEN 256 /* max length of hostname or name for auth */ #define MAXSECRETLEN 256 /* max length of password or secret */ /* * Global variables. */ extern int hungup; /* Physical layer has disconnected */ extern int ifunit; /* Interface unit number */ extern char ifname[]; /* Interface name */ extern int fd; /* Serial device file descriptor */ extern char hostname[MAXNAMELEN]; /* Our hostname */ extern u_char outpacket_buf[]; /* Buffer for outgoing packets */ extern int phase; /* Current state of link - see values below */ extern int baud_rate; /* Current link speed in bits/sec */ /* * Variables set by command-line options. */ extern int debug; /* Debug flag */ extern int kdebugflag; /* Tell kernel to print debug messages */ extern int default_device; /* Using /dev/tty or equivalent */ extern char devnam[MAXPATHLEN]; /* Device name */ extern int crtscts; /* Use hardware flow control */ extern int modem; /* Use modem control lines */ extern int inspeed; /* Input/Output speed requested */ extern u_int32_t netmask; /* IP netmask to set on interface */ extern int lockflag; /* Create lock file to lock the serial dev */ extern int nodetach; /* Don't detach from controlling tty */ extern char *connector; /* Script to establish physical link */ extern char *disconnector; /* Script to disestablish physical link */ extern char user[MAXNAMELEN]; /* Username for PAP */ extern char passwd[MAXSECRETLEN]; /* Password for PAP */ extern int auth_required; /* Peer is required to authenticate */ extern int proxyarp; /* Set up proxy ARP entry for peer */ extern int persist; /* Reopen link after it goes down */ extern int uselogin; /* Use /etc/passwd for checking PAP */ extern int lcp_echo_interval; /* Interval between LCP echo-requests */ extern int lcp_echo_fails; /* Tolerance to unanswered echo-requests */ extern char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ extern int usehostname; /* Use hostname for our_name */ extern int disable_defaultip; /* Don't use hostname for default IP adrs */ extern char *ipparam; /* Extra parameter for ip up/down scripts */ extern int cryptpap; /* Others' PAP passwords are encrypted */ /* * Values for phase. */ #define PHASE_DEAD 0 #define PHASE_ESTABLISH 1 #define PHASE_AUTHENTICATE 2 #define PHASE_NETWORK 3 #define PHASE_TERMINATE 4 /* * Prototypes. */ void quit __P((void)); /* Cleanup and exit */ void timeout __P((void (*)(), caddr_t, int)); /* Look-alike of kernel's timeout() */ void untimeout __P((void (*)(), caddr_t)); /* Look-alike of kernel's untimeout() */ void output __P((int, u_char *, int)); /* Output a PPP packet */ void demuxprotrej __P((int, int)); /* Demultiplex a Protocol-Reject */ int check_passwd __P((int, char *, int, char *, int, char **, int *)); /* Check peer-supplied username/password */ int get_secret __P((int, char *, char *, char *, int *, int)); /* get "secret" for chap */ u_int32_t GetMask __P((u_int32_t)); /* get netmask for address */ void die __P((int)); /* * Inline versions of get/put char/short/long. * Pointer is advanced; we assume that both arguments * are lvalues and will already be in registers. * cp MUST be u_char *. */ #define GETCHAR(c, cp) { \ (c) = *(cp)++; \ } #define PUTCHAR(c, cp) { \ *(cp)++ = (u_char) (c); \ } #define GETSHORT(s, cp) { \ (s) = *(cp)++ << 8; \ (s) |= *(cp)++; \ } #define PUTSHORT(s, cp) { \ *(cp)++ = (u_char) ((s) >> 8); \ *(cp)++ = (u_char) (s); \ } #define GETLONG(l, cp) { \ (l) = *(cp)++ << 8; \ (l) |= *(cp)++; (l) <<= 8; \ (l) |= *(cp)++; (l) <<= 8; \ (l) |= *(cp)++; \ } #define PUTLONG(l, cp) { \ *(cp)++ = (u_char) ((l) >> 24); \ *(cp)++ = (u_char) ((l) >> 16); \ *(cp)++ = (u_char) ((l) >> 8); \ *(cp)++ = (u_char) (l); \ } #define INCPTR(n, cp) ((cp) += (n)) #define DECPTR(n, cp) ((cp) -= (n)) #undef FALSE #define FALSE 0 #undef TRUE #define TRUE 1 /* * System dependent definitions for user-level 4.3BSD UNIX implementation. */ #define DEMUXPROTREJ(u, p) demuxprotrej(u, p) #define TIMEOUT(r, f, t) timeout((r), (f), (t)) #define UNTIMEOUT(r, f) untimeout((r), (f)) #define BCOPY(s, d, l) memcpy(d, s, l) #define BZERO(s, n) memset(s, 0, n) #define EXIT(u) quit() #define PRINTMSG(m, l) { m[l] = '\0'; do_syslog(LOG_INFO, "Remote message: %s", m); } /* * MAKEHEADER - Add Header fields to a packet. */ #define MAKEHEADER(p, t) { \ PUTCHAR(PPP_ALLSTATIONS, p); \ PUTCHAR(PPP_UI, p); \ PUTSHORT(t, p); } #ifdef DEBUGALL #define DEBUGMAIN 1 #define DEBUGFSM 1 #define DEBUGLCP 1 #define DEBUGIPCP 1 #define DEBUGUPAP 1 #define DEBUGCHAP 1 #endif #ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */ #if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \ || defined(DEBUGCHAP) #define LOG_PPP LOG_LOCAL2 #else #define LOG_PPP LOG_DAEMON #endif #endif /* LOG_PPP */ #ifdef DEBUGMAIN #define MAINDEBUG(x) if (debug) do_syslog x #else #define MAINDEBUG(x) #endif #ifdef DEBUGFSM #define FSMDEBUG(x) if (debug) do_syslog x #else #define FSMDEBUG(x) #endif #ifdef DEBUGLCP #define LCPDEBUG(x) if (debug) do_syslog x #else #define LCPDEBUG(x) #endif #ifdef DEBUGIPCP #define IPCPDEBUG(x) if (debug) do_syslog x #else #define IPCPDEBUG(x) #endif #ifdef DEBUGUPAP #define UPAPDEBUG(x) if (debug) do_syslog x #else #define UPAPDEBUG(x) #endif #ifdef DEBUGCHAP #define CHAPDEBUG(x) if (debug) do_syslog x #else #define CHAPDEBUG(x) #endif #ifndef SIGTYPE #if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) #define SIGTYPE void #else #define SIGTYPE int #endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */ #endif /* SIGTYPE */ #ifndef MIN #define MIN(a, b) ((a) < (b)? (a): (b)) #endif #ifndef MAX #define MAX(a, b) ((a) > (b)? (a): (b)) #endif struct protent { u_short protocol; void (*init)(); void (*input)(); void (*protrej)(); int (*printpkt)(); void (*datainput)(); char *name; }; #endif /* __PPP_H__ */ slirp-1.0.17/src/ppp/pppdfncs.c0000644000175000017500000002155710115276024015364 0ustar roverrover/* * main.c - Point-to-Point Protocol main module * * 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. */ #ifndef lint static char rcsid[] = "$Id: main.c,v 1.24 1995/06/12 11:22:49 paulus Exp $"; #endif #include /* #include */ #include #include #include #include #include #include #include #include #include #include #include #include #include "pppd.h" #include "magic.h" #include "fsm.h" #include "lcp.h" #include "ipcp.h" #include "upap.h" #include "chap.h" #include "ccp.h" #include "pathnames.h" #include "patchlevel.h" #undef ifs_next #include /* must follow include of slirp.h via pppd.h */ /* * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless * /etc/ppp/options exists. */ /* XXXXX Delete fields not used */ #ifndef REQ_SYSOPTIONS #define REQ_SYSOPTIONS 1 #endif /* interface vars */ char ifname[MAX_INTERFACES]; /* Interface name */ int ifunit; /* Interface unit number */ char hostname[MAXNAMELEN]; /* Our hostname */ static char pidfilename[MAXPATHLEN]; /* name of pid file */ static char default_devnam[MAXPATHLEN]; /* name of default device */ static pid_t pid; /* Our pid */ static pid_t pgrpid; /* Process Group ID */ static uid_t uid; /* Our real user-id */ int fd = -1; /* Device file descriptor */ struct timeval schedtime; int phase; /* where the link is at */ int kill_link; static int initfdflags = -1; /* Initial file descriptor flags */ u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */ /* static u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; */ /* buffer for incoming packet */ int hungup; /* terminal has been hung up */ static int n_children; /* # child processes still running */ int baud_rate; /* prototypes */ static void hup __P((int)); static void term __P((int)); static void chld __P((int)); static void toggle_debug __P((int)); static void open_ccp __P((int)); static void get_input __P((void)); void establish_ppp __P((void)); void calltimeout __P((void)); struct timeval *timeleft __P((struct timeval *)); void reap_kids __P((void)); void cleanup __P((int, caddr_t)); void close_fd __P((void)); void die __P((int)); void novm __P((char *)); void log_packet __P((u_char *, int, char *)); void format_packet __P((u_char *, int, void (*) (void *, char *, ...), void *)); void pr_log __P((void *, char *, ...)); extern char *ttyname __P((int)); extern char *getlogin __P((void)); #ifdef ultrix #undef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif /* * PPP Data Link Layer "protocol" table. * One entry per supported protocol. */ struct protent prottbl[] = { { PPP_LCP, lcp_init, lcp_input, lcp_protrej, lcp_printpkt, NULL, "LCP" }, { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej, ipcp_printpkt, NULL, "IPCP" }, { PPP_PAP, upap_init, upap_input, upap_protrej, upap_printpkt, NULL, "PAP" }, { PPP_CHAP, ChapInit, ChapInput, ChapProtocolReject, ChapPrintPkt, NULL, "CHAP" }, { PPP_CCP, ccp_init, ccp_input, ccp_protrej, ccp_printpkt, ccp_datainput, "CCP" }, }; /* * demuxprotrej - Demultiplex a Protocol-Reject. */ void demuxprotrej(unit, protocol) int unit; u_short protocol; { int i; /* * Upcall the proper Protocol-Reject routine. */ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++) if (prottbl[i].protocol == protocol) { (*prottbl[i].protrej)(unit); return; } do_syslog(LOG_WARNING, "demuxprotrej: Unrecognized Protocol-Reject for protocol 0x%x", protocol); } /* * quit - Clean up state and exit. */ void quit() { die(0); } struct callout { int c_time; /* time at which to call routine */ caddr_t c_arg; /* argument to routine */ void (*c_func)(); /* routine */ struct callout *c_next; }; static struct callout *callout = NULL; /* Callout list */ static struct timeval timenow; /* Current time */ /* * timeout - Schedule a timeout. * * Note that this timeout takes the number of seconds, NOT hz (as in * the kernel). */ void timeout(func, arg, time) void (*func)(); caddr_t arg; int time; { struct itimerval itv; struct callout *newp, **oldpp; MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.", (int) func, (int) arg, time)); /* * Allocate timeout. */ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) { do_syslog(LOG_ERR, "Out of memory in timeout()!"); die(1); } newp->c_arg = arg; newp->c_func = func; /* * Find correct place to link it in and decrement its time by the * amount of time used by preceding timeouts. */ for (oldpp = &callout; *oldpp && (*oldpp)->c_time <= time; oldpp = &(*oldpp)->c_next) time -= (*oldpp)->c_time; newp->c_time = time; newp->c_next = *oldpp; if (*oldpp) (*oldpp)->c_time -= time; *oldpp = newp; /* * If this is now the first callout then we have to set a new * itimer. */ if (callout == newp) { itv.it_interval.tv_sec = itv.it_interval.tv_usec = itv.it_value.tv_usec = 0; itv.it_value.tv_sec = callout->c_time; MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in timeout.", itv.it_value.tv_sec)); if (setitimer(ITIMER_REAL, &itv, NULL)) { do_syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m"); die(1); } if (gettimeofday(&schedtime, NULL)) { do_syslog(LOG_ERR, "gettimeofday: %m"); die(1); } } } /* * untimeout - Unschedule a timeout. */ void untimeout(func, arg) void (*func)(); caddr_t arg; { struct itimerval itv; struct callout **copp, *freep; int reschedule = 0; MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg)); /* * If the first callout is unscheduled then we have to set a new * itimer. */ if (callout && callout->c_func == func && callout->c_arg == arg) reschedule = 1; /* * Find first matching timeout. Add its time to the next timeouts * time. */ for (copp = &callout; *copp; copp = &(*copp)->c_next) if ((*copp)->c_func == func && (*copp)->c_arg == arg) { freep = *copp; *copp = freep->c_next; if (*copp) (*copp)->c_time += freep->c_time; (void) free((char *) freep); break; } if (reschedule) { itv.it_interval.tv_sec = itv.it_interval.tv_usec = itv.it_value.tv_usec = 0; itv.it_value.tv_sec = callout ? callout->c_time : 0; MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in untimeout.", itv.it_value.tv_sec)); if (setitimer(ITIMER_REAL, &itv, NULL)) { do_syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m"); die(1); } if (gettimeofday(&schedtime, NULL)) { do_syslog(LOG_ERR, "gettimeofday: %m"); die(1); } } } /* * alrm - Catch SIGALRM signal. * * Indicates a timeout. */ void /* static removed by JP */ alrm(sig) int sig; { struct itimerval itv; struct callout *freep, *list, *last; MAINDEBUG((LOG_DEBUG, "Alarm")); if (callout == NULL) return; /* * Get the first scheduled timeout and any that were scheduled * for the same time as a list, and remove them all from callout * list. */ list = last = callout; while (last->c_next != NULL && last->c_next->c_time == 0) last = last->c_next; callout = last->c_next; last->c_next = NULL; /* * Set a new itimer if there are more timeouts scheduled. */ if (callout) { itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0; itv.it_value.tv_usec = 0; itv.it_value.tv_sec = callout->c_time; MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in alrm.", itv.it_value.tv_sec)); if (setitimer(ITIMER_REAL, &itv, NULL)) { do_syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m"); die(1); } if (gettimeofday(&schedtime, NULL)) { do_syslog(LOG_ERR, "gettimeofday: %m"); die(1); } } /* * Now call all the timeout routines scheduled for this time. */ while (list) { (*list->c_func)(list->c_arg); freep = list; list = list->c_next; (void) free((char *) freep); } } /* * novm - log an error message saying we ran out of memory, and die. */ void novm(msg) char *msg; { do_syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg); die(1); } slirp-1.0.17/src/ppp/slirppp.h0000644000175000017500000000207610115276024015240 0ustar roverrover/* * slirppp.h - definitions * * Juha Pirkola 1995 * * included through ppp.h and SLiRP's main.c * */ #ifndef __SLIRPPP_H__ #define __SLIRPPP_H__ #define PPP_LOGFILE "ppplog" /* special characters */ /* #define PPP_FLAG 0x7E */ /* frame delimiter */ #define PPP_ESC 0x7d /* escape character */ /* protocols */ #define PROTO_IP 0x0021 #define PROTO_VJCOMP 0x002d #define PROTO_VJUNCOMP 0x002f /* FCS support */ #define PPP_FCS_INIT 0xffff #define PPP_FCS_GOOD 0xf0b8 #define in_xmap(c, unit) (xmit_async_map[unit][(c) >> 5] & (1 << ((c) & 0x1f))) #define in_rmap(c, unit) ((((unsigned int) (unsigned char) (c)) < 0x20) && \ recv_async_map[unit] & (1 << (c))) #ifndef GIDSET_TYPE /* I'm not sure who needs this */ #define GIDSET_TYPE gid_t #endif #ifdef __linux__ /* Maybe both should be undef'd ? */ #define _linux_ #endif struct ppp_out { unsigned char *buff; unsigned char *head; unsigned short fcs; }; extern int debug; extern int ppp_up; extern FILE *logfile; #endif /* __SLIRPPP_H__ */ slirp-1.0.17/src/ppp/upap.c0000644000175000017500000003143610115276024014511 0ustar roverrover/* * upap.c - User/Password Authentication Protocol. * * 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. */ #ifndef lint static char rcsid[] = "$Id: upap.c,v 1.6 1995/06/12 12:02:24 paulus Exp $"; #endif /* * TODO: */ #include #include #include #include #include #include "pppd.h" #include "upap.h" upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ static void upap_timeout __P((caddr_t)); static void upap_reqtimeout __P((caddr_t)); static void upap_rauthreq __P((upap_state *, u_char *, int, int)); static void upap_rauthack __P((upap_state *, u_char *, int, int)); static void upap_rauthnak __P((upap_state *, u_char *, int, int)); static void upap_sauthreq __P((upap_state *)); static void upap_sresp __P((upap_state *, int, int, char *, int)); /* * upap_init - Initialize a UPAP unit. */ void upap_init(unit) int unit; { upap_state *u = &upap[unit]; u->us_unit = unit; u->us_user = NULL; u->us_userlen = 0; u->us_passwd = NULL; u->us_passwdlen = 0; u->us_clientstate = UPAPCS_INITIAL; u->us_serverstate = UPAPSS_INITIAL; u->us_id = 0; u->us_timeouttime = UPAP_DEFTIMEOUT; u->us_maxtransmits = 10; u->us_reqtimeout = UPAP_DEFREQTIME; } /* * upap_authwithpeer - Authenticate us with our peer (start client). * * Set new state and send authenticate's. */ void upap_authwithpeer(unit, user, password) int unit; char *user, *password; { upap_state *u = &upap[unit]; /* Save the username and password we're given */ u->us_user = user; u->us_userlen = strlen(user); u->us_passwd = password; u->us_passwdlen = strlen(password); u->us_transmits = 0; /* Lower layer up yet? */ if (u->us_clientstate == UPAPCS_INITIAL || u->us_clientstate == UPAPCS_PENDING) { u->us_clientstate = UPAPCS_PENDING; return; } upap_sauthreq(u); /* Start protocol */ } /* * upap_authpeer - Authenticate our peer (start server). * * Set new state. */ void upap_authpeer(unit) int unit; { upap_state *u = &upap[unit]; /* Lower layer up yet? */ if (u->us_serverstate == UPAPSS_INITIAL || u->us_serverstate == UPAPSS_PENDING) { u->us_serverstate = UPAPSS_PENDING; return; } u->us_serverstate = UPAPSS_LISTEN; if (u->us_reqtimeout > 0) TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout); } /* * upap_timeout - Retransmission timer for sending auth-reqs expired. */ static void upap_timeout(arg) caddr_t arg; { upap_state *u = (upap_state *) arg; if (u->us_clientstate != UPAPCS_AUTHREQ) return; if (u->us_transmits >= u->us_maxtransmits) { /* give up in disgust */ do_syslog(LOG_ERR, "No response to PAP authenticate-requests"); u->us_clientstate = UPAPCS_BADAUTH; auth_withpeer_fail(u->us_unit, PPP_PAP); return; } upap_sauthreq(u); /* Send Authenticate-Request */ } /* * upap_reqtimeout - Give up waiting for the peer to send an auth-req. */ static void upap_reqtimeout(arg) caddr_t arg; { upap_state *u = (upap_state *) arg; if (u->us_serverstate != UPAPSS_LISTEN) return; /* huh?? */ auth_peer_fail(u->us_unit, PPP_PAP); u->us_serverstate = UPAPSS_BADAUTH; } /* * upap_lowerup - The lower layer is up. * * Start authenticating if pending. */ void upap_lowerup(unit) int unit; { upap_state *u = &upap[unit]; if (u->us_clientstate == UPAPCS_INITIAL) u->us_clientstate = UPAPCS_CLOSED; else if (u->us_clientstate == UPAPCS_PENDING) { upap_sauthreq(u); /* send an auth-request */ } if (u->us_serverstate == UPAPSS_INITIAL) u->us_serverstate = UPAPSS_CLOSED; else if (u->us_serverstate == UPAPSS_PENDING) { u->us_serverstate = UPAPSS_LISTEN; if (u->us_reqtimeout > 0) TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout); } } /* * upap_lowerdown - The lower layer is down. * * Cancel all timeouts. */ void upap_lowerdown(unit) int unit; { upap_state *u = &upap[unit]; if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */ if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) UNTIMEOUT(upap_reqtimeout, (caddr_t) u); u->us_clientstate = UPAPCS_INITIAL; u->us_serverstate = UPAPSS_INITIAL; } /* * upap_protrej - Peer doesn't speak this protocol. * * This shouldn't happen. In any case, pretend lower layer went down. */ void upap_protrej(unit) int unit; { upap_state *u = &upap[unit]; if (u->us_clientstate == UPAPCS_AUTHREQ) { do_syslog(LOG_ERR, "PAP authentication failed due to protocol-reject"); auth_withpeer_fail(unit, PPP_PAP); } if (u->us_serverstate == UPAPSS_LISTEN) { do_syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)"); auth_peer_fail(unit, PPP_PAP); } upap_lowerdown(unit); } /* * upap_input - Input UPAP packet. */ void upap_input(unit, inpacket, l) int unit; u_char *inpacket; int l; { upap_state *u = &upap[unit]; u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < UPAP_HEADERLEN) { UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header.")); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < UPAP_HEADERLEN) { UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length.")); return; } if (len > l) { UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet.")); return; } len -= UPAP_HEADERLEN; /* * Action depends on code. */ switch (code) { case UPAP_AUTHREQ: upap_rauthreq(u, inp, id, len); break; case UPAP_AUTHACK: upap_rauthack(u, inp, id, len); break; case UPAP_AUTHNAK: upap_rauthnak(u, inp, id, len); break; default: /* XXX Need code reject */ break; } } /* * upap_rauth - Receive Authenticate. */ static void upap_rauthreq(u, inp, id, len) upap_state *u; u_char *inp; int id; int len; { u_char ruserlen, rpasswdlen; char *ruser, *rpasswd; int retcode; char *msg; int msglen; UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id)); if (u->us_serverstate < UPAPSS_LISTEN) return; /* * If we receive a duplicate authenticate-request, we are * supposed to return the same status as for the first request. */ if (u->us_serverstate == UPAPSS_OPEN) { upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ return; } if (u->us_serverstate == UPAPSS_BADAUTH) { upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ return; } /* * Parse user/passwd. */ if (len < sizeof (u_char)) { UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet.")); return; } GETCHAR(ruserlen, inp); len -= sizeof (u_char) + ruserlen + sizeof (u_char); if (len < 0) { UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet.")); return; } ruser = (char *) inp; INCPTR(ruserlen, inp); GETCHAR(rpasswdlen, inp); if (len < rpasswdlen) { UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet.")); return; } rpasswd = (char *) inp; /* * Check the username and password given. */ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen); upap_sresp(u, retcode, id, msg, msglen); if (retcode == UPAP_AUTHACK) { u->us_serverstate = UPAPSS_OPEN; auth_peer_success(u->us_unit, PPP_PAP); } else { u->us_serverstate = UPAPSS_BADAUTH; auth_peer_fail(u->us_unit, PPP_PAP); } if (u->us_reqtimeout > 0) UNTIMEOUT(upap_reqtimeout, (caddr_t) u); } /* * upap_rauthack - Receive Authenticate-Ack. */ static void upap_rauthack(u, inp, id, len) upap_state *u; u_char *inp; int id; int len; { u_char msglen; char *msg; UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id)); if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ return; /* * Parse message. */ if (len < sizeof (u_char)) { UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet.")); return; } GETCHAR(msglen, inp); len -= sizeof (u_char); if (len < msglen) { UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet.")); return; } msg = (char *) inp; PRINTMSG(msg, msglen); u->us_clientstate = UPAPCS_OPEN; auth_withpeer_success(u->us_unit, PPP_PAP); } /* * upap_rauthnak - Receive Authenticate-Nakk. */ static void upap_rauthnak(u, inp, id, len) upap_state *u; u_char *inp; int id; int len; { u_char msglen; char *msg; UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id)); if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ return; /* * Parse message. */ if (len < sizeof (u_char)) { UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet.")); return; } GETCHAR(msglen, inp); len -= sizeof (u_char); if (len < msglen) { UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet.")); return; } msg = (char *) inp; PRINTMSG(msg, msglen); u->us_clientstate = UPAPCS_BADAUTH; do_syslog(LOG_ERR, "PAP authentication failed"); auth_withpeer_fail(u->us_unit, PPP_PAP); } /* * upap_sauthreq - Send an Authenticate-Request. */ static void upap_sauthreq(u) upap_state *u; { u_char *outp; int outlen; outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + u->us_passwdlen; outp = outpacket_buf; MAKEHEADER(outp, PPP_PAP); PUTCHAR(UPAP_AUTHREQ, outp); PUTCHAR(++u->us_id, outp); PUTSHORT(outlen, outp); PUTCHAR(u->us_userlen, outp); BCOPY(u->us_user, outp, u->us_userlen); INCPTR(u->us_userlen, outp); PUTCHAR(u->us_passwdlen, outp); BCOPY(u->us_passwd, outp, u->us_passwdlen); output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id)); TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime); ++u->us_transmits; u->us_clientstate = UPAPCS_AUTHREQ; } /* * upap_sresp - Send a response (ack or nak). */ static void upap_sresp(u, code, id, msg, msglen) upap_state *u; u_char code, id; char *msg; int msglen; { u_char *outp; int outlen; outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; outp = outpacket_buf; MAKEHEADER(outp, PPP_PAP); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); PUTCHAR(msglen, outp); BCOPY(msg, outp, msglen); output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id)); } /* * upap_printpkt - print the contents of a PAP packet. */ char *upap_codenames[] = { "AuthReq", "AuthAck", "AuthNak" }; int upap_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) __P((void *, char *, ...)); void *arg; { int code, id, len; int mlen, ulen, wlen; char *user, *pwd, *msg; u_char *pstart; if (plen < UPAP_HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < UPAP_HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *)) printer(arg, " %s", upap_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= UPAP_HEADERLEN; switch (code) { case UPAP_AUTHREQ: if (len < 1) break; ulen = p[0]; if (len < ulen + 2) break; wlen = p[ulen + 1]; if (len < ulen + wlen + 2) break; user = (char *) (p + 1); pwd = (char *) (p + ulen + 2); p += ulen + wlen + 2; len -= ulen + wlen + 2; printer(arg, " user="); print_string(user, ulen, printer, arg); printer(arg, " password="); print_string(pwd, wlen, printer, arg); break; case UPAP_AUTHACK: case UPAP_AUTHNAK: if (len < 1) break; mlen = p[0]; if (len < mlen + 1) break; msg = (char *) (p + 1); p += mlen + 1; len -= mlen + 1; printer(arg, "msg="); print_string(msg, mlen, printer, arg); break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } slirp-1.0.17/src/ppp/upap.h0000644000175000017500000000612410115276024014512 0ustar roverrover/* * upap.h - User/Password Authentication Protocol definitions. * * 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: upap.h,v 1.4 1995/06/12 12:02:25 paulus Exp $ */ /* * Packet header = Code, id, length. */ #define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) /* * UPAP codes. */ #define UPAP_AUTHREQ 1 /* Authenticate-Request */ #define UPAP_AUTHACK 2 /* Authenticate-Ack */ #define UPAP_AUTHNAK 3 /* Authenticate-Nak */ /* * Each interface is described by upap structure. */ typedef struct upap_state { int us_unit; /* Interface unit number */ char *us_user; /* User */ int us_userlen; /* User length */ char *us_passwd; /* Password */ int us_passwdlen; /* Password length */ int us_clientstate; /* Client state */ int us_serverstate; /* Server state */ u_char us_id; /* Current id */ int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */ int us_transmits; /* Number of auth-reqs sent */ int us_maxtransmits; /* Maximum number of auth-reqs to send */ int us_reqtimeout; /* Time to wait for auth-req from peer */ } upap_state; /* * Client states. */ #define UPAPCS_INITIAL 0 /* Connection down */ #define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ #define UPAPCS_PENDING 2 /* Connection down, have requested auth */ #define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ #define UPAPCS_OPEN 4 /* We've received an Ack */ #define UPAPCS_BADAUTH 5 /* We've received a Nak */ /* * Server states. */ #define UPAPSS_INITIAL 0 /* Connection down */ #define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ #define UPAPSS_PENDING 2 /* Connection down, have requested auth */ #define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ #define UPAPSS_OPEN 4 /* We've sent an Ack */ #define UPAPSS_BADAUTH 5 /* We've sent a Nak */ /* * Timeouts. */ #define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ #define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ extern upap_state upap[]; void upap_init __P((int)); void upap_authwithpeer __P((int, char *, char *)); void upap_authpeer __P((int)); void upap_lowerup __P((int)); void upap_lowerdown __P((int)); void upap_input __P((int, u_char *, int)); void upap_protrej __P((int)); int upap_printpkt __P((u_char *, int, void (*) __P((void *, char *, ...)), void *)); slirp-1.0.17/src/ppp.c0000644000175000017500000006166310115276014013550 0ustar roverrover/* * ppp.c - interface between SLiRP and ppp-2.1.2b package * * Copyright (c) 1995 Juha Pirkola * * 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 Juha Pirkola. * * THIS SOFTWARE IS PROVIDED ``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 * JUHA PIRKOLA 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. * * This file adds PPP functionality to SLiRP, a free SLIP emulator * by Danny Gasparovski, using the free PPP package ppp-2.1.2b * maintained by Paul Mackerras. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* #include */ #ifdef HAVE_TERMIOS_H #include #else #include #endif #include "ppp/ppp.h" #include "ppp/magic.h" #include "ppp/fsm.h" #include "ppp/lcp.h" #include "ppp/ipcp.h" #include "ppp/upap.h" #include "ppp/chap.h" #include "ppp/pppd.h" #include "ppp/pathnames.h" #include #include "ppp/ppp-comp.h" #include "ppp/bsd-comp.h" extern struct compressor ppp_bsd_compress; struct compressor *ppp_compressors[2] = { #if DO_BSD_COMPRESS &ppp_bsd_compress, #endif NULL }; extern struct protent prottbl[]; #define N_PROTO 5 /* Nr of protocol entries */ /* in prottbl */ /* Lookup table for checksum calculation. From RFC-1662 */ static unsigned short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; u_int32_t recv_async_map[NUM_PPP]; /* which received characters to ignore */ u_int32_t xmit_async_map[NUM_PPP][8]; /* which xmitted characters to escape */ int proto_field_comp[NUM_PPP]; /* compressing the protocol field ? */ int addr_field_comp[NUM_PPP]; /* compressing the address field ? */ FILE *logfile; /* where to log events */ int ppp_exit; /* Exit when PPP goes down */ /* * stuff character in the output buffer, escaped if mentioned * in xmit_async_map, and update the check sum */ void stuff_char(c, unit, outp) int c; int unit; struct ppp_out *outp; { c &= 0xff; if (in_xmap(c, unit)){ *outp->head++ = PPP_ESC; *outp->head++ = c^PPP_TRANS; } else *outp->head++ = c; outp->fcs = (outp->fcs >> 8) ^ fcstab[(outp->fcs ^ c) & 0xff]; } /* * Add a two byte check sum to the end of the outgoing packet */ void add_fcs(outp, unit) struct ppp_out *outp; int unit; { u_short s = outp->fcs; s ^= 0xffff; stuff_char(s & 0xff, unit, outp); stuff_char(s >> 8, unit, outp); } /* * check the check sum of an incoming frame */ int check_fcs(buff, len) u_char *buff; int len; { u_short fcs = PPP_FCS_INIT; u_char *c = buff; int i; for (i = 0; i < len ; i++, c++) fcs = (fcs >> 8) ^ fcstab[(fcs ^ *c) & 0xff]; if (fcs == PPP_FCS_GOOD) return 1; else { do_syslog(0, "check_fcs: Checksum error, packet length = %d", len); /* Spit out faulty packets when debugging. */ if(debug) { for(i=0;i < len ; i++) fprintf(logfile, "%c:%02x ", iscntrl(buff[i]) ? '.' : buff[i] , buff[i] & 0xff); fprintf(logfile, "\n"); } return 0; } } /* * IPCP tells us that the link is broken, we're not allowed * pass IP packets */ int sifdown(unit) int unit; { struct ttys *ttyp = ttys_unit[unit]; if (!ttyp) return 0; /* *shrug* */ ttyp->up = 0; do_syslog(0, "slirppp: PPP is down now"); return 1; } /* * IPCP says link is open, we can pass IP packets */ int sifup (unit) int unit; { struct ttys *ttyp = ttys_unit[unit]; if (!ttyp) return 0; /* *shrug* */ ttyp->up = 1; do_syslog(0, "slirppp: PPP is up now"); return 1; } /* * configure receive characteristics after negotiations * we don't really care about pcomp and accomp, because compression * can be directly detected from the incoming packet */ void ppp_recv_config (unit, mru, asyncmap, pcomp, accomp) int unit, mru; u_int32_t asyncmap; int pcomp, accomp; { recv_async_map[unit] = asyncmap; do_syslog(0, "ppp_recv_config: (recv) asyncmap set to %08lx", asyncmap); do_syslog(0, " : mru set to %d", mru); } /* * set the transmit asyncmap, in other words the characters to * be escaped when transmitted */ void ppp_set_xaccm(unit, accm) int unit; u_int32_t *accm; { memcpy(xmit_async_map[unit], accm, sizeof(accm[0]) * 8); do_syslog(0, "ppp_set_xaccm: extended xmit asyncmap set to %08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx", accm[7], accm[6], accm[5], accm[4], accm[3], accm[2], accm[1], accm[0]); } /* * configure our receive characteristic after negotiations */ void ppp_send_config (unit, mtu, asyncmap, pcomp, accomp) int unit, mtu; u_int32_t asyncmap; int pcomp, accomp; { if_mtu = MIN(mtu, if_mtu); do_syslog(0, "ppp_send_config: mtu set to %d", if_mtu); xmit_async_map[unit][0] = asyncmap; do_syslog(0, "ppp_send_config: (xmit) asyncmap set to %08lx", asyncmap); proto_field_comp[unit] = pcomp; if (pcomp) do_syslog(0, "ppp_send_config: compressing the protocol field"); addr_field_comp[unit] = accomp; if (accomp) do_syslog(0, "ppp_send_config: compressing the address field"); } /* * set TCP/IP header compression mode according to what * has been negotiated * I don't know what to do with cidcomp and maxcid * must fix later */ void sifvjcomp (unit, vjcomp, cidcomp, maxcid) int unit, vjcomp, cidcomp, maxcid; { if (vjcomp) { if_comp &= ~(IF_AUTOCOMP|IF_NOCOMPRESS); if_comp |= IF_COMPRESS; do_syslog(0, "sifvjcomp: Using VJ header compression"); } else { if_comp &= ~(IF_AUTOCOMP|IF_COMPRESS); if_comp |= IF_NOCOMPRESS; do_syslog(0, "sifvjcomp: Not using VJ header compression"); } if (cidcomp) { if_comp &= ~IF_NOCIDCOMP; } else { if_comp |= IF_NOCIDCOMP; } } /* * now we have a frame from ppp_input * if the protocol field says that it is an IP packet, copy * the it to a mbuf and deliver to slirps ip_input function */ void doframe(ttyp) struct ttys *ttyp; { u_short proto; int i, unit = ttyp->unit; struct mbuf *m = ttyp->m, *dmp = NULL; int rv; if (!check_fcs(mtod(m, u_char *), m->m_len)) { ttyp->sc_flags |= SC_VJ_RESET; ttyp->ifstats.in_errpkts++; ttyp->ifstats.in_errbytes += m->m_len; m_free(m); return; } m->m_len -= 2; /* Drop trailing fcs */ if (((u_char)m->m_data[0] == ALLSTATIONS) && (u_char)(m->m_data[1] == UI)) { m->m_data += 2; m->m_len -= 2; /* Drop address field */ } proto = (u_short)*(u_char *)m->m_data++; if (proto & 1) { m->m_len--; } else { /* XXX */ proto = (proto << 8) | ((u_short)*(u_char *)m->m_data++); m->m_len -= 2; /* Drop protocol field */ } do_syslog(0, "Received a packet of %d bytes, protocol = 0x%04x", m->m_len, proto); /* XXXXX HACK! */ if (m->m_len < 0) m->m_len = 0; /* * Decompress this packet if necessary, update the receiver's' * dictionary, or take appropriate action on a CCP packet. */ if (proto == PPP_COMP && ttyp->sc_rc_state && (ttyp->sc_flags & SC_DECOMP_RUN) && !(ttyp->sc_flags & SC_DC_ERROR) && !(ttyp->sc_flags & SC_DC_FERROR)) { /* decompress this packet */ rv = (*ttyp->sc_rcomp->decompress)(ttyp->sc_rc_state, m, &dmp); if (rv == DECOMP_OK) { m_free(m); if (dmp == NULL) { /* no error, but no decompressed packet produced */ return; } m = dmp; /* the first byte is the old protocol */ proto = (u_char)*m->m_data++; m->m_len--; } else { /* * An error has occurred in decompression. * Pass the compressed packet up to pppd, which may take * CCP down or issue a Reset-Req. */ ttyp->sc_flags |= SC_VJ_RESET; if (rv == DECOMP_ERROR) ttyp->sc_flags |= SC_DC_ERROR; else ttyp->sc_flags |= SC_DC_FERROR; } } else { if (ttyp->sc_rc_state && (ttyp->sc_flags & SC_DECOMP_RUN)) (*ttyp->sc_rcomp->incomp)(ttyp->sc_rc_state, m, proto); if (proto == PPP_CCP) ppp_ccp(ttyp, mtod(m, u_char *), m->m_len, 1); } if (ttyp->sc_flags & SC_VJ_RESET) { /* * XXX This may be inefficient... when the header is NOT * damaged, uncompressing it can get a good header, which * will help fast recovery... still... */ sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &comp_s); ttyp->sc_flags &= ~SC_VJ_RESET; ttyp->ifstats.in_errpkts++; ttyp->ifstats.in_errbytes += m->m_len; } /* * Align here because the proto field in PPP will unalign * the whole packet, and sl_uncompress_tcp grabs some IP * fields */ if (proto != PROTO_VJCOMP && ((long)m->m_data & 3)) { ipstat.ips_unaligned++; memmove((u_char *)(m->m_data - ((long)m->m_data & 3)), m->m_data, m->m_len); m->m_data -= ((long)m->m_data) & 3; } switch (proto) { case PROTO_VJUNCOMP: if (ttyp->up) { m->m_len = sl_uncompress_tcp((u_char **)&m->m_data, m->m_len, (u_int) TYPE_UNCOMPRESSED_TCP, &comp_s); } goto proto_ip; case PROTO_VJCOMP: if (ttyp->up) { m->m_len = sl_uncompress_tcp((u_char **)&m->m_data, m->m_len, (u_int) TYPE_COMPRESSED_TCP, &comp_s); } proto_ip: if (m->m_len < 0) goto dump; /* FALLTHROUGH */ case PROTO_IP: if (!ttyp->up) { dump: ttyp->ifstats.in_errpkts++; ttyp->ifstats.in_errbytes += m->m_len; m_free(m); break; } ttyp->ifstats.in_pkts++; ttyp->ifstats.in_bytes += m->m_len; ip_input(m); break; default: /* If LCP isn't up, and it's not an LCP, dump it */ if (proto != PPP_LCP && lcp_fsm[ttyp->unit].state != OPENED) { m_free(m); return; } for (i = 0; i < N_PROTO; i++) { if (prottbl[i].protocol == proto) { (*prottbl[i].input)(unit, mtod(m, u_char *), m->m_len); free_it: ttyp->ifstats.in_pkts++; ttyp->ifstats.in_bytes += m->m_len; m_free(m); return; } if (prottbl[i].datainput && proto == (prottbl[i].protocol & ~0x8000)) { (*prottbl[i].datainput)(unit, mtod(m, u_char *), m->m_len); goto free_it; } } /* lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); */ /* XXXXX */ m_free(m); return; } } /* * the main input routine corresponding to sl_input * I tried to make this similar to sl_input, but it was not * possible to write the unescaped data directly to a mbuf, * and therefore this is a bit different */ void ppp_input(ttyp, if_bptr, if_n) struct ttys *ttyp; u_char *if_bptr; int if_n; { DEBUG_CALL("ppp_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); DEBUG_ARG("if_bptr = %lx", (long)if_bptr); DEBUG_ARG("if_n = %d", if_n); for(; if_n; if_bptr++, if_n--) { if (*if_bptr == PPP_FLAG) { DEBUG_MISC((dfd, "ppp_flag")); if (ttyp->inpkt == 0) { DEBUG_MISC((dfd, "not inpkt")); continue; } if (ttyp->esc) { ttyp->ifstats.in_mbad++; ttyp->mbad = 1; DEBUG_MISC((dfd, "mbad")); } ttyp->m->m_len = (char *)ttyp->mptr - (char *)ttyp->m->m_data; if (!ttyp->mbad) { DEBUG_MISC((dfd, "doframe")) doframe(ttyp); } else { m_free(ttyp->m); do_syslog(0, "ppp_input: Got a bad frame of %d bytes", ttyp->m->m_len); } ttyp->m = 0; ttyp->inpkt = 0; continue; } /* We fall here if it was not PPP_FLAG */ if (ttyp->inpkt == 0) { /* new frame starting */ ttyp->inpkt = 1; ttyp->m = m_get(); ttyp->m->m_data += if_maxlinkhdr; /* Allow for uncompress */ ttyp->mptr = mtod(ttyp->m, u_char *); ttyp->msize = M_FREEROOM(ttyp->m); ttyp->esc = 0; ttyp->mbad = 0; } if (!ttyp->mbad) { if (*if_bptr == PPP_ESC) { DEBUG_MISC((dfd, "ppp_esc")); ttyp->esc = 1; ttyp->inpkt = 1; /* XXX */ } else if (!in_rmap(*if_bptr, ttyp->unit)) { if (ttyp->esc) { *ttyp->mptr++ = *if_bptr ^ PPP_TRANS; ttyp->esc = 0; } else *ttyp->mptr++ = *if_bptr; if (--ttyp->msize < 0) { ttyp->ifstats.in_mbad++; ttyp->mbad = 1; /* frame too long */ do_syslog(0, "ppp_input: Frame too long"); } } } } } /* * this is the output function SLiRP uses, corresponding to sl_encap. * data from a mbuf is encapsulated according to the HDLC-like * framing scheme (RFC-1662) and put to the buffer pointed by inbptr * Note: This is only called on PROT_IP packets, all other protocol * packets use output() */ int ppp_encap(inbptr, m, unit, ppp_esc, proto) char *inbptr; struct mbuf *m; int unit; int ppp_esc; int proto; { int i; int slen, clen; struct ppp_out out; struct mbuf *mcomp = NULL; struct ttys *ttyp = ttys_unit[unit]; DEBUG_CALL("ppp_encap"); DEBUG_ARG("inbptr = %lx", (long)inbptr); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("unit = %d", unit); DEBUG_ARG("ppp_esc = %lx", (long)ppp_esc); out.buff = out.head = (u_char *) inbptr; out.fcs = PPP_FCS_INIT; if (ppp_esc) *out.head++ = PPP_FLAG; /* * See what type of packet it is (returned by sl_compress_tcp) * and make proto into the corresponding PPP protocol number */ switch(proto) { case TYPE_IP: proto = PROTO_IP; break; case TYPE_UNCOMPRESSED_TCP: proto = PROTO_VJUNCOMP; break; case TYPE_COMPRESSED_TCP: proto = PROTO_VJCOMP; break; default: /* Shouldn't happen */ return -1; } if (ttyp->sc_xc_state && (ttyp->sc_flags & SC_COMP_RUN)) { slen = m->m_len; clen = (*ttyp->sc_xcomp->compress)(ttyp->sc_xc_state, &mcomp, m, slen, (ttyp->sc_flags & SC_CCP_UP ? if_mtu: 0), proto); if (mcomp != NULL) { ttyp->ifstats.bytes_saved += (slen - clen); m_free(m); m = mcomp; proto = PPP_COMP; } } if (!addr_field_comp[unit]) { stuff_char(ALLSTATIONS, unit, &out); stuff_char(UI, unit, &out); } if (!proto_field_comp[unit] || proto >= 0xff) stuff_char(proto >> 8, unit, &out); stuff_char(proto & 0xff, unit, &out); for(i = 0; i < m->m_len; i++) stuff_char(*(m->m_data + i), unit, &out); add_fcs(&out, unit); *out.head++ = PPP_FLAG; m_free(m); return (out.head - out.buff); } /* * this is the output routine used by the link level protocols * it writes directly to the tty */ void output(unit, p, len) int unit; u_char *p; int len; { #ifndef FULL_BOLT u_char outgoing[IF_OUTBUFFSIZE]; #endif int i; u_short proto; struct ppp_out out; struct ttys *ttyp; DEBUG_CALL("output (in ppp.c)"); DEBUG_ARG("unit = %d", unit); DEBUG_ARG("p = %lx", (long)p); DEBUG_ARG("len = %d", len); ttyp = ttys_unit[unit]; if (!ttyp) return; #ifndef FULL_BOLT out.buff = out.head = outgoing; #else /* XXXXX Kludge */ while ((len + ttyp->nbuff + 20 /* XXXXX */) > IF_OUTBUFFSIZE) { u_sleep(500); if_start(ttyp); } out.buff = out.head = ttyp->if_outbuff + ttyp->nbuff; #endif out.fcs = PPP_FCS_INIT; *out.head++ = PPP_FLAG; proto = PPP_PROTOCOL(p); /* * ppp_ccp expects no PPP header */ if (proto == PPP_CCP) ppp_ccp(ttyp, p + PPP_HDRLEN, len, 0); for (i = 0; i fd, (char *) outgoing, (out.head - out.buff)); #else ttyp->nbuff += (out.head - out.buff); if_start(ttyp); #endif } void die(status) int status; { slirp_exit(status); } /* * we seem to be using PPP - initialise a few things */ void ppp_init(ttyp) struct ttys *ttyp; { int i; /* * Check if it's already been init'd */ if (ttyp->proto == PROTO_PPP) return; for (i = 0; i < N_PROTO; i++) (*prottbl[i].init)(ttyp->unit); check_auth_options(ttyp->unit); setipdefault(ttyp->unit); magic_init(); ipcp_wantoptions[ttyp->unit].hisaddr = inet_addr(CTL_LOCAL); ttyp->proto = PROTO_PPP; ttyp->up = 0; ttyp->if_input = ppp_input; ttyp->if_encap = ppp_encap; ttyp->flags |= TTY_PPPSTART; /* Tell the main loop to call ppp_start on this ttyp */ } /* * tell the user what options we are going to negotiate * and then start the negotiation process */ void ppp_start(unit) int unit; { lcp_lowerup(unit); lcp_open(unit); } /* * The following functions (random, srandom, index, bcmp, gethostid) * are defined here for systems that don't have them. The pppd pack- * age was written for BSD systems that have these non-ANSI funcs */ #ifndef HAVE_RANDOM long random () { return rand(); } #endif #ifndef HAVE_SRANDOM void srandom (seed) int seed; { srand(seed); } #endif #ifndef HAVE_INDEX char * index(s, c) const char *s; int c; { return strchr(s, c); } #endif #ifndef HAVE_BCMP int bcmp(s1, s2, n) const void *s1, *s2; int n; { return memcmp(s1, s2, n); } #endif #ifndef HAVE_GETHOSTID long gethostid() { return 12345678; } #endif /* * We define our own syslog, because we are not running as a * system daemon but a normal user program. This will raise * compile warning, because in some environments syslog is * defined to return int, and in some others it is void */ void #ifdef __STDC__ real_do_syslog(int priority, const char *format, ...) #else real_do_syslog(va_alist) va_dcl #endif { va_list argp; #ifdef __STDC__ va_start(argp, format); #else int priority; char *format; va_start(argp); priority = va_arg(argp, int); format = va_arg(argp, char *); #endif vfprintf(logfile, format, argp); va_end(argp); fprintf(logfile, "\n"); fflush(logfile); } /* * The rest of the functions are there just to satisfy * lcp.c, ipcp.c etc. They don't really do anything but * return an acceptable value */ int sifaddr (unit, our_adr, his_adr, net_mask) int unit, our_adr, his_adr, net_mask; { return 1; } int cifaddr (unit, our_adr, his_adr) int unit, our_adr, his_adr; { return 1; } int sifdefaultroute (unit, gateway) int unit, gateway; { return 1; } int cifdefaultroute (unit, gateway) int unit, gateway; { return 1; } #ifdef LOGWTMP_WORKED /* I don't know why blocking this out solves so many problems with RedHat 6. But I'll do it anyway. It doesn't do much of anything, and only ppp/auth.c called it to begin with. --Kelly */ int logwtmp(line, name, host) char *line, *name, *host; { return 1; } #endif /* I like these better than worrying about comment nesting. :P */ int cifproxyarp (unit, his_adr) int unit; u_long his_adr; { return 1; } int sifproxyarp (unit, his_adr) int unit; u_long his_adr; { return 1; } int run_program(prog, args, must_exist) char *prog, **args; int must_exist; { return 0; } void print_string(p, len, printer, arg) char *p; int len; void (*printer) _P((void *, char *, ...)); void *arg; { } int ccp_test(unit, ccp_option, opt_len, for_transmit) int unit; u_char *ccp_option; int opt_len, for_transmit; { int nb; struct compressor **cp; struct ttys *ttyp = ttys_unit[unit]; nb = opt_len; if (ccp_option[1] < 2) return 0; for (cp = ppp_compressors; *cp != NULL; ++cp) if ((*cp)->compress_proto == ccp_option[0]) { /* * Found a handler for the protocol - try to allocate * a compressor or decompressor. */ if (for_transmit) { if (ttyp->sc_xc_state != NULL) (*ttyp->sc_xcomp->comp_free)(ttyp->sc_xc_state); ttyp->sc_xcomp = *cp; ttyp->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); if (ttyp->sc_xc_state == NULL) return 0; ttyp->sc_flags &= ~SC_COMP_RUN; } else { if (ttyp->sc_rc_state != NULL) (*ttyp->sc_rcomp->decomp_free)(ttyp->sc_rc_state); ttyp->sc_rcomp = *cp; ttyp->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); if (ttyp->sc_rc_state == NULL) return 0; ttyp->sc_flags &= ~SC_DECOMP_RUN; } return 1; } return 0; } void ccp_flags_set(unit, isopen, isup) int unit, isopen, isup; { struct ttys *ttyp = ttys_unit[unit]; int x = ttyp->sc_flags; x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN; x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP; ttyp->sc_flags = x; } int ccp_fatal_error(unit) int unit; { struct ttys *ttyp = ttys_unit[unit]; return ttyp->sc_flags & SC_DC_FERROR; } /* * Handle a CCP packet. rcvd' is 1 if the packet was received, * 0 if it is about to be transmitted. */ void ppp_ccp(ttyp, dp, len, rcvd) struct ttys *ttyp; u_char *dp; int len; int rcvd; { u_char *ep; int slen; ep = dp + len; if (dp + CCP_HDRLEN > ep) return; slen = CCP_LENGTH(dp); if (dp + slen > ep) return; switch (CCP_CODE(dp)) { case CCP_CONFREQ: case CCP_TERMREQ: case CCP_TERMACK: /* CCP must be going down - disable compression */ if (ttyp->sc_flags & SC_CCP_UP) { ttyp->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); } break; case CCP_CONFACK: if (ttyp->sc_flags & SC_CCP_OPEN && !(ttyp->sc_flags & SC_CCP_UP) && slen >= CCP_HDRLEN + CCP_OPT_MINLEN && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) { if (!rcvd) { /* we're agreeing to send compressed packets. */ if (ttyp->sc_xc_state != NULL && (*ttyp->sc_xcomp->comp_init) (ttyp->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, ttyp->unit, 0, 0 /* XXX debug */)) { ttyp->sc_flags |= SC_COMP_RUN; } } else { /* peer is agreeing to send compressed packets. */ if (ttyp->sc_rc_state != NULL && (*ttyp->sc_rcomp->decomp_init) (ttyp->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, ttyp->unit, 0, if_mru, 0 /* XXX debug */)) { ttyp->sc_flags |= SC_DECOMP_RUN; ttyp->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR); } } } break; case CCP_RESETACK: if (ttyp->sc_flags & SC_CCP_UP) { if (!rcvd) { if (ttyp->sc_xc_state && (ttyp->sc_flags & SC_COMP_RUN)) (*ttyp->sc_xcomp->comp_reset)(ttyp->sc_xc_state); } else { if (ttyp->sc_rc_state && (ttyp->sc_flags & SC_DECOMP_RUN)) { (*ttyp->sc_rcomp->decomp_reset)(ttyp->sc_rc_state); ttyp->sc_flags &= ~SC_DC_ERROR; } } } break; } } /* * * CCP is down; free (de)compressor state if necessary. * */ void ppp_ccp_closed(ttyp) struct ttys *ttyp; { if (ttyp->sc_xc_state) { (*ttyp->sc_xcomp->comp_free)(ttyp->sc_xc_state); ttyp->sc_xc_state = NULL; } if (ttyp->sc_rc_state) { (*ttyp->sc_rcomp->decomp_free)(ttyp->sc_rc_state); ttyp->sc_rc_state = NULL; } } slirp-1.0.17/src/ppp.p0000644000175000017500000000212610115325664013560 0ustar roverrovervoid stuff_char _P((int, int, struct ppp_out *)); void add_fcs _P((struct ppp_out *, int)); int check_fcs _P((u_char *, int)); int sifdown _P((int)); int sifup _P((int)); void ppp_recv_config _P((int, int, u_int32_t, int, int)); void ppp_set_xaccm _P((int, u_int32_t *)); void ppp_send_config _P((int, int, u_int32_t, int, int)); void sifvjcomp _P((int, int, int, int)); void doframe _P((struct ttys *)); void ppp_input _P((struct ttys *, u_char *, int)); int ppp_encap _P((char *, struct mbuf *, int, int, int)); void output _P((int, u_char *, int)); void die _P((int)); void ppp_init _P((struct ttys *)); void ppp_start _P((int)); int sifaddr _P((int, int, int, int)); int cifaddr _P((int, int, int)); int sifdefaultroute _P((int, int)); int cifdefaultroute _P((int, int)); int cifproxyarp _P((int, u_long)); int sifproxyarp _P((int, u_long)); int run_program _P((char *, char **, int)); int ccp_test _P((int, u_char *, int, int)); void ccp_flags_set _P((int, int, int)); int ccp_fatal_error _P((int)); void ppp_ccp _P((struct ttys *, u_char *, int, int)); void ppp_ccp_closed _P((struct ttys *)); slirp-1.0.17/src/sbuf.c0000644000175000017500000000775610115276014013713 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include /* Done as a macro in socket.h */ /* int * sbspace(struct sockbuff *sb) * { * return SB_DATALEN - sb->sb_cc; * } */ void sbfree(sb) struct sbuf *sb; { free(sb->sb_data); } void sbdrop(sb, num) struct sbuf *sb; int num; { /* * We can only drop how much we have * This should never succeed */ if(num > sb->sb_cc) num = sb->sb_cc; sb->sb_cc -= num; sb->sb_rptr += num; if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) sb->sb_rptr -= sb->sb_datalen; } void sbreserve(sb, size) struct sbuf *sb; int size; { if (sb->sb_data) { /* Already alloced, realloc if necessary */ if (sb->sb_datalen != size) { sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); sb->sb_cc = 0; if (sb->sb_wptr) sb->sb_datalen = size; else sb->sb_datalen = 0; } } else { sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); sb->sb_cc = 0; if (sb->sb_wptr) sb->sb_datalen = size; else sb->sb_datalen = 0; } } /* * Try and write() to the socket, whatever doesn't get written * append to the buffer... for a host with a fast net connection, * this prevents an unnecessary copy of the data * (the socket is non-blocking, so we won't hang) */ void sbappend(so, m) struct socket *so; struct mbuf *m; { int ret = 0; DEBUG_CALL("sbappend"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m->m_len = %d", m->m_len); /* Shouldn't happen, but... e.g. foreign host closes connection */ if (m->m_len <= 0) { m_free(m); return; } /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest * (The rest of this function is just an optimisation) */ if (so->so_urgc) { sbappendsb(&so->so_rcv, m); m_free(m); sosendoob(so); return; } /* * We only write if there's nothing in the buffer, * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) ret = write(so->s, m->m_data, m->m_len); if (ret <= 0) { /* * Nothing was written * It's possible that the socket has closed, but * we don't need to check because if it has closed, * it will be detected in the normal way by soread() */ sbappendsb(&so->so_rcv, m); } else if (ret != m->m_len) { /* * Something was written, but not everything.. * sbappendsb the rest */ m->m_len -= ret; m->m_data += ret; sbappendsb(&so->so_rcv, m); } /* else */ /* Whatever happened, we free the mbuf */ m_free(m); } /* * Copy the data from m into sb * The caller is responsible to make sure there's enough room */ void sbappendsb(sb, m) struct sbuf *sb; struct mbuf *m; { int len, n, nn; len = m->m_len; if (sb->sb_wptr < sb->sb_rptr) { n = sb->sb_rptr - sb->sb_wptr; if (n > len) n = len; memcpy(sb->sb_wptr, m->m_data, n); } else { /* Do the right edge first */ n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; if (n > len) n = len; memcpy(sb->sb_wptr, m->m_data, n); len -= n; if (len) { /* Now the left edge */ nn = sb->sb_rptr - sb->sb_data; if (nn > len) nn = len; memcpy(sb->sb_data,m->m_data+n,nn); n += nn; } } sb->sb_cc += n; sb->sb_wptr += n; if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) sb->sb_wptr -= sb->sb_datalen; } /* * Copy data from sbuf to a normal, straight buffer * Don't update the sbuf rptr, this will be * done in sbdrop when the data is acked */ void sbcopy(sb, off, len, to) struct sbuf *sb; int off; int len; char *to; { char *from; from = sb->sb_rptr + off; if (from >= sb->sb_data + sb->sb_datalen) from -= sb->sb_datalen; if (from < sb->sb_wptr) { if (len > sb->sb_cc) len = sb->sb_cc; memcpy(to,from,len); } else { /* re-use off */ off = (sb->sb_data + sb->sb_datalen) - from; if (off > len) off = len; memcpy(to,from,off); len -= off; if (len) memcpy(to+off,sb->sb_data,len); } } slirp-1.0.17/src/sbuf.h0000644000175000017500000000115710115276015013706 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _SBUF_H_ #define _SBUF_H_ #define sbflush(sb) sbdrop((sb),(sb)->sb_cc) #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) struct sbuf { u_int sb_cc; /* actual chars in buffer */ u_int sb_datalen; /* Length of data */ char *sb_wptr; /* write pointer. points to where the next * bytes should be written in the sbuf */ char *sb_rptr; /* read pointer. points to where the next * byte should be read from the sbuf */ char *sb_data; /* Actual data */ }; #endif slirp-1.0.17/src/sbuf.p0000644000175000017500000000041310115325664013715 0ustar roverrovervoid sbfree _P((struct sbuf *)); void sbdrop _P((struct sbuf *, int)); void sbreserve _P((struct sbuf *, int)); void sbappend _P((struct socket *, struct mbuf *)); void sbappendsb _P((struct sbuf *, struct mbuf *)); void sbcopy _P((struct sbuf *, int, int, char *)); slirp-1.0.17/src/sl.c0000644000175000017500000000744110115276014013361 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include /* * NOTE: FRAME_END means in_pkt = 0. Any other byte while in_pkt = 0 * means we're getting a packet now. */ void sl_input(ttyp, if_bptr, if_n) struct ttys *ttyp; u_char *if_bptr; int if_n; { DEBUG_CALL("sl_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); DEBUG_ARG("if_bptr = %lx", (long)if_bptr); DEBUG_ARG("if_n = %d", if_n); for (; if_n; if_bptr++, if_n--) { if (*if_bptr == FRAME_END) { if (ttyp->inpkt == 0) continue; if (ttyp->esc) { ttyp->ifstats.in_mbad++; ttyp->mbad = 1; } if (!ttyp->mbad) { ttyp->m->m_len = (char *)ttyp->mptr - (char *)ttyp->m->m_data; sl_dispatch(ttyp); } else { m_free(ttyp->m); /* XXX */ } ttyp->m = 0; ttyp->inpkt = 0; continue; } if (ttyp->inpkt == 0) { /* A new packet is arriving, setup mbufs etc. */ ttyp->inpkt = 1; ttyp->m = m_get(); ttyp->m->m_data += if_maxlinkhdr; /* Allow for uncompress */ ttyp->mptr = mtod(ttyp->m, u_char *); ttyp->msize = M_FREEROOM(ttyp->m); ttyp->esc = 0; ttyp->mbad = 0; } if (!ttyp->mbad) { if (*if_bptr == FRAME_ESCAPE) { ttyp->esc = 1; /* * Do the following in case the packet starts with FRAME_ESCAPE, * which shouldn't happen, but... */ ttyp->inpkt = 1; } else { if (ttyp->esc) { switch (*if_bptr) { case TRANS_FRAME_ESCAPE: *ttyp->mptr++ = FRAME_ESCAPE; break; case TRANS_FRAME_END: *ttyp->mptr++ = FRAME_END; break; default: /* XXX What to do? */ *ttyp->mptr++ = *if_bptr; } ttyp->esc = 0; } else *ttyp->mptr ++ = *if_bptr; if (--ttyp->msize < 0) { ttyp->ifstats.in_mbad++; ttyp->mbad = 1; } } } } } void sl_dispatch(ttyp) struct ttys *ttyp; { u_char c; struct mbuf *m = ttyp->m; if ((c = (u_char)*m->m_data & 0xf0) != (IPVERSION << 4)) { if (c & 0x80) c = TYPE_COMPRESSED_TCP; else if (c == TYPE_UNCOMPRESSED_TCP) *m->m_data &= 0x4f; /* XXX */ if (if_comp & IF_COMPRESS) m->m_len = sl_uncompress_tcp((u_char **)&m->m_data, m->m_len,(u_int)c, &comp_s); else if ((if_comp & IF_AUTOCOMP) && c == TYPE_UNCOMPRESSED_TCP) { m->m_len = sl_uncompress_tcp((u_char **)&m->m_data, m->m_len,(u_int)c, &comp_s); if (m->m_len > 0) { if_comp &= ~(IF_AUTOCOMP|IF_NOCOMPRESS); if_comp |= IF_COMPRESS; } } if (m->m_len > 0) { ttyp->ifstats.in_pkts++; ttyp->ifstats.in_bytes += m->m_len; ip_input(m); } else { ttyp->ifstats.in_errpkts++; ttyp->ifstats.in_errbytes += m->m_len; m_free(m); } } else { ttyp->ifstats.in_pkts++; ttyp->ifstats.in_bytes += m->m_len; ip_input(m); } } /* * Copy data from m to inbptr, applying SLIP encapsulation * Returns number of bytes in inbptr */ int sl_encap(inbptr, m, unit, sl_esc, proto) char *inbptr; struct mbuf *m; int unit; int sl_esc; int proto; { u_char *mptr; int mlen; char *bptr = inbptr; DEBUG_CALL("sl_encap"); DEBUG_ARG("inbptr = %lx", (long)inbptr); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("unit = %d", unit); DEBUG_ARG("sl_esc = %d", sl_esc); mptr = mtod(m, u_char *); *mptr |= proto; /* SLIP encodes the protocol in the first 4 bits */ mlen = m->m_len; /* * Prepend a FRAME_ESCAPE if no data is * being sent, to flush any line-noise. */ if (sl_esc) *bptr++ = FRAME_END; while(mlen--) { switch (*mptr) { case FRAME_END: *bptr++ = FRAME_ESCAPE; *bptr++ = TRANS_FRAME_END; mptr++; break; case FRAME_ESCAPE: *bptr++ = FRAME_ESCAPE; *bptr++ = TRANS_FRAME_ESCAPE; mptr++; break; default: *bptr++ = *mptr++; } } *bptr++ = FRAME_END; m_free(m); return bptr - inbptr; } slirp-1.0.17/src/sl.h0000644000175000017500000000101710115276015013360 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define FRAME_END 0xc0 /* Frame End */ #define FRAME_ESCAPE 0xdb /* Frame Esc */ #define TRANS_FRAME_END 0xdc /* transposed frame end */ #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ extern int if_n; extern struct mbuf if_fastq; extern struct mbuf if_batchq; extern int if_queued, if_thresh; slirp-1.0.17/src/sl.p0000644000175000017500000000022110115325665013372 0ustar roverrovervoid sl_input _P((struct ttys *, u_char *, int)); void sl_dispatch _P((struct ttys *)); int sl_encap _P((char *, struct mbuf *, int, int, int)); slirp-1.0.17/src/slcompress.c0000644000175000017500000003515510115276014015140 0ustar roverrover/*- * Copyright (c) 1989, 1993, 1994 * 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. * * @(#)slcompress.c 8.2 (Berkeley) 4/16/94 * slcompress.c,v 1.4 1994/10/08 22:38:27 phk Exp */ /* * Routines to compress and uncompress tcp packets (for transmission * over low speed serial lines. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. * */ #include struct slcompress comp_s; #define INCR(counter) ++comp->counter; #define MEMCMP(p1, p2, n) memcmp((char *)(p1), (char *)(p2), (int)(n)) #define MEMCPY(p1, p2, n) memcpy((char *)(p1), (char *)(p2), (int)(n)) void sl_compress_init(comp) struct slcompress *comp; { register u_int i; register struct cstate *tstate = comp->tstate; memset((char *)comp, 0, sizeof(*comp)); for (i = MAX_STATES - 1; i > 0; --i) { tstate[i].cs_id = i; tstate[i].cs_next = &tstate[i - 1]; } tstate[0].cs_next = &tstate[MAX_STATES - 1]; 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_int16_t)(n) >= 256) { \ *cp++ = 0; \ cp[1] = (n); \ cp[0] = (n) >> 8; \ cp += 2; \ } else { \ *cp++ = (n); \ } \ } #define ENCODEZ(n) { \ if ((u_int16_t)(n) >= 256 || (u_int16_t)(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_int32_t)*cp++); \ } \ } #define DECODES(f) { \ if (*cp == 0) {\ (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ cp += 3; \ } else { \ (f) = htons(ntohs(f) + (u_int32_t)*cp++); \ } \ } #define DECODEU(f) { \ if (*cp == 0) {\ (f) = htons((cp[1] << 8) | cp[2]); \ cp += 3; \ } else { \ (f) = htons((u_int32_t)*cp++); \ } \ } u_int sl_compress_tcp(m, ip, comp, compress_cid) struct mbuf *m; register 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->m_len < 40) return (TYPE_IP); th = (struct tcphdr *)&((int32_t *)ip)[hlen]; if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) 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 || *(int32_t *)th != ((int32_t *)&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 && *(int32_t *)th == ((int32_t *)&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; hlen += th->th_off; hlen <<= 2; 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 *)&((int32_t *)&cs->cs_ip)[hlen]; deltaS = hlen; hlen += th->th_off; hlen <<= 2; if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] || ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] || ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] || th->th_off != oth->th_off || (deltaS > 5 && MEMCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || (th->th_off > 5 && MEMCMP(th + 1, oth + 1, (th->th_off - 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_int16_t)(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; if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { comp->last_xmit = cs->cs_id; hlen -= deltaS + 4; cp += hlen; *cp++ = changes | NEW_C; *cp++ = cs->cs_id; } else { hlen -= deltaS + 3; cp += hlen; *cp++ = changes; } m->m_len -= hlen; m->m_data += 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(bufp, len, type, comp) 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; register u_int16_t *bp; 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; hlen = ip->ip_hl; hlen += ((struct tcphdr *)&((int32_t *)ip)[hlen])->th_off; hlen <<= 2; 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++; 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) 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) 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); /* * 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; if ((long)cp & 3) { if (len > 0) (void) memmove(cp - ((long)cp & 3), cp, len); ipstat.ips_unaligned++; cp -= (long)cp & 3; } 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 */ { bp = (u_int16_t *)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); } slirp-1.0.17/src/slcompress.h0000644000175000017500000001465110115276015015144 0ustar roverrover/* slcompress.h 8.1 93/06/10 */ /* * Definitions for tcp compression routines. * * Copyright (c) 1989, 1993 * 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. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. * slcompress.h,v 1.5 1994/08/22 14:16:36 bde Exp */ #ifndef _NET_SLCOMPRESS_H_ #define _NET_SLCOMPRESS_H_ #define MAX_STATES 16 /* must be > 2 and < 256 */ #define MAX_HDR 128 /* MLEN */ /* 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, * acknowledgement, 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; 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 */ 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 struct slcompress comp_s; #endif /* !_NET_SLCOMPRESS_H_ */ slirp-1.0.17/src/slcompress.p0000644000175000017500000000032410115325665015152 0ustar roverrovervoid sl_compress_init _P((struct slcompress *)); u_int sl_compress_tcp _P((struct mbuf *, register struct ip *, struct slcompress *, int)); int sl_uncompress_tcp _P((u_char **, int, u_int, struct slcompress *)); slirp-1.0.17/src/slirp.h0000644000175000017500000001177010115276015014102 0ustar roverrover#ifndef __COMMON_H__ #define __COMMON_H__ #include "version.h" #include #include #ifdef HAVE_SYS_BITYPES_H # include #endif #ifdef NEED_TYPEDEFS typedef char int8_t; typedef unsigned char u_int8_t; # if SIZEOF_SHORT == 2 typedef short int16_t; typedef unsigned short u_int16_t; # else # if SIZEOF_INT == 2 typedef int int16_t; typedef unsigned int u_int16_t; # else #error Cannot find a type with sizeof() == 2 # endif # endif # if SIZEOF_SHORT == 4 typedef short int32_t; typedef unsigned short u_int32_t; # else # if SIZEOF_INT == 4 typedef int int32_t; typedef unsigned int u_int32_t; # else #error Cannot find a type with sizeof() == 4 # endif # endif #endif /* NEED_TYPEDEFS */ #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #include #include #ifndef HAVE_MEMMOVE #define memmove(x, y, z) bcopy(y, x, z) #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_STRING_H # include #else # include #endif #include #ifndef _P #ifndef NO_PROTOTYPES # define _P(x) x #else # define _P(x) () #endif #endif #include #include #ifdef GETTIMEOFDAY_ONE_ARG #define gettimeofday(x, y) gettimeofday(x) #endif /* Systems lacking strdup() definition in . */ #if defined(ultrix) char *strdup _P((const char *)); #endif /* Systems lacking malloc() definition in . */ #if defined(ultrix) || defined(hcx) void *malloc _P((size_t arg)); void free _P((void *ptr)); #endif #ifndef HAVE_INET_ATON int inet_aton _P((const char *cp, struct in_addr *ia)); #endif #include #ifndef NO_UNIX_SOCKETS #include #endif #include #ifdef HAVE_SYS_SIGNAL_H # include #endif #include #if defined(WANT_SYS_IOCTL_H) && defined(HAVE_SYS_IOCTL_H) # include #else # define WANT_SYS_TERMIOS_H #endif #ifdef WANT_SYS_TERMIOS_H # ifndef INCLUDED_TERMIOS_H # ifdef HAVE_TERMIOS_H # include # else # include # endif # define INCLUDED_TERMIOS_H # endif #endif #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_SYS_FILIO_H # include #endif #ifdef USE_PPP #include #endif #ifdef __STDC__ #include #else #include #endif #include /* Avoid conflicting with the libc insque() and remque(), which have different prototypes. */ #define insque slirp_insque #define remque slirp_remque #ifdef HAVE_SYS_STROPTS_H #include #endif #include "debug.h" #include "ip.h" #include "tcp.h" #include "tcp_timer.h" #include "tcp_var.h" #include "tcpip.h" #include "udp.h" #include "icmp_var.h" #include "terminal.h" #include "mbuf.h" #include "sbuf.h" #include "socket.h" #include "if.h" #include "slcompress.h" #include "main.h" #include "misc.h" #include "options.h" #include "ctl.h" #include "sl.h" #ifdef USE_PPP #include "ppp/pppd.h" #include "ppp/ppp.h" #endif #include "ttys.h" extern struct ttys *ttys_unit[MAX_INTERFACES]; #ifndef NULL #define NULL (void *)0 #endif #ifndef FULL_BOLT void if_start _P((void)); #else void if_start _P((struct ttys *)); #endif #ifdef BAD_SPRINTF # define vsprintf vsprintf_len # define sprintf sprintf_len extern int vsprintf_len _P((char *, const char *, va_list)); extern int sprintf_len _P((char *, const char *, ...)); #endif #ifdef DECLARE_SPRINTF # ifndef BAD_SPRINTF extern int vsprintf _P((char *, const char *, va_list)); # endif extern int vfprintf _P((FILE *, const char *, va_list)); #endif #ifndef HAVE_STRERROR extern char *strerror _P((int error)); #endif #ifndef HAVE_RANDOM long random _P((void)); #endif #ifndef HAVE_SRANDOM void srandom _P((int)); #endif #ifndef HAVE_INDEX char *index _P((const char *, int)); #endif #ifndef HAVE_BCMP int bcmp _P((const void *, const void *, int)); #endif #ifndef HAVE_GETHOSTID long gethostid _P((void)); #endif void lprint _P((const char *, ...)); extern int do_echo; #if SIZEOF_CHAR_P == 4 # define insque_32 insque # define remque_32 remque #else inline void insque_32 _P((void *, void *)); inline void remque_32 _P((void *)); #endif #include #include #define DEFAULT_BAUD 115200 #include #include #include #include #include #include #include #include #include #ifdef USE_PPP #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_PPP #define MIN_MRU MINMRU #define MAX_MRU MAXMRU #else #define MIN_MRU 128 #define MAX_MRU 16384 #endif #endif slirp-1.0.17/src/slirp.man0000644000175000017500000011407207156473774014453 0ustar roverrover.TH SLIRP 1 "9 Jan 1996" "Version 1.0b" .\" Start displayed text macro .de DS .nf .na .. .\" End displayed text macro .de DE .ad .fi .. .SH NAME slirp \- TCP/IP emulator .SH SYNOPSIS slirp [options|commands] .br slirp help .br slirp "help \fIcmd\fP" .SH DESCRIPTION Slirp is a TCP/IP emulator which turns an ordinary shell account into a (C)SLIP/PPP account. This allows shell users to use all the funky Internet applications like Netscape, Mosaic, CUSeeMe, etc. .PP Slirp is copyright (c) 1995 Danny Gasparovski. All rights reserved. See the section COPYRIGHT for details. .PP This manpage is organized as follows. First, basic usage is described very briefly. This is followed by details of configuration files, commands, and command-line options. Several sections discussing technical issues (special addresses, port redirection, baudrate setting) are next, followed by answers to frequently-asked questions and common problems. Contact information, acknowledgements and the copyright notice are at the end. .PP Please read this manpage thoroughly before reporting problems! .SH USAGE To run Slirp, simply type: .DS slirp .DE (or whatever the full path to Slirp is). That's it. Now you activate your SLIP/PPP software, and start your applications. .PP All you have to remember is this: Once you run Slirp, your shell account now looks exactly like a SLIP/PPP account (with some limitations of course). Any documentation that you have telling you how to connect to a SLIP/PPP account is completely valid for Slirp as well. .PP To quit Slirp you simply kill your SLIP/PPP software and type five 0's (zeroes), with a 1 second gap between each zero. Slirp will then exit and you will be back at your shell prompt. .PP You can also "disconnect" Slirp by typing five 1's (one's), with a 1 second gap between each. This will disconnect Slirp from your shell's terminal and put Slirp in the background. Later, you can type .DS slirp -l 0 .DE to "reconnect" Slirp again. .PP Quick note for PDA users: If you set SLIRP_TTY to the tty connected to your PDA (Palm, POSE emulator, etc.), Slirp will use that tty for communication. You can use PPP without full masquerading, although you will be subject to the standard Slirp constraints. You may need to experiment to find the correct baud rate. Start with 19200 for Palms. If Slirp was not compiled with DO_CFSETSPEED, you'll need to set the speed on the tty manually. Use an appropriate variant of "stty 19200 < /dev/pilot" after starting slirp. .SH "CONFIGURING SLIRP" .I Slirp can be configured in 3 different ways: the command line, the configuration files, and "on-the-fly" configuration by telnet-ing to 10.0.2.0 and entering the commands there (see "SPECIAL ADDRESSES," below). .PP The configuration file is located in your home directory (~) and is called ".slirprc", hence the path to your configuration file is "~/.slirprc". .PP Options which can appear in a configuration file can also be given on the command line. E.g., If your .slirprc file looks like the following: .DS redir 5022 21 redir X .DE you can achieve the same thing by running Slirp as: .DS slirp "redir 5022 21" "redir X" .DE (Notice the quotes, they ARE significant). The reverse is also true. E.g., if you run slirp as: .DS slirp -P -b 14400 .DE you can create your .slirprc file too look like the following: .DS -P -b 14400 .DE (Notice that only ONE command per line is allowed in configuration files). The 2 types of options can also be mixed. For example: .DS In .slirprc: -P -b 14400 redir 5022 21 Command line: slirp -P -b 14400 "redir 5022 21" .DE Note that on the command line, any command/option that does not begin with a '-' or '+', and has spaces in it, MUST be enclosed in quotes. E.g., The following are all legal: .DS slirp -P "redir udp 5022 25" -vj -b 14400 slirp "ppp" "baudrate 14400" slirp ppp "baudrate 14400" .DE (Notice that even though "ppp" does not begin with a '-' or '+', it does not need to be enclosed in quotes because it has no spaces in it) .PP The following are NOT legal: .DS slirp baudrate 14400 slirp "-b 14400" .DE (Because "-b" starts with a '-' you must NOT enclose it in quotes.) Easy, eh? .PP Note: Whenever Slirp expects an IP address as an argument (E.g., in the command "redir") and the IP address argument is not given, then the default used is different depending on where the command appeared; if it was in ~/.slirprc then the default is 10.0.2.15; if it was in a telnet 10.0.2.0, then the IP address used is the IP address from where the telnet 10.0.2.0 connection was made. For example, if you have a LAN at home and telnet to 10.0.2.0 from one of the hosts and issue a "redir" command, Slirp will use the IP address of the host from where you made the telnet 10.0.2.0 connection. Also, if you use an IP address on your PC other than 10.0.2.15, you should include it as an argument whenever Slirp expects it, for example with the redir command: .DS redir 5555 your.ip.address:5555 .DE .PP A few notes on configuration: .RS 2 .IP * 2 You should have "ppp" or "-P" before any PPP options (because when Slirp parses -P or ppp, it will initialize all related fields, hence clearing anything that was parsed before it). .IP * 2 Upon startup, the configuration is done in this order: .RS .IP 1) 3 ~/.slirprc-N (if using Load-balancing or Link-resumption) .IP 2) 3 ~/.slirprc .IP 3) 3 Command-line options .RE .IP \ 2 This is important because, for example, if you have "initiate-options" (a PPP option) in ~/.slirprc-0, and you run slirp with -P, "initiate-options" will not be valid, because -P will clear the fact that you want options initiated by Slirp (remember, -P should always come before any PPP options). .RE .SH "COMMANDS AND OPTIONS" Slirp includes an "online-help" facility. To get a list of commands accepted by Slirp give it the command "help". I.e, you can either run Slirp from your shell prompt as: .DS slirp "help" .DE or once Slirp is running, telnet to 10.0.2.0 and type: .DS help .DE To get a brief description of each command simply type "help COMMAND". E.g.: .DS slirp "help baudrate" .DE from the command line, or .DS help baudrate .DE in telnet to 10.0.2.0. .PP In the following descriptions, items within square brackets are optional. "Usable" refers to where it can be used, ie: "command-line/config-file", "telnet", or "anywhere" (which means it can appear in either command-line/config-file or be given via telnet). "Command-line" gives the command-line equivalent, where applicable. .IP "redir X [start N] [ADDR][:DISPLAY[.SCREEN]]" .RS 4 Redirect a port for use with the X Window System. .br Usable: anywhere .br Command-line: -X .br Options: .RS 2 .IP "start N" 4 Tell slirp to start looking for free ports starting from N. eg: if N = 2, slirp will try to grab port 6002 then 6003 etc. this is useful for sites which sometimes run their own X server and you don't want to nab their port 6000, which they would naturally expect. .IP ADDR 4 Our home ip address, or the address where the X server is (if you have a LAN at home to connect more than one machine to the net) (default 10.0.2.15 when in ~/.slirprc, the source IP address when in command-line). .IP DISPLAY 4 Which display to redirect to (default :0). .IP SCREEN 4 Which screen to redirect to (default .0). .RE .PP Example: redir X 10.0.2.15:0.0 .PP Note: This will print the command needed to enter into each shell from where you launch your X apps. .PP See also: show X. .RE .IP "show X" .RS 4 Show the command that needs to be given to your shell for any X port that has been redirected (in case you forget). .PP Usable: telnet .PP Example: show X .PP Note: This is useful if you forget the command to give to your shell for X redirection. .PP See also: redir X, log start. .RE .IP "redir [once|time] [udp|tcp] PORT [to] [ADDRESS:]LPORT" .RS 4 Redirect host port to local port using a selected protocol. .br Usable: anywhere .br Options: .RS 2 .IP once 8 Only allow one redirection [TCP only] .IP time 8 Allow redirection to time out [UDP only] .IP udp 8 Redirect a UDP port .IP tcp 8 Redirect a TCP port [default] .IP PORT 8 Port to use on host system .IP ADDRESS 8 Address of your home machine [default 10.0.2.15] .IP LPORT 8 Port to redirect host port to on local system .RE .PP Example: redir tcp 5021 to 21 .br Allow users to ftp to your local machine using your host's port 21. (ftp your.hosts.name 5021). .PP Note: if this command is in your .slirprc file and no address is specified, it will assume that your local IP address is 10.0.2.15. If you enter the command from the slirp control telnet IP it will use the IP address you are accessing with. .RE .IP "baudrate N" .RS 4 Controls the allocation of time to communications across your serial link. Higher values generally use more of the available bandwidth to your modem. This is _only_ an internal control value and does _not_ change the physical settings for the host port or modem. .br Usable: anywhere .br Command-line: -b .PP Example: baudrate 14400 .PP Note: higher numbers generally allow better transfer rates for ftp sessions, but interactive sessions could become less responsive. the optimum value is *JUST* when ftp sessions reach maximum throughput, but this can be hard to find (especially on compressing modems) so you should choose the maximum throughput you would expect from your modem. .RE .IP "special|control|host addr ADDRESS" .RS 4 Set ip address aliases and others for slirp. .br Usable: anywhere .br Options: .RS 2 .IP "special address" 4 Set the network ip alias for slirp .IP "control address" 4 Only allow access to slirp control address from ADDRESS. .IP "host address" 4 Tell slirp the IP address of the host it's running on. Use this only if slirp can't properly find the host's IP address. .RE .PP Example: special address 10.0.3.0 .PP Note: The ADDRESS for special must end in 0 (zero) and other addresses are classed from this. The default special address is 10.0.2.0 giving the following defined IP's: .DS 10.0.2.0 slirp control telnet IP 10.0.2.1 slirp exec IP 10.0.2.2 slirp host alias 10.0.2.x add [pty]exec optional address .DE .RE .IP "add [pty]exec PROGRAM:[ADDRESS:]PORT" .RS 4 Set program to execute on host when local machine attempts to connect to ADDRESS at port PORT. .br Usable: anywhere .br Options: .RS 2 .IP exec 8 Establish binary connection to program in the style of inetd. .IP ptyexec 8 Establish telnet connection to program using telnetd helper application under a pseudo-terminal. .IP PROGRAM 8 Program to exec .IP ADDRESS 8 Optional address .IP PORT 8 Port .RE .PP Example: add ptyexec csh:55 .br A telnet connection to the slirp exec IP (default 10.0.2.1) will start and connect you directly to the csh program on the host. (telnet 10.0.2.1 55). .PP Example: add exec nntpd:10.0.2.3:119 .br A program that attempts to open port 119 at address 10.0.2.3 will be connected to the nntpd program. .PP Note: The use of the ptyexec form requires the slirp.telnetd helper application be available on your path. Also note that ADDRESS must be of the form SPECIAL_ADDRESS.xx (10.0.2.xx by default). .RE .IP "[no]compress" .RS 4 Force startup mode for slirp to SLIP or CSLIP. This overrides the default automatic mode determination. .PP Example: nocompress .br Start in SLIP mode. .PP Example: compress .br Start in CSLIP mode. .PP Note: The default method of operation generally performs well. You should only have to use this command if you find that your host and local system are failing synchronize the connection type. .RE .IP "mtu N" .RS 4 Controls the size of the IP packets sent across the serial IP link. Valid values are <= 1500. .PP Example: mtu 1500 Set the mtu to its largest allowable size. .PP Note: Larger values generally improve the performance of graphics web browsers and ftp transfers across the serial link, at the expense of interactive performance. The default value of 552 seems to be a reasonable compromise for connections at 14400 baud. .RE .IP "shell PROGRAM" .RS 4 Set program to execute on EXEC IP default telnet port (23). .PP This is the same as .DS add ptyexec PROGRAM:23 .DE Note: By default slirp connects /bin/sh to the exec IP telnet port. .RE .IP "help [COMMAND]" .RS 4 Show a brief list of available commands, or more information on the named command. .RE .IP "remove [pty]exec PROGRAM:[ADDRESS/]PORT" .RS 4 Reverse the effect of "add [pty]exec". see "add [pty]exec" for the options etc. .PP Note: you must enter the options exactly as you entered it in add [pty]exec. .PP **This description is incomplete.** .RE .IP "echo [on|off]" .RS 4 Turn echo on or off, depending on how your client behaves. "echo" by itself will show whether echo is currently on or off. .RE .IP "kill N" .RS 4 Kill the session which has a Socket no. of N. to find the Socket no. of a particular session, use the "stats socket" commands. See "stats" below. .PP Note: It is recommended you use "close N" instead, as this merely wipes out the session, whereas "close N" closes it properly, as a good little tcpip-emulator should :) .PP "kill -1" shouldn't be used, it will kill the first session it finds with -1, which usually is the command-line connection. .RE .IP "close N" .RS 4 Close the session which has a Socket no. of N. same as "kill N", but closes it session gracefully. See "kill N". .RE .IP "stats [ip|socket|tcp|vj|udp|mbuf|tty|alltty|others?]" .RS 4 Show statistics on the given argument. .br Options: .RS 2 .IP ip 7 Show ip statistics. .IP socket 7 Show statistics on the currently active sockets. Use this to find out which sessions to close/kill as it will also show the FD of the session. .IP tcp 7 Show tcp statistics (packets sent, received, etc). .IP udp 7 Same as tcp but for udp. .IP mbuf 7 Show how many mbufs were allocated, are in use, etc. If the modem is idle, and there are more than 1 mbufs on the used list, it suggests an mbuf leak. .RE .RE .IP "[pty]exec PROGRAM" .RS 4 This will execute PROGRAM, and the current command-line session will cease to exist, taken over by the PROGRAM. ie: when the program exits, you will not get the command-line back, the session will (should) close. .RE .IP "socket [PORT,PASSWORD]" .RS 4 Create a Unix-domain socket and listen() for more interfaces to connect. This is also needed for restarting. Give the arguments PORT,PASSWORD if you wish to use Internet-domain sockets instead of UNIX-domain sockets. .RE .IP "log start" .RS 4 Log all the startup output to the file .slirp_start. .RE .IP "add emu SERVICE[:TYPE_OF_SERVICE] [lport:]fport" .RS 4 Tell slirp to emulate SERVICE when on port lport/fport. .br Options: .RS 2 .IP SERVICE Can be: ftp, ksh, irc, none. .IP TYPE_OF_SERVICE Can be: throughput, lowdelay. .IP LPORT Can be given if that service needs emulation for, say, servers. .RE .PP Example: add emu ftp 8021 .br If you wish to ftp to somewhere on port 8021. .PP Example: add emu ftp 8021:0 .br If your home ftp server is on port 8021. NOTE: this does NOT mean if you redirect port 8021 for your ftp daemon, it refers the the port AT HOME at which ftpd is listening to. .PP Example: add emu none:lowdelay 8000 .br If you telnet somewhere on port 8000, and you wish those packets to go on the fastq (ie: so they have a higher priority than, say, ftp packets). This tells slirp that any packets destined for port 8000 will not have any emulation, but it will be set IPTOS_LOWDELAY. .RE .IP "dns DNS_IP" .RS 4 Give this to slirp if you want to use 10.0.2.3 as an alias for DNS, AND slirp guesses wrong for the DNS on startup. .RE .SH "TECHNICAL TOPICS" .SH " Special Addresses" All addresses of the form 10.0.2.xxx are special to Slirp (this can be changed with the "special addr" command). The following is a description of what each of the addresses mean: .IP "10.0.2.0" This is the Slirp "on-line" configuration address. When you telnet to 10.0.2.0 you can close connections, configure Slirp, redirect ports, etc. all while Slirp is running. Please read the section "CONFIGURING SLIRP" for details on how to use this. .IP "10.0.2.1" This is the address used by Slirp to execute programs. For example, if you give Slirp the command "add exec /bin/ls:23", when a connection is made to 10.0.2.1 on port 23, Slirp will execute /bin/ls and redirect the output to that connection. E.g., with "add exec /bin/ls:23", if you telnet to 10.0.2.1 (telnet uses port 23) you will get a list of files in the directory Slirp was started. Another example could be "add exec /path/to/nntpd:119". Now you can tell your News reader to use 10.0.2.1 as the News host and it will actually connect to the running program "nntpd". .IP "10.0.2.2" This is an alias for the remote host. When you connect to 10.0.2.2 you will actually connect to the host Slirp is running on. This is useful if your shell account can be on different hosts, 10.0.2.2 will always mean the host Slirp is running on. .IP "10.0.2.3" This is an alias for your DNS. Slirp will try to figure out your DNS address and all data sent to 10.0.2.3 will be redirected to your DNS address, so you can tell your TCP/IP software to use 10.0.2.3 as your DNS. This can also be useful if your run Slirp from multiple hosts; you don't need to change your DNS for each host. .IP "10.0.2.15" This is the address recommended by Slirp to be used on your PC. However this is merely a suggestion, Slirp does not care what address you use. .SH " Port Redirection" Port redirection is an important concept in TCP/IP emulators because it allows other people to connect to your PC, as well as allowing some programs to work which normally would not work. .SH " How do I Redirect a Port?" First you need to realize that under Slirp, nobody on the Internet can address your PC directly, since you do NOT have an IP address that anybody else can see. The ONLY way they can contact you is through the remote host (where Slirp is running). .PP What has this got to do with Port redirection? Lots. For other people on the Internet to be able to connect to your PC, Slirp needs to listen for connections on a specific port on the remote host, then "redirect" this connection and have it connect back to your PC. .PP For example, say you are running an FTP server on your PC and you want others to be able to connect to it, get files, upload files, etc. What you need to do is pick a port number, any port number above 1024 (for security reasons), and tell Slirp that any connections on that port are really connections to your FTP server. You do this with the "redir" command. .PP For this example, say you choose 5555 as the port to redirect (this can be ANY number, provided nobody else is using it). You simply give Slirp the command: .DS redir 5555 21 .DE The second argument, 21, is the port that is used by FTP. You could have also used the command: .DS redir 5555 ftp .DE and Slirp will figure out that "ftp" means 21. This command is basically telling Slirp "any connections to this host (where Slirp is running) on port 5555 are really connections to the home PC on port 21 (the port used by the FTP server)". .PP Now you simply tell others to connect to the Remote Host (where Slirp is running), which IS visible on the Internet, on port 5555 and they will be connected to your FTP server. .PP This same technique is used when a program uses a specific port for communication, for example Kali, an IPX emulator over TCP/IP allowing users to run IPX games over the Internet. Kali uses UDP port 2213 for communication so for others to be able to send a packet to your PC on UDP port 2213 you need to do the following: .DS redir udp 2213 2213 .DE All packets now destined for the Remote Host on UDP port 2213 will be sent to your PC on port 2213. .SH " Common Port Redirections" Here is a list of programs which need a port redirection to work. YOUR_PC_ADDRESS refers to the IP address you assigned to your PC. If it is not supplied, 10.0.2.15 is assumed. .IP Kali 3 redir udp 2213 YOUR_PC_ADDRESS:2213 .br (Note: you MUST also set your PC's IP address to the same IP address as the Remote Host (where Slirp is running)) .IP IPhone redir udp 22555 YOUR_PC_ADDRESS:22555 .IP StreamWorks redir udp 8000 YOUR_PC_ADDRESS:8000 .br (the 8000 is configurable) .IP PowWow redir tcp 13223 YOUR_PC_ADDRESS:13223 .IP WebPhone redir tcp 21845 YOUR_PC_ADDRESS:21845 .br redir udp 21845 YOUR_PC_ADDRESS:21845 .br (Note: WebPhone uses BOTH tcp and udp port 21845. In addition, you probably need to set your PC's address to the same IP address as the RemoteHost in order to get full functionality) .PP Please let me know of other programs which require redirection like the above. See "GETTING HELP" for details on how to contact me. .SH " Setting The baudrate Option" Slirp's "baudrate" option has caused some confusion. This section will explain exactly what it's for and how to use it. .PP When sending data over the modem to your PC, Slirp needs to know how much data it can send over without "saturating" the link. If Slirp was to send as much data as it could, the Operating System would buffer a LOT of it - 20k is not uncommon. This could severely "lag" any telnet connections if you happen to be FTP-ing a file at the same time. This is because when you type a character, you will not see that character on the screen until the the other end sends you the "echo", so if there is 20k worth of data buffered you will need to wait until 20k of data is received before you see that character on your screen. .PP To counter this, Slirp uses the "baudrate" option to limit the amount of data it sends over the link to prevent the Operating System from buffering too much of it. So if you give Slirp a "baudrate" of 14400, Slirp will send data at a rate of 14400 Baud modem (with no compression). .PP In general, the baud rate at which the connection was made should be the "baudrate" you give to Slirp. So, for example, if you connected at 14400 Baud, you should give Slirp the option "baudrate 14400". However, since most modems today do compression (v.42bis), it is very difficult for Slirp know how much data to send to keep the link "full", yet prevent too much buffering by the Operating system. .PP Therefore you should choose a "baudrate" appropriate to your needs: if you use telnet a lot while downloading compressed files, you should set your "baudrate" to the same as the CONNECT speed of your modem. Downloading compressed files should not suffer, and telnet sessions will be far more responsive. However, sending text over the modem will not be as fast, because your modem will compress the data and send it faster than Slirp expects. Giving a "baudrate" the same as the CONNECT speed will effectively turn off modem compression. .PP If you do not use telnet very much, you should set your "baudrate" to the maximum theoretical speed your modem can do. For example, if you connect at 14400 and use v.42bis compression, which can compress up to 4x, you should set your "baudrate" to 14400*4 = 57600. This will ensure any compressible data will get compressed, and a maximum throughput will be attained, at the expense of telnet sessions which will be almost unusable if you happen to be downloading files at the same time. .PP Note however that you can change the "baudrate" setting at any time. Simply telnet to 10.0.2.0 and enter "baudrate XXX" and Slirp will change the rate at which data is sent. This can be useful for example if you're downloading a lot of compressed files, but in the middle of the download you want to read mail. Simply change the "baudrate" to the CONNECT speed, and when you're finished, change it back to the maximum theoretical speed. .PP Also, keep in mind that the "baudrate" is also used for other calculations. For example, if there are many connections, Slirp will try to be fair and send one packet per connection in a round-robin fashion. This makes all connections "smooth" instead of sending a bunch of packets for one connection, then a bunch of packets for another connection, etc. But if the "baudrate" is too high, the is exactly what will happen. Packet priority selection also uses the "baudrate"; I.e., if there are packets queued ready for sending from both an FTP connection and a telnet connection, the telnet packets will be sent first. But again, this will only work if the "baudrate" reflects the amount of data Slirp can send, and generally won't work if you set it to the maximum theoretical connection speed. .PP So here are my tips: .RS 2 .IP * 2 If you download a lot of compressed files and occasionally use telnet, or other "interactive" programs, set your "baudrate" to your CONNECT speed (because already compressed files won't compress any more with the modem compression, so you're unlikely to get faster download's as a result of modem compression); .IP * 2 If you mainly use telnet, or other "interactive" programs, and you occasionally download some compressed files, set your "baudrate" to the maximum theoretical speed (because telnet sessions are usually text, which compresses very well, hence screen updates will be faster. Only when downloading compressed files will you experience severe lag); .IP * 2 If you mainly browse the Web (E.g., using Netscape, etc.), then you should set your "baudrate" to the theoretical maximum speed (because there's lots of text in Web documents which is very compressible, and there's no telnet sessions so lag will not be a problem); .RE .PP I personally have by baudrate set at 14400, the speed at which my modem connects, even though the modems do v.42bis compression. Compressed file downloads are just as fast, and telnet sessions during FTP downloads are surprisingly responsive. Try it yourself, there's a world of difference. .SH "PROBLEMS, QUESTIONS, AND ANSWERS" .SH " Which programs do not work over Slirp?" Any programs that bind()'s a port, then tell the other end of the connection where they should connect() to this bound port. .PP For example, when you "get" a file during an FTP session, the FTP client bind()'s a socket, has a look at which port the socket is bound to, then tells the FTP server the address and port of this socket (with the PORT command). The FTP server then connect()'s to this address/socket pair. .PP Now, since your machine isn't really on the Internet, this connect() request will not arrive to your host, so it will not work. .PP Slirp emulates this by bind()ing it's own port on the server that *is* on the Internet, and tells the FTP server about *that* address/socket pair. When the server connect()'s to it, Slirp will then connect back to your machine. .PP At present, the following programs are emulated: .DS rlogin ftp ksh irc (for /dcc) RealAudio talk/ytalk/ntalk CUSeeMe .DE .SH " Troubleshooting" .IP Symptom: The connection will "freeze". E.g., while downloading a picture on WWW it will stop halfway and no connections will continue. .IP Diagnosis: You probably don't have an 8bit clean link. .IP Cure: You should try and find out from your sysadmin which characters need to be "escaped", then tell Slirp about them using the "asyncmap" and "escape" commands. Note that you need to use PPP for this to work. (One way to test for 8bit cleanliness is to download a BINARY file with Z-Modem. If the file doesn't make it, you have a "dirty" link). .IP One thing you might try is run Slirp as: .DS slirp "asyncmap ffffffff" "escape ff" .DE (quotes included!) This will tell Slirp to escape the most common "nasty characters. .IP Symptom: You can connect to hosts using numerical addresses (of the form aa.bb.cc.dd) but you cannot connect to hosts when you use their hostname (E.g.: ftp.cdrom.com). It usually times out with a DNS error. .IP Diagnosis: You probably did not set your DNS address properly. .IP Cure: Try setting your DNS address to 10.0.2.3. This should work for most situations. If that fails, go to your shell prompt and type "nslookup". This should print the address and hostname of your DNS server. Use the numerical IP address as your DNS. Do NOT use the hostname. .IP If you still can't find your DNS address, ask your sysadmin for it. .SH " Answers to Frequently Asked Questions (FAQs)" .IP Q1. Can I use Slirp through Telnet or Rlogin? .IP A1. Yes, usually. But this is highly dependent on your situation. .IP The reason Slirp usually doesn't work through telnet is because of the ^] character is interpreted by the telnet client, and 0xff interpreted by the server. While you can tell Slirp to escape these characters while using PPP, it may not be possible to get your local PPP software to escape characters greater than ASCII 31. Rlogin also interprets the ~ character, which may interfere with PPP (especially considering ~ is ASCII 0x7e which is used by PPP as the "end of packet" character"). .IP If your PPP software is unable to escape these characters, or you're using (C)SLIP (which must have an 8bit clean link), your best bet is to try and make the link 8bit clean. For example, on some systems you can give telnet the -8 flag to make the link 8bit, and -E to stop it from interpreting the ^] character. Similarly for rlogin; -8 to make the link 8bit, -E to stop rlogin from interpreting the ~ character. You should look at the telnet and rlogin manual pages ("man telnet" and "man rlogin" respectively) to see if your telnet/rlogin has similar options. .IP Another possible solution is to use Slirp's ability to work over multiple hosts. See the slirp.doc documentation for more details. .IP Q2. How do I run an X program on another host and have it display on my PC? .IP A2. Use the "redir X" command in ~/.slirprc. This will redirect a port for use with X programs. .IP On startup, Slirp should print something like: .DS X Redir: In sh/bash/zsh/etc. type: DISPLAY=IP.ADDRESS:X.Y; export DISPLAY X Redir: In csh/tcsh/etc. type: setenv DISPLAY IP.ADDRESS:X.Y .DE Now, when you telnet to the host you wish to run the X programs from, you should do as Slirp suggest above; type either of the two commands, depending on which shell you are using. You could also run the X program as "xprog -display IP.ADDRESS:X.Y" as printed above. .IP If you missed what Slirp displayed on startup, you can telnet to 10.0.2.0 and give Slirp the command "show X", and the above will be printed. .IP Note that you also have to make sure your X server will accept the connection. See the man page for xhost and Xsecurity. Be careful with issuing commands like "xhost +", this will allow anyone to connect to your X server and do basically anything they want. .IP Q3. When I run "talk" or "wintalk", etc. I am able to send requests to other people but they cannot send requests to me. Why? .IP A3. You won't be able to receive talk requests, period. This is because Slirp never see's the incoming talk request; it is sent directly over the modem, most likely corrupting any incoming packet with it (which will have to be retransmitted). Slirp turns off your messages so the person who tries to talk to you should receive a "User is refusing messages" error. .IP Q4. I can't telnet to 10.0.2.0, the Slirp control address. What's wrong? .IP A4. See the answer to this question in slirp.doc and recompile slirp. .IP Q5. I'm having a few problems with Slirp and want to try and find the problem myself. Does Slirp have any debugging facilities? .IP A5. Yes. See slirp.doc for compile-time debug options. .IP Q6. My ISP logs me out if I idle too long. How can I get Slirp to prevent this? .IP A6. First of all, the idle-logout mechanism is used for a reason: to prevent people from hogging a modem which is not in use. So if you're idle, logout and give others chance to logon. .IP Having said that, you can make Slirp use TCP keep-alive timers to regularly probe each TCP connection. To activate this, add: .DS keepalive .DE to your ~/.slirprc file. This will make Slirp probe each TCP connection every minute or so. You can change this interval by giving keepalive the number of seconds: .DS keepalive SECONDS .DE Note that no probes will be sent if there are no TCP connections. So you need at least one active TCP connection for this to work. .SH "GETTING HELP" There are several sources of help. First, read the previous sections "Troubleshooting" and "Answers to Frequently Asked Questions (FAQs)". .PP If that fails, try the Slirp Home Page at: .DS http://blitzen.canberra.edu.au/slirp .DE There are lots of neat links there to other pages which have specific configuration information. .PP There is also a Newsgroup dedicated to SLIP-emulators called alt.dcom.slip-emulators. You will find lots of discussion about Slirp and other "SLIP-emulators". The FAQ (Frequently Asked Questions) for alt.dcom.slip-emulators is included in the "docs" directory, I would suggest reading this as well. .PP If all else fails, send me e-mail to danjo@blitzen.canberra.edu.au with the following information: .RS 2 .IP * 2 Output of the command "uname -a" on the remote system; .IP * 2 Operating System name and version you run on your PC; .IP * 2 Version of Slirp you are using (IMPORTANT!!!); .IP * 2 If you managed to get Slirp running, run Slirp as "slirp -S" then try whatever failed. When you exit Slirp, you should have a file called "slirp_stats". Send me this file; and .IP * 2 Anything else you consider relevant. .RE .PP *PLEASE* include all the above information. If you do not, I may simply press "d". I can't guarantee a response, but I will try my best. .SH THANKS A big "THANK YOU!" goes to the following people for their help in creating Slirp. .PP Juha Pirkola, Gregory M. Christy, The Regents of the University of California, Carnegie Mellon University, The Australian National University, and RSA Data Security, Inc. whose source code is used throughout Slirp. Slirp would not be without them. .PP Thanks to all the contributors who helped with bugs, suggestions, code, etc. Read the file ChangeLog to see exactly who helped with what. .PP A special thanks goes to Chris Metcalf and Juha Pirkola for their contributions (see ChangeLog). They put in extra effort and Slirp wouldn't be the same without their help. Thanks guys! .PP Thanks to all the people who sent very kind and encouraging e-mail, it's sincerely appreciated. .PP Thanks to all the admins and Head Honcho's at UCNet, the University of Canberra Computer Club ("blitzen") who gave me some real-estate on their machine (blitzen.canberra.edu.au) to work with (thanks to Tony Delroy for giving me the account originally). Hey! Why don't you check out their home page at http://blitzen.canberra.edu.au/? .PP Thanks to Brazil for coffee (and Sepultura! :) .PP Thanks to the laws of physics, the building blocks of the universe. .SH COPYRIGHT Slirp was written by Danny Gasparovski. .PP Copyright (c) 1995 Danny Gasparovski. All Rights Reserved. .PP Slirp is free software; "free" as in you don't have to pay for it, and you are free to do whatever you want with it. I do not accept any donations, monetary or otherwise, for Slirp. Instead, I would ask you to pass this potential donation to your favorite charity. In fact, I encourage *everyone* who finds Slirp useful to make a small donation to their favorite charity (for example, GreenPeace). This is not a requirement, but a suggestion from someone who highly values the service they provide. .PP Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: .IP 1. 3 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. .IP 2. 3 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. .IP 3. 3 All advertising materials mentioning features or use of this software must display the following acknowledgment: This product includes software developed by Danny Gasparovski. .PP THIS SOFTWARE IS PROVIDED ``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 DANNY GASPAROVSKI 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. .PP This basically means you can do anything you want with the software, except 1) call it your own, and 2) claim warranty on it. There is no warranty for this software. None. Nada. If you lose a million dollars while using Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. .PP If these conditions cannot be met due to legal restrictions (E.g. where it is against the law to give out Software without warranty), you must cease using the software and delete all copies you have. .PP Slirp uses code that is copyrighted by the following people/organizations: .PP .DS Juha Pirkola. Gregory M. Christy. The Regents of the University of California. Carnegie Mellon University. The Australian National University. RSA Data Security, Inc. .DE Please read the top of each source file for the details on the various copyrights. .SH AUTHOR Slirp was written by Danny Gasparovski. .PP Manpage by George Ferguson, ferguson@cs.rochester.edu, based on Slirp 1.0b documentation. slirp-1.0.17/src/slirp_debug0000644000175000017500000001122210117211532015005 0ustar roverroverSlirp 1.0.16 - Debugging Started. Debugging Started level -1. tty_attach... unit = 0 device = 0 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 if_input... ttyp = a0508d0 read 1 bytes, fd=0 IN: 0 30 ppp_input... ttyp = a0508d0 if_bptr = 22e330 if_n = 1 m_get... m = a051ae0 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 if_input... ttyp = a0508d0 read 1 bytes, fd=0 IN: 0 30 ppp_input... ttyp = a0508d0 if_bptr = 22e330 if_n = 1 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 if_input... ttyp = a0508d0 read 1 bytes, fd=0 IN: 0 30 ppp_input... ttyp = a0508d0 if_bptr = 22e330 if_n = 1 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 if_input... ttyp = a0508d0 read 1 bytes, fd=0 IN: 0 30 ppp_input... ttyp = a0508d0 if_bptr = 22e330 if_n = 1 timeout.tv_usec = 4294967295 hunting ttyp=a0508d0 if_input... ttyp = a0508d0 read 1 bytes, fd=0 IN: 0 30 slirp_exit... exit_status = 0 IP stats: 0 total packets received (0 were unaligned) 0 with incorrect vers timeout.tv_usec = 4294967295 timeout.tv_usec = 4294967295 slirp_exit... exit_status = 15 IP stats: 0 total packets received (0 were unaligned) 0 with incorrect version 0 with bad header checksum 0 with length too short (len < sizeof(iphdr)) 0 with length too small (len < ip->len) 0 with bad header length 0 with bad packet length 0 fragments received 0 fragments dropped 0 fragments timed out 0 packets reassembled ok 0 outgoing packets fragmented 0 total outgoing fragments 0 with bad protocol field 0 total packets delivered TCP stats: 0 packets sent 0 data packets (0 bytes) 0 data packets retransmitted (0 bytes) 0 ack-only packets (0 delayed) 0 URG only packets 0 window probe packets 0 window update packets 0 control (SYN/FIN/RST) packets 0 times tcp_output did nothing 0 packets received 0 acks (for 0 bytes) 0 duplicate acks 0 acks for unsent data 0 packets received in sequence (0 bytes) 0 completely duplicate packets (0 bytes) 0 packets with some duplicate data (0 bytes duped) 0 out-of-order packets (0 bytes) 0 packets of data after window (0 bytes) 0 window probes 0 window update packets 0 packets received after close 0 discarded for bad checksums 0 discarded for bad header offset fields 0 connection requests 0 connection accepts 0 connections established (including accepts) 0 connections closed (including 0 drop) 0 embryonic connections dropped 0 segments we tried to get rtt (0 succeeded) 0 retransmit timeouts 0 connections dropped by rxmt timeout 0 persist timeouts 0 keepalive timeouts 0 keepalive probes sent 0 connections dropped by keepalive 0 correct ACK header predictions 0 correct data packet header predictions 0 TCP cache misses UDP stats: 0 datagrams received 0 with packets shorter than header 0 with bad checksums 0 with data length larger than packet 0 UDP socket cache misses 0 datagrams sent ICMP stats: 0 ICMP packets received 0 were too short 0 with bad checksums 0 with type not supported 0 with bad type feilds 0 ICMP packets sent in reply Mbuf stats: 1 mbufs allocated (1 max) 1 mbufs on free list 0 mbufs on used list 0 mbufs queued as packets Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ VJ compression stats: 0 outbound packets (0 compressed) 0 searches for connection stats (0 misses) 0 inbound uncompressed packets 0 inbound compressed packets 0 inbound unknown type packets 0 inbound packets tossed due to error compressed) 0 searches for connection stats (0 misses) 0 inbound uncompressed packets 0 inbound compressed packets 0 inbound unknown type packets 0 inbound packets tossed due to error tty_detached... ttyp = a0508d0 exiting = 1 m_free... m = a051ae0 slirp-1.0.17/src/slirp_stats0000644000175000017500000000731410117012061015060 0ustar roverroverSlirp 1.0.16 - Debugging Started. Debugging Started level 15. IP stats: 0 total packets received (0 were unaligned) 0 with incorrect version 0 with bad header checksum 0 with length too short (len < sizeof(iphdr)) 0 with length too small (len < ip->len) 0 with bad header length 0 with bad packet length 0 fragments received 0 fragments dropped 0 fragments timed out 0 packets reassembled ok 0 outgoing packets fragmented 0 total outgoing fragments 0 with bad protocol field 0 total packets delivered TCP stats: 0 packets sent 0 data packets (0 bytes) 0 data packets retransmitted (0 bytes) 0 ack-only packets (0 delayed) 0 URG only packets 0 window probe packets 0 window update packets 0 control (SYN/FIN/RST) packets 0 times tcp_output did nothing 0 packets received 0 acks (for 0 bytes) 0 duplicate acks 0 acks for unsent data 0 packets received in sequence (0 bytes) 0 completely duplicate packets (0 bytes) 0 packets with some duplicate data (0 bytes duped) 0 out-of-order packets (0 bytes) 0 packets of data after window (0 bytes) 0 window probes 0 window update packets 0 packets received after close 0 discarded for bad checksums 0 discarded for bad header offset fields 0 connection requests 0 connection accepts 0 connections established (including accepts) 0 connections closed (including 0 drop) 0 embryonic connections dropped 0 segments we tried to get rtt (0 succeeded) 0 retransmit timeouts 0 connections dropped by rxmt timeout 0 persist timeouts 0 keepalive timeouts 0 keepalive probes sent 0 connections dropped by keepalive 0 correct ACK header predictions 0 correct data packet header predictions 0 TCP cache misses UDP stats: 0 datagrams received 0 with packets shorter than header 0 with bad checksums 0 with data length larger than packet 0 UDP socket cache misses 0 datagrams sent ICMP stats: 0 ICMP packets received 0 were too short 0 with bad checksums 0 with type not supported 0 with bad type feilds 0 ICMP packets sent in reply Mbuf stats: 1 mbufs allocated (1 max) 0 mbufs on free list 1 mbufs on used list 0 mbufs queued as packets Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ Unit 0: using PPP encapsulation (VJ compression is off (for now)) 115200 baudrate interface is down using fd 6, guardian pid is 1504 towrite is 512 bytes 5 zeros have been typed Interface stats: 0 output packets sent (0 bytes) 0 output packets dropped (0 bytes) 0 input packets received (0 bytes) 0 input packets dropped (0 bytes) 0 bad input packets VJ compression stats: 0 outbound packets (0 compressed) 0 searches for connection stats (0 misses) 0 inbound uncompressed packets 0 inbound compressed packets 0 inbound unknown type packets 0 inbound packets tossed due to error tty_detached... ttyp = a050260 exiting = 1 m_free... m = a051698 slirp-1.0.17/src/slirptrace.sh0000755000175000017500000000025710117177450015312 0ustar roverrover#!/bin/bash #Cygwin #Stack trace of a slirp stack dump file. #Thanks google, people on internet. awk '/^[0-9]/{print $2}' slirp.exe.stackdump | addr2line -f -e slirp.exe slirp-1.0.17/src/socket.c0000644000175000017500000004015510115276014014232 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include #include "ip_icmp.h" #include "main.h" void so_init() { /* Nothing yet */ } struct socket * solookup(head, laddr, lport, faddr, fport) struct socket *head; struct in_addr laddr; u_int lport; struct in_addr faddr; u_int fport; { struct socket *so; for (so = head->so_next; so != head; so = so->so_next) { if (so->so_lport == lport && so->so_laddr.s_addr == laddr.s_addr && so->so_faddr.s_addr == faddr.s_addr && so->so_fport == fport) break; } if (so == head) return (struct socket *)NULL; return so; } /* * Create a new socket, initialise the fields * It is the responsibility of the caller to * insque() it into the correct linked-list */ struct socket * socreate() { struct socket *so; so = (struct socket *)malloc(sizeof(struct socket)); if(so) { memset(so, 0, sizeof(struct socket)); so->so_state = SS_NOFDREF; so->s = -1; } return(so); } /* * remque and free a socket, clobber cache */ void sofree(so) struct socket *so; { if (so->so_emu==EMU_RSH && so->extra) { sofree(so->extra); so->extra=NULL; } if (so == tcp_last_so) tcp_last_so = &tcb; else if (so == udp_last_so) udp_last_so = &udb; m_free(so->so_m); if(so->so_next && so->so_prev) remque(so); /* crashes if so is not in a queue */ free(so); } /* * Read from so's socket into sb_snd, updating all relevant sbuf fields * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ int soread(so) struct socket *so; { int n, nn, lss, total; struct sbuf *sb = &so->so_snd; int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; DEBUG_CALL("soread"); DEBUG_ARG("so = %lx", (long )so); /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_rptr - sb->sb_data; if(iov[1].iov_len > len) iov[1].iov_len = len; total = iov[0].iov_len + iov[1].iov_len; if (total > mss) { lss = total%mss; if (iov[1].iov_len > lss) { iov[1].iov_len -= lss; n = 2; } else { lss -= iov[1].iov_len; iov[0].iov_len -= lss; n = 1; } } else n = 2; } else { if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } } #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else nn = read(so->s, iov[0].iov_base, iov[0].iov_len); #endif if (nn <= 0) { if (nn < 0 && (errno == EINTR || errno == EAGAIN)) return 0; else { DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); sofcantrcvmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } } #ifndef HAVE_READV /* * If there was no error, try and read the second time round * We read again if n = 2 (ie, there's another part of the buffer) * and we read as much as we could in the first read * We don't test for <= 0 this time, because there legitimately * might not be any more data (since the socket is non-blocking), * a close will be detected on next iteration. * A return of -1 wont (shouldn't) happen, since it didn't happen above */ if (n == 2 && nn == iov[0].iov_len) nn += read(so->s, iov[1].iov_base, iov[1].iov_len); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif /* Update fields */ sb->sb_cc += nn; sb->sb_wptr += nn; if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_wptr -= sb->sb_datalen; return nn; } /* * Get urgent data * * When the socket is created, we set it SO_OOBINLINE, * so when OOB data arrives, we soread() it and everything * in the send buffer is sent as urgent data */ void sorecvoob(so) struct socket *so; { struct tcpcb *tp = sototcpcb(so); DEBUG_CALL("sorecvoob"); DEBUG_ARG("so = %lx", (long)so); /* * We take a guess at how much urgent data has arrived. * In most situations, when urgent data arrives, the next * read() should get all the urgent data. This guess will * be wrong however if more data arrives just after the * urgent data, or the read() doesn't return all the * urgent data. */ soread(so); tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_force = 1; tcp_output(tp); tp->t_force = 0; } /* * Send urgent data * There's a lot duplicated code here, but... */ int sosendoob(so) struct socket *so; { struct sbuf *sb = &so->so_rcv; char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ int n, len; DEBUG_CALL("sosendoob"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); if (so->so_urgc > 2048) so->so_urgc = 2048; /* XXXX */ if (sb->sb_rptr < sb->sb_wptr) { /* We can send it directly */ n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } else { /* * Since there's no sendv or sendtov like writev, * we must copy all data to a linear buffer then * send it all */ len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; if (len > so->so_urgc) len = so->so_urgc; memcpy(buff, sb->sb_rptr, len); so->so_urgc -= len; if (so->so_urgc) { n = sb->sb_wptr - sb->sb_data; if (n > so->so_urgc) n = so->so_urgc; memcpy((buff + len), sb->sb_data, n); so->so_urgc -= n; len += n; } n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); #endif DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } sb->sb_cc -= n; sb->sb_rptr += n; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; return n; } /* * Write data from so_rcv to so's socket, * updating all sbuf field as necessary */ int sowrite(so) struct socket *so; { int n,nn; struct sbuf *sb = &so->so_rcv; int len = sb->sb_cc; struct iovec iov[2]; DEBUG_CALL("sowrite"); DEBUG_ARG("so = %lx", (long)so); if (so->so_urgc) { sosendoob(so); if (sb->sb_cc == 0) return 0; } /* * No need to check if there's something to write, * sowrite wouldn't have been called otherwise */ len = sb->sb_cc; iov[0].iov_base = sb->sb_rptr; if (sb->sb_rptr < sb->sb_wptr) { iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_wptr - sb->sb_data; if (iov[1].iov_len > len) iov[1].iov_len = len; n = 2; } else n = 1; } /* Check if there's urgent data to send, and if so, send it */ #ifdef HAVE_READV nn = writev(so->s, (const struct iovec *)iov, n); DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else nn = write(so->s, iov[0].iov_base, iov[0].iov_len); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) return 0; if (nn <= 0) { DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", so->so_state, errno)); sofcantsendmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) nn += write(so->s, iov[1].iov_base, iov[1].iov_len); DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif /* Update sbuf */ sb->sb_cc -= nn; sb->sb_rptr += nn; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; /* * If in DRAIN mode, and there's no more data, set * it CANTSENDMORE */ if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) sofcantsendmore(so); return nn; } /* * recvfrom() a UDP socket */ void sorecvfrom(so) struct socket *so; { struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); DEBUG_CALL("sorecvfrom"); DEBUG_ARG("so = %lx", (long)so); if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ char buff[256]; int len; len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen); /* XXX Check if reply is "correct"? */ if(len == -1 || len == 0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", errno,strerror(errno))); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); } else { icmp_reflect(so->so_m); so->so_m = 0; /* Don't m_free() it again! */ } /* No need for this socket anymore, udp_detach it */ udp_detach(so); } else { /* A "normal" UDP packet */ struct mbuf *m; int len, n; if (!(m = m_get())) return; m->m_data += if_maxlinkhdr; /* * XXX Shouldn't FIONREAD packets destined for port 53, * but I don't know the max packet size for DNS lookups */ len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ ioctl(so->s, FIONREAD, &n); if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; m_inc(m, n); len = M_FREEROOM(m); } /* } */ m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr, &addrlen); DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", m->m_len, errno,strerror(errno))); if(m->m_len<0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); m_free(m); } else { /* * Hack: domain name lookup will be used the most for UDP, * and since they'll only be used once there's no need * for the 4 minute (or whatever) timeout... So we time them * out much quicker (10 seconds for now...) */ if (so->so_expire) { if (so->so_fport == htons(53)) so->so_expire = curtime + SO_EXPIREFAST; else so->so_expire = curtime + SO_EXPIRE; } /* if (m->m_len == len) { * m_inc(m, MINCSIZE); * m->m_len = 0; * } */ /* * If this packet was destined for CTL_ADDR, * make it look like that's where it came from, done by udp_output */ udp_output(so, m, &addr); } /* rx error */ } /* if ping packet */ } /* * sendto() a socket */ int sosendto(so, m) struct socket *so; struct mbuf *m; { int ret; struct sockaddr_in addr; DEBUG_CALL("sosendto"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, sizeof (struct sockaddr)); if (ret < 0) return -1; /* * Kill the socket if there's no reply in 4 minutes, * but only if it's an expirable socket */ if (so->so_expire) so->so_expire = curtime + SO_EXPIRE; so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ return 0; } /* * XXX This should really be tcp_listen */ struct socket * solisten(port, laddr, lport, flags) u_int port; u_int32_t laddr; u_int lport; int flags; { struct sockaddr_in addr; struct socket *so; int s, addrlen = sizeof(addr), opt = 1; DEBUG_CALL("solisten"); DEBUG_ARG("port = %d", port); DEBUG_ARG("laddr = %x", laddr); DEBUG_ARG("lport = %d", lport); DEBUG_ARG("flags = %x", flags); if ((so = socreate()) == NULL) { /* free(so); Not sofree() ??? free(NULL) == NOP */ return NULL; } /* Don't tcp_attach... we don't need so_snd nor so_rcv */ if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { free(so); return NULL; } insque(so,&tcb); /* * SS_FACCEPTONCE sockets must time out. */ if (flags & SS_FACCEPTONCE) so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; so->so_state = (SS_FACCEPTCONN|flags); so->so_lport = lport; /* Kept in network format */ so->so_laddr.s_addr = laddr; /* Ditto */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = port; if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ close(s); sofree(so); /* Restore the real errno */ errno = tmperrno; return NULL; } setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = our_addr; else so->so_faddr = addr.sin_addr; so->s = s; return so; } /* * Data is available in so_rcv * Just write() the data to the socket * XXX not yet... */ void sorwakeup(so) struct socket *so; { /* sowrite(so); */ /* FD_CLR(so->s,&writefds); */ } /* * Data has been freed in so_snd * We have room for a read() if we want to * For now, don't read, it'll be done in the main loop */ void sowwakeup(so) struct socket *so; { /* Nothing, yet */ } /* * Various session state calls * XXX Should be #define's * The socket state stuff needs work, these often get call 2 or 3 * times each when only 1 was needed */ void soisfconnecting(so) register struct socket *so; { so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| SS_FCANTSENDMORE|SS_FWDRAIN); so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ } void soisfconnected(so) register struct socket *so; { so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ } void sofcantrcvmore(so) struct socket *so; { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,0); FD_CLR(so->s,&writefds); } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTSENDMORE) so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ else so->so_state |= SS_FCANTRCVMORE; } void sofcantsendmore(so) struct socket *so; { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,1); /* send FIN to fhost */ FD_CLR(so->s,&readfds); FD_CLR(so->s,&xfds); } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTRCVMORE) so->so_state = SS_NOFDREF; /* as above */ else so->so_state |= SS_FCANTSENDMORE; } void soisfdisconnected(so) struct socket *so; { /* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ /* close(so->s); */ /* so->so_state = SS_ISFDISCONNECTED; */ /* * XXX Do nothing ... ? */ } /* * Set write drain mode * Set CANTSENDMORE once all data has been write()n */ void sofwdrain(so) struct socket *so; { if (so->so_rcv.sb_cc) so->so_state |= SS_FWDRAIN; else sofcantsendmore(so); } slirp-1.0.17/src/socket.h0000644000175000017500000000524410115276015014240 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ /* MINE */ #ifndef _SLIRP_SOCKET_H_ #define _SLIRP_SOCKET_H_ #define SO_EXPIRE 240000 #define SO_EXPIREFAST 10000 /* * Our socket structure */ struct socket { struct socket *so_next,*so_prev; /* For a linked list of sockets */ int s; /* The actual socket */ /* XXX union these with not-yet-used sbuf params */ struct mbuf *so_m; /* Pointer to the original SYN packet, * for non-blocking connect()'s, and * PING reply's */ struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ int so_urgc; struct in_addr so_faddr; /* foreign host table entry */ struct in_addr so_laddr; /* local host table entry */ u_int16_t so_fport; /* foreign port */ u_int16_t so_lport; /* local port */ u_int8_t so_iptos; /* Type of service */ u_int8_t so_emu; /* Is the socket emulated? */ u_char so_type; /* Type of socket, UDP or TCP */ int so_state; /* internal state flags SS_*, below */ struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ u_int so_expire; /* When the socket will expire */ int so_queued; /* Number of packets queued from this socket */ int so_nqueued; /* Number of packets queued in a row * Used to determine when to "downgrade" a session * from fastq to batchq */ struct sbuf so_rcv; /* Receive buffer */ struct sbuf so_snd; /* Send buffer */ void * extra; /* Extra pointer */ }; /* * Socket state bits. (peer means the host on the Internet, * local host means the host on the other end of the modem) */ #define SS_NOFDREF 0x001 /* No fd reference */ #define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ #define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ #define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ #define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ /* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ #define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ #define SS_CTL 0x080 #define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ #define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ extern struct socket tcb; #if defined(DECLARE_IOVEC) && !defined(HAVE_READV) struct iovec { char *iov_base; size_t iov_len; }; #endif #endif /* _SOCKET_H_ */ slirp-1.0.17/src/socket.p0000644000175000017500000000150610115325665014253 0ustar roverrovervoid so_init _P((void)); struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int)); struct socket * socreate _P((void)); void sofree _P((struct socket *)); int soread _P((struct socket *)); void sorecvoob _P((struct socket *)); int sosendoob _P((struct socket *)); int sowrite _P((struct socket *)); void sorecvfrom _P((struct socket *)); int sosendto _P((struct socket *, struct mbuf *)); struct socket * solisten _P((u_int, u_int32_t, u_int, int)); void sorwakeup _P((struct socket *)); void sowwakeup _P((struct socket *)); void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); void sofcantrcvmore _P((struct socket *)); void sofcantsendmore _P((struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); slirp-1.0.17/src/stacktrace.sh0000755000175000017500000000024310117177471015264 0ustar roverrover#!/bin/bash #Cygwin #Stack trace of a stack dump file. #Thanks google, people on internet. awk '/^[0-9]/{print $2}' $1.exe.stackdump | addr2line -f -e $1.exe slirp-1.0.17/src/strtoul.c0000644000175000017500000000671710115276014014464 0ustar roverrover/* * Copyright (c) 1990 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. */ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)strtoul.c 5.3 (Berkeley) 2/23/91";*/ static char *rcsid = "$Id: strtoul.c,v 1.4 1993/08/26 00:48:14 jtc Exp $"; #endif /* LIBC_SCCS and not lint */ #include "slirp.h" unsigned long strtoul _P((const char *, char **, int)); #undef _P /* used by */ #include #include /* * Convert a string to an unsigned long integer. * * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. */ unsigned long strtoul(nptr, endptr, base) const char *nptr; char **endptr; register int base; { register const char *s = nptr; register unsigned long acc; register int c; register unsigned long cutoff; register int neg = 0, any, cutlim; /* * See strtol for comments as to the logic used. */ do { c = *s++; } while (isspace(c)); if (c == '-') { neg = 1; c = *s++; } else if (c == '+') c = *s++; if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; base = 16; } if (base == 0) base = c == '0' ? 8 : 10; cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; for (acc = 0, any = 0;; c = *s++) { if (isdigit(c)) c -= '0'; else if (isalpha(c)) c -= isupper(c) ? 'A' - 10 : 'a' - 10; else break; if (c >= base) break; if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) any = -1; else { any = 1; acc *= base; acc += c; } } if (any < 0) { acc = ULONG_MAX; errno = ERANGE; } else if (neg) acc = -acc; if (endptr != 0) *endptr = (char *) (any ? s - 1 : nptr); return (acc); } slirp-1.0.17/src/talkd.h0000644000175000017500000001261010115276015014042 0ustar roverrover/* * Copyright (c) 1983, 1993 * 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. * * @(#)talkd.h 8.1 (Berkeley) 6/2/93 */ #ifndef _PROTOCOLS_TALKD_H_ #define _PROTOCOLS_TALKD_H_ /* Phil LoCascio's patch for SGI Irix 6.5 -kp 5-29-2000 */ #ifdef SGI_OLD_SA #define sa_family sa_family_old #define sa_data sa_data_old #endif struct old_sockaddr { u_short sa_family; /* address family */ char sa_data[14]; /* up to 14 bytes of direct address */ }; /* * This describes the protocol used by the talk server and clients. * * The talk server acts a repository of invitations, responding to * requests by clients wishing to rendezvous for the purpose of * holding a conversation. In normal operation, a client, the caller, * initiates a rendezvous by sending a CTL_MSG to the server of * type LOOK_UP. This causes the server to search its invitation * tables to check if an invitation currently exists for the caller * (to speak to the callee specified in the message). If the lookup * fails, the caller then sends an ANNOUNCE message causing the server * to broadcast an announcement on the callee's login ports requesting * contact. When the callee responds, the local server uses the * recorded invitation to respond with the appropriate rendezvous * address and the caller and callee client programs establish a * stream connection through which the conversation takes place. */ /* * Client->server request message format. */ typedef struct { u_char vers; /* protocol version */ u_char type; /* request type, see below */ u_char answer; /* not used */ u_char pad; u_int32_t id_num; /* message id */ struct old_sockaddr addr; /* old (4.3) style */ struct old_sockaddr ctl_addr; /* old (4.3) style */ long pid; /* caller's process id */ #define NAME_SIZE 12 char l_name[NAME_SIZE];/* caller's name */ char r_name[NAME_SIZE];/* callee's name */ #define TTY_SIZE 16 char r_tty[TTY_SIZE];/* callee's tty name */ } CTL_MSG; /* * Server->client response message format. */ typedef struct { u_char vers; /* protocol version */ u_char type; /* type of request message, see below */ u_char answer; /* response to request message, see below */ u_char pad; u_int32_t id_num; /* message id */ struct old_sockaddr addr; /* address for establishing conversation */ } CTL_RESPONSE; #define TALK_VERSION 1 /* protocol version */ /* message type values */ #define LEAVE_INVITE 0 /* leave invitation with server */ #define LOOK_UP 1 /* check for invitation by callee */ #define DELETE 2 /* delete invitation by caller */ #define ANNOUNCE 3 /* announce invitation by caller */ /* answer values */ #define SUCCESS 0 /* operation completed properly */ #define NOT_HERE 1 /* callee not logged in */ #define FAILED 2 /* operation failed for unexplained reason */ #define MACHINE_UNKNOWN 3 /* caller's machine name unknown */ #define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */ #define UNKNOWN_REQUEST 5 /* request has invalid type value */ #define BADVERSION 6 /* request has invalid protocol version */ #define BADADDR 7 /* request has invalid addr value */ #define BADCTLADDR 8 /* request has invalid ctl_addr value */ /* * Operational parameters. */ #define MAX_LIFE 60 /* max time daemon saves invitations */ /* RING_WAIT should be 10's of seconds less than MAX_LIFE */ #define RING_WAIT 30 /* time to wait before resending invitation */ #define NAME_SIZE_OLD 9 typedef struct { u_char type; char l_name[NAME_SIZE_OLD]; char r_name[NAME_SIZE_OLD]; u_char filler; u_int32_t id_num; long pid; char r_tty[TTY_SIZE]; struct old_sockaddr addr; struct old_sockaddr ctl_addr; } CTL_MSG_OLD; #endif /* !_TALKD_H_ */ slirp-1.0.17/src/tcp.h0000644000175000017500000001375610115276015013545 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)tcp.h 8.1 (Berkeley) 6/10/93 * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp */ #ifndef _TCP_H_ #define _TCP_H_ typedef u_int32_t tcp_seq; #define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ #define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ extern int tcp_rcvspace; extern int tcp_sndspace; extern struct socket *tcp_last_so; #define TCP_SNDSPACE 8192 #define TCP_RCVSPACE 8192 /* * TCP header. * Per RFC 793, September, 1981. */ struct tcphdr { u_int16_t th_sport; /* source port */ u_int16_t th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ #ifdef WORDS_BIGENDIAN u_int th_off:4, /* data offset */ th_x2:4; /* (unused) */ #else u_int th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif u_int8_t th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 u_int16_t th_win; /* window */ u_int16_t th_sum; /* checksum */ u_int16_t th_urp; /* urgent pointer */ }; #include "tcp_var.h" #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 #define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 #define TCPOLEN_WINDOW 3 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */ #define TCPOLEN_SACK_PERMITTED 2 #define TCPOPT_SACK 5 /* Experimental */ #define TCPOPT_TIMESTAMP 8 #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) /* * Default maximum segment size for TCP. * With an IP MSS of 576, this is 536, * but 512 is probably more convenient. * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). */ #define TCP_MSS 512 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ #define TCP_MAX_WINSHIFT 14 /* maximum window shift */ /* * User-settable options (used with setsockopt). */ /* #define TCP_NODELAY 0x01 */ /* don't delay send to coalesce packets */ /* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ /* * TCP FSM state definitions. * Per RFC793, September, 1981. */ #define TCP_NSTATES 11 #define TCPS_CLOSED 0 /* closed */ #define TCPS_LISTEN 1 /* listening for connection */ #define TCPS_SYN_SENT 2 /* active, have sent syn */ #define TCPS_SYN_RECEIVED 3 /* have send and received syn */ /* states < TCPS_ESTABLISHED are those where connections not established */ #define TCPS_ESTABLISHED 4 /* established */ #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ /* states > TCPS_CLOSE_WAIT are those where user has closed */ #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ #define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ #define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ #define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) /* * TCP sequence numbers are 32 bit integers operated * on with modular arithmetic. These macros can be * used to compare such integers. */ #define SEQ_LT(a,b) ((int)((a)-(b)) < 0) #define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define SEQ_GT(a,b) ((int)((a)-(b)) > 0) #define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) /* * Macros to initialize tcp sequence numbers for * send and receive from initial send and receive * sequence numbers. */ #define tcp_rcvseqinit(tp) \ (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 #define tcp_sendseqinit(tp) \ (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss #define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ extern tcp_seq tcp_iss; /* tcp initial send seq # */ extern char *tcpstates[]; #endif slirp-1.0.17/src/tcp_input.c0000644000175000017500000014102310115276014014743 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 * 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. * * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include "ip_icmp.h" struct socket tcb; #define min(x,y) ((x) < (y) ? (x) : (y)) #define max(x,y) ((x) > (y) ? (x) : (y)) int tcprexmtthresh = 3; struct socket *tcp_last_so = &tcb; tcp_seq tcp_iss; /* tcp initial send seq # */ #define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) /* for modulo comparisons of timestamps */ #define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) #define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) /* * Insert segment ti into reassembly queue of tcp with * control block tp. Return TH_FIN if reassembly now includes * a segment with FIN. The macro form does the common case inline * (segment is the next to be received on an established connection, * and the queue is empty), avoiding linkage into and removal * from the queue and repetition of various conversions. * Set DELACK for segments received in order, but ack immediately * when segments are out of order (so fast retransmit can work). */ #ifdef TCP_ACK_HACK #define TCP_REASS(tp, ti, m, so, flags) {\ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (tcpiphdrp_32)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) {\ if (ti->ti_flags & TH_PUSH) \ tp->t_flags |= TF_ACKNOW; \ else \ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ tcpstat.tcps_rcvpack++;\ tcpstat.tcps_rcvbyte += (ti)->ti_len;\ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend((so), (m)); \ } else \ sbappend((so), (m)); \ /* sorwakeup(so); */ \ } else {\ (flags) = tcp_reass((tp), (ti), (m)); \ tp->t_flags |= TF_ACKNOW; \ } \ } #else #define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (tcpiphdrp_32)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ tcpstat.tcps_rcvpack++;\ tcpstat.tcps_rcvbyte += (ti)->ti_len;\ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend(so, (m)); \ } else \ sbappend((so), (m)); \ /* sorwakeup(so); */ \ } else { \ (flags) = tcp_reass((tp), (ti), (m)); \ tp->t_flags |= TF_ACKNOW; \ } \ } #endif int tcp_reass(tp, ti, m) register struct tcpcb *tp; register struct tcpiphdr *ti; struct mbuf *m; { register struct tcpiphdr *q; struct socket *so = tp->t_socket; int flags; /* * Call with ti==0 after become established to * force pre-ESTABLISHED data up to user socket. */ if (ti == 0) goto present; /* * Find a segment which begins after this one does. */ for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; q = (struct tcpiphdr *)q->ti_next) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { register int i; q = (struct tcpiphdr *)q->ti_prev; /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { if (i >= ti->ti_len) { tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += ti->ti_len; m_freem(m); /* * Try to present any queued data * at the left window edge to the user. * This is needed after the 3-WHS * completes. */ goto present; /* ??? */ } m_adj(m, i); ti->ti_len -= i; ti->ti_seq += i; } q = (struct tcpiphdr *)(q->ti_next); } tcpstat.tcps_rcvoopack++; tcpstat.tcps_rcvoobyte += ti->ti_len; REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct tcpiphdr *)tp) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; m_adj((struct mbuf *) REASS_MBUF(q), i); break; } q = (struct tcpiphdr *)q->ti_next; m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); remque_32((void *)(q->ti_prev)); m_freem(m); } /* * Stick new segment in its place. */ insque_32(ti, (void *)(q->ti_prev)); present: /* * Present data to user, advancing rcv_nxt through * completed sequence space. */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); ti = (struct tcpiphdr *) tp->seg_next; if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; remque_32(ti); m = (struct mbuf *) REASS_MBUF(ti); /* XXX */ ti = (struct tcpiphdr *)ti->ti_next; /* if (so->so_state & SS_FCANTRCVMORE) */ if (so->so_state & SS_FCANTSENDMORE) m_freem(m); else { if (so->so_emu) { if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); } } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); /* sorwakeup(so); */ return (flags); } /* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. */ void tcp_input(m, iphlen, inso) register struct mbuf *m; int iphlen; struct socket *inso; { struct ip save_ip, *ip; register struct tcpiphdr *ti; caddr_t optp = NULL; int optlen = 0; int len, tlen, off; register struct tcpcb *tp = 0; register int tiflags; struct socket *so = 0; int todrop, acked, ourfinisacked, needoutput = 0; /* int dropsocket = 0; */ int iss = 0; u_long tiwin; int ret; /* int ts_present = 0; */ DEBUG_CALL("tcp_input"); DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", (long )m, iphlen, (long )inso )); /* * If called with m == 0, then we're continuing the connect */ if (m == NULL) { so = inso; /* Re-set a few variables */ tp = sototcpcb(so); m = so->so_m; so->so_m = 0; ti = so->so_ti; tiwin = ti->ti_win; tiflags = ti->ti_flags; goto cont_conn; } tcpstat.tcps_rcvtotal++; /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. */ ti = mtod(m, struct tcpiphdr *); if (iphlen > sizeof(struct ip )) { ip_stripoptions(m, (struct mbuf *)0); iphlen=sizeof(struct ip ); } /* XXX Check if too short */ /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ ip=mtod(m, struct ip *); save_ip = *ip; save_ip.ip_len+= iphlen; /* * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = htons((u_int16_t)tlen); len = sizeof(struct ip ) + tlen; /* keep checksum for ICMP reply * ti->ti_sum = cksum(m, len); * if (ti->ti_sum) { */ if(cksum(m, len)) { tcpstat.tcps_rcvbadsum++; goto drop; } /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { tcpstat.tcps_rcvbadoff++; goto drop; } tlen -= off; ti->ti_len = tlen; if (off > sizeof (struct tcphdr)) { optlen = off - sizeof (struct tcphdr); optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr); /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's * formatted as recommended in RFC 1323 appendix A, we * quickly get the values now and not bother calling * tcp_dooptions(), etc. */ /* if ((optlen == TCPOLEN_TSTAMP_APPA || * (optlen > TCPOLEN_TSTAMP_APPA && * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && * (ti->ti_flags & TH_SYN) == 0) { * ts_present = 1; * ts_val = ntohl(*(u_int32_t *)(optp + 4)); * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); * optp = NULL; / * we've parsed the options * / * } */ } tiflags = ti->ti_flags; /* * Convert TCP protocol specific fields to host format. */ NTOHL(ti->ti_seq); NTOHL(ti->ti_ack); NTOHS(ti->ti_win); NTOHS(ti->ti_urp); /* * Drop TCP, IP headers and TCP options. */ m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); /* * Locate pcb for segment. */ findso: so = tcp_last_so; if (so->so_fport != ti->ti_dport || so->so_lport != ti->ti_sport || so->so_laddr.s_addr != ti->ti_src.s_addr || so->so_faddr.s_addr != ti->ti_dst.s_addr) { so = solookup(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); if (so) tcp_last_so = so; ++tcpstat.tcps_socachemiss; } /* * If the state is CLOSED (i.e., TCB does not exist) then * all data in the incoming segment is discarded. * If the TCB exists but is in CLOSED state, it is embryonic, * but should either do a listen or a connect soon. * * state == CLOSED means we've done socreate() but haven't * attached it to a protocol yet... * * XXX If a TCB does not exist, and the TH_SYN flag is * the only flag set, then create a session, mark it * as if it was LISTENING, and continue... */ if (so == 0) { if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) goto dropwithreset; if ((so = socreate()) == NULL) goto dropwithreset; if (tcp_attach(so) < 0) { free(so); /* Not sofree (if it failed, it's not insqued) */ goto dropwithreset; } sbreserve(&so->so_snd, tcp_sndspace); sbreserve(&so->so_rcv, tcp_rcvspace); /* tcp_last_so = so; */ /* XXX ? */ /* tp = sototcpcb(so); */ so->so_laddr = ti->ti_src; so->so_lport = ti->ti_sport; so->so_faddr = ti->ti_dst; so->so_fport = ti->ti_dport; if ((so->so_iptos = tcp_tos(so)) == 0) so->so_iptos = ((struct ip *)ti)->ip_tos; tp = sototcpcb(so); tp->t_state = TCPS_LISTEN; } /* * If this is a still-connecting socket, this probably * a retransmit of the SYN. Whether it's a retransmit SYN * or something else, we nuke it. */ if (so->so_state & SS_ISFCONNECTING) goto drop; tp = sototcpcb(so); /* XXX Should never fail */ if (tp == 0) goto dropwithreset; if (tp->t_state == TCPS_CLOSED) goto drop; /* Unscale the window into a 32-bit value. */ /* if ((tiflags & TH_SYN) == 0) * tiwin = ti->ti_win << tp->snd_scale; * else */ tiwin = ti->ti_win; /* * Segment received on connection. * Reset idle time and keep-alive timer. */ tp->t_idle = 0; if (so_options) tp->t_timer[TCPT_KEEP] = tcp_keepintvl; else tp->t_timer[TCPT_KEEP] = tcp_keepidle; /* * Process options if not in LISTEN state, * else do it below (after getting remote address). */ if (optp && tp->t_state != TCPS_LISTEN) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ /* * Header prediction: check for the two common cases * of a uni-directional data xfer. If the packet has * no control flags, is in-sequence, the window didn't * change and we're not retransmitting, it's a * candidate. If the length is zero and the ack moved * forward, we're the sender side of the xfer. Just * free the data acked & wake any higher level process * that was blocked waiting for space. If the length * is non-zero and the ack didn't move, we're the * receiver side. If we're getting packets in-order * (the reassembly queue is empty), add the data to * the socket buffer and note that we need a delayed ack. * * XXX Some of these tests are not needed * eg: the tiwin == tp->snd_wnd prevents many more * predictions.. with no *real* advantage.. */ if (tp->t_state == TCPS_ESTABLISHED && (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && /* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { /* * If last ACK falls within this segment's sequence numbers, * record the timestamp. */ /* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { * tp->ts_recent_age = tcp_now; * tp->ts_recent = ts_val; * } */ if (ti->ti_len == 0) { if (SEQ_GT(ti->ti_ack, tp->snd_una) && SEQ_LEQ(ti->ti_ack, tp->snd_max) && tp->snd_cwnd >= tp->snd_wnd) { /* * this is a pure ack for outstanding data. */ ++tcpstat.tcps_predack; /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; sbdrop(&so->so_snd, acked); tp->snd_una = ti->ti_ack; m_freem(m); /* * If all outstanding data are acked, stop * retransmit timer, otherwise restart timer * using current (possibly backed-off) value. * If process is waiting for space, * wakeup/selwakeup/signal. If data * are ready to send, let tcp_output * decide between more output or persist. */ if (tp->snd_una == tp->snd_max) tp->t_timer[TCPT_REXMT] = 0; else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * There's room in so_snd, sowwakup will read() * from the socket if we can */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); */ /* * This is called because sowwakeup might have * put data into so_snd. Since we don't so sowwakeup, * we don't need this.. XXX??? */ if (so->so_snd.sb_cc) (void) tcp_output(tp); return; } } else if (ti->ti_ack == tp->snd_una && tp->seg_next == (tcpiphdrp_32)tp && ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet * with nothing on the reassembly queue and * we have enough buffer space to take it. */ ++tcpstat.tcps_preddat; tp->rcv_nxt += ti->ti_len; tcpstat.tcps_rcvpack++; tcpstat.tcps_rcvbyte += ti->ti_len; /* * Add data to socket buffer. */ if (so->so_emu) { if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); /* * XXX This is called when data arrives. Later, check * if we can actually write() to the socket * XXX Need to check? It's be NON_BLOCKING */ /* sorwakeup(so); */ /* * If this is a short packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. * * Here are 3 interpretations of what should happen. * The best (for me) is to delay-ack everything except * if it's a one-byte packet containing an ESC * (this means it's an arrow key (or similar) sent using * Nagel, hence there will be no echo) * The first of these is the original, the second is the * middle ground between the other 2 */ /* if (((unsigned)ti->ti_len < tp->t_maxseg)) { */ /* if (((unsigned)ti->ti_len < tp->t_maxseg && * (so->so_iptos & IPTOS_LOWDELAY) == 0) || * ((so->so_iptos & IPTOS_LOWDELAY) && * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { */ if ((unsigned)ti->ti_len == 1 && ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { tp->t_flags |= TF_ACKNOW; tcp_output(tp); } else { tp->t_flags |= TF_DELACK; } return; } } /* header prediction */ /* * Calculate amount of space in receive window, * and then do TCP input processing. * Receive window is amount of space in rcv queue, * but not less than advertised window. */ { int win; win = sbspace(&so->so_rcv); if (win < 0) win = 0; tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); } switch (tp->t_state) { /* * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. * If it does not contain a SYN then it is not interesting; drop it. * Don't bother responding if the destination was a broadcast. * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial * tp->iss, and send a segment: * * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. * Fill in remote peer address fields if not previously specified. * Enter SYN_RECEIVED state, and process any other fields of this * segment in this state. */ case TCPS_LISTEN: { if (tiflags & TH_RST) goto drop; if (tiflags & TH_ACK) goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; /* * This has way too many gotos... * But a bit of spaghetti code never hurt anybody :) */ /* * If this is destined for the control address, then flag to * tcp_ctl once connected, otherwise connect */ if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { /* Command or exec adress */ so->so_state |= SS_CTL; } else { /* May be an add exec */ struct ex_list *ex_ptr; for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if(ex_ptr->ex_fport == so->so_fport && lastbyte == ex_ptr->ex_addr) { so->so_state |= SS_CTL; break; } } } if(so->so_state & SS_CTL) goto cont_input; } /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ } if (so->so_emu & EMU_NOCONNECT) { so->so_emu &= ~EMU_NOCONNECT; goto cont_input; } if(tcp_fconnect(so) == -1 && errno != EINPROGRESS) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", errno,strerror(errno))); if(errno == ECONNREFUSED) { /* ACK the SYN, send RST to refuse the connection */ tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, TH_RST|TH_ACK); } else { if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; HTONL(ti->ti_seq); /* restore tcp header */ HTONL(ti->ti_ack); HTONS(ti->ti_win); HTONS(ti->ti_urp); m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); *ip=save_ip; icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); } tp = tcp_close(tp); m_free(m); } else { /* * Haven't connected yet, save the current mbuf * and ti, and return * XXX Some OS's don't tell us whether the connect() * succeeded or not. So we must time it out. */ so->so_m = m; so->so_ti = ti; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->t_state = TCPS_SYN_RECEIVED; } return; cont_conn: /* m==NULL * Check if the connect succeeded */ if (so->so_state & SS_NOFDREF) { tp = tcp_close(tp); goto dropwithreset; } cont_input: tcp_template(tp); if (optp) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ if (iss) tp->iss = iss; else tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tp->irs = ti->ti_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; tp->t_state = TCPS_SYN_RECEIVED; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tcpstat.tcps_accepts++; goto trimthenstep6; } /* case TCPS_LISTEN */ /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. * if seg contains a RST, then drop the connection. * if seg does not contain SYN, then drop it. * Otherwise this is an acceptable SYN segment * initialize tp->rcv_nxt and tp->irs * if seg contains ack then advance tp->snd_una * if SYN has been acked change to ESTABLISHED else SYN_RCVD state * arrange for segment to be acked (eventually) * continue processing rest of data/controls, beginning with URG */ case TCPS_SYN_SENT: if ((tiflags & TH_ACK) && (SEQ_LEQ(ti->ti_ack, tp->iss) || SEQ_GT(ti->ti_ack, tp->snd_max))) goto dropwithreset; if (tiflags & TH_RST) { if (tiflags & TH_ACK) tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ goto drop; } if ((tiflags & TH_SYN) == 0) goto drop; if (tiflags & TH_ACK) { tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; } tp->t_timer[TCPT_REXMT] = 0; tp->irs = ti->ti_seq; tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { tcpstat.tcps_connects++; soisfconnected(so); tp->t_state = TCPS_ESTABLISHED; /* Do window scaling on this connection? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { * tp->snd_scale = tp->requested_s_scale; * tp->rcv_scale = tp->request_r_scale; * } */ (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); /* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. */ if (tp->t_rtt) tcp_xmit_timer(tp, tp->t_rtt); } else tp->t_state = TCPS_SYN_RECEIVED; trimthenstep6: /* * Advance ti->ti_seq to correspond to first data byte. * If data, trim to stay within window, * dropping FIN if necessary. */ ti->ti_seq++; if (ti->ti_len > tp->rcv_wnd) { todrop = ti->ti_len - tp->rcv_wnd; m_adj(m, -todrop); ti->ti_len = tp->rcv_wnd; tiflags &= ~TH_FIN; tcpstat.tcps_rcvpackafterwin++; tcpstat.tcps_rcvbyteafterwin += todrop; } tp->snd_wl1 = ti->ti_seq - 1; tp->rcv_up = ti->ti_seq; goto step6; } /* switch tp->t_state */ /* * States other than LISTEN or SYN_SENT. * First check timestamp, if present. * Then check that at least some bytes of segment are within * receive window. If segment begins before rcv_nxt, * drop leading data (and SYN); if nothing left, just ack. * * RFC 1323 PAWS: If we have a timestamp reply on this segment * and it's less than ts_recent, drop it. */ /* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && * TSTMP_LT(ts_val, tp->ts_recent)) { * */ /* Check to see if ts_recent is over 24 days old. */ /* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { */ /* * * Invalidate ts_recent. If this segment updates * * ts_recent, the age will be reset later and ts_recent * * will get a valid value. If it does not, setting * * ts_recent to zero will at least satisfy the * * requirement that zero be placed in the timestamp * * echo reply when ts_recent isn't valid. The * * age isn't reset until we get a valid ts_recent * * because we don't want out-of-order segments to be * * dropped when ts_recent is old. * */ /* tp->ts_recent = 0; * } else { * tcpstat.tcps_rcvduppack++; * tcpstat.tcps_rcvdupbyte += ti->ti_len; * tcpstat.tcps_pawsdrop++; * goto dropafterack; * } * } */ todrop = tp->rcv_nxt - ti->ti_seq; if (todrop > 0) { if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; ti->ti_seq++; if (ti->ti_urp > 1) ti->ti_urp--; else tiflags &= ~TH_URG; todrop--; } /* * Following if statement from Stevens, vol. 2, p. 960. */ if (todrop > ti->ti_len || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { /* * Any valid FIN must be to the left of the window. * At this point the FIN must be a duplicate or out * of sequence; drop it. */ tiflags &= ~TH_FIN; /* * Send an ACK to resynchronize and drop any data. * But keep on processing for RST or ACK. */ tp->t_flags |= TF_ACKNOW; todrop = ti->ti_len; tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += todrop; } else { tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; } m_adj(m, todrop); ti->ti_seq += todrop; ti->ti_len -= todrop; if (ti->ti_urp > todrop) ti->ti_urp -= todrop; else { tiflags &= ~TH_URG; ti->ti_urp = 0; } } /* * If new data are received on a connection after the * user processes are gone, then RST the other end. */ if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; goto dropwithreset; } /* * If segment ends after window, drop trailing data * (and PUSH and FIN); if nothing left, just ACK. */ todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); if (todrop > 0) { tcpstat.tcps_rcvpackafterwin++; if (todrop >= ti->ti_len) { tcpstat.tcps_rcvbyteafterwin += ti->ti_len; /* * If a new connection request is received * while in TIME_WAIT, drop the old connection * and start over if the sequence numbers * are above the previous ones. */ if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { iss = tp->rcv_nxt + TCP_ISSINCR; tp = tcp_close(tp); goto findso; } /* * If window is closed can only take segments at * window edge, and have to drop data and PUSH from * incoming segments. Continue processing, but * remember to ack. Otherwise, drop segment * and ack. */ if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { tp->t_flags |= TF_ACKNOW; tcpstat.tcps_rcvwinprobe++; } else goto dropafterack; } else tcpstat.tcps_rcvbyteafterwin += todrop; m_adj(m, -todrop); ti->ti_len -= todrop; tiflags &= ~(TH_PUSH|TH_FIN); } /* * If last ACK falls within this segment's sequence numbers, * record its timestamp. */ /* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { * tp->ts_recent_age = tcp_now; * tp->ts_recent = ts_val; * } */ /* * If the RST bit is set examine the state: * SYN_RECEIVED STATE: * If passive open, return to LISTEN state. * If active open, inform user that connection was refused. * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: * Inform user that connection was reset, and close tcb. * CLOSING, LAST_ACK, TIME_WAIT STATES * Close the tcb. */ if (tiflags&TH_RST) switch (tp->t_state) { case TCPS_SYN_RECEIVED: /* so->so_error = ECONNREFUSED; */ goto close; case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: /* so->so_error = ECONNRESET; */ close: tp->t_state = TCPS_CLOSED; tcpstat.tcps_drops++; tp = tcp_close(tp); goto drop; case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: tp = tcp_close(tp); goto drop; } /* * If a SYN is in the window, then this is an * error and we send an RST and drop the connection. */ if (tiflags & TH_SYN) { tp = tcp_drop(tp,0); goto dropwithreset; } /* * If the ACK bit is off we drop the segment and return. */ if ((tiflags & TH_ACK) == 0) goto drop; /* * Ack processing. */ switch (tp->t_state) { /* * In SYN_RECEIVED state if the ack ACKs our SYN then enter * ESTABLISHED state and continue processing, otherwise * send an RST. una<=ack<=max */ case TCPS_SYN_RECEIVED: if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max)) goto dropwithreset; tcpstat.tcps_connects++; tp->t_state = TCPS_ESTABLISHED; /* * The sent SYN is ack'ed with our sequence number +1 * The first data byte already in the buffer will get * lost if no correction is made. This is only needed for * SS_CTL since the buffer is empty otherwise. * tp->snd_una++; or: */ tp->snd_una=ti->ti_ack; if (so->so_state & SS_CTL) { /* So tcp_ctl reports the right state */ ret = tcp_ctl(so); if (ret == 1) { soisfconnected(so); so->so_state &= ~SS_CTL; /* success XXX */ } else if (ret == 2) { so->so_state = SS_NOFDREF; /* CTL_CMD */ } else { needoutput = 1; tp->t_state = TCPS_FIN_WAIT_1; } } else { soisfconnected(so); } /* Do window scaling? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { * tp->snd_scale = tp->requested_s_scale; * tp->rcv_scale = tp->request_r_scale; * } */ (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); tp->snd_wl1 = ti->ti_seq - 1; /* Avoid ack processing; snd_una==ti_ack => dup ack */ goto synrx_to_est; /* fall into ... */ /* * In ESTABLISHED state: drop duplicate ACKs; ACK out of range * ACKs. If the ack is in the range * tp->snd_una < ti->ti_ack <= tp->snd_max * then advance tp->snd_una to ti->ti_ack and drop * data from the retransmission queue. If this ACK reflects * more up to date window information we update our window information. */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { tcpstat.tcps_rcvdupack++; DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", (long )m, (long )so)); /* * If we have outstanding data (other than * a window probe), this is a completely * duplicate ack (ie, window info didn't * change), the ack is the biggest we've * seen and we've seen exactly our rexmt * threshold of them, assume a packet * has been dropped and retransmit it. * Kludge snd_nxt & the congestion * window so we send only this one * packet. * * We know we're losing at the current * window size so do congestion avoidance * (set ssthresh to half the current window * and pull our congestion window back to * the new ssthresh). * * Dup acks mean that packets have left the * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. */ if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) tp->t_dupacks = 0; else if (++tp->t_dupacks == tcprexmtthresh) { tcp_seq onxt = tp->snd_nxt; u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_timer[TCPT_REXMT] = 0; tp->t_rtt = 0; tp->snd_nxt = ti->ti_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } else if (tp->t_dupacks > tcprexmtthresh) { tp->snd_cwnd += tp->t_maxseg; (void) tcp_output(tp); goto drop; } } else tp->t_dupacks = 0; break; } synrx_to_est: /* * If the congestion window was inflated to account * for the other side's cached packets, retract it. */ if (tp->t_dupacks > tcprexmtthresh && tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_dupacks = 0; if (SEQ_GT(ti->ti_ack, tp->snd_max)) { tcpstat.tcps_rcvacktoomuch++; goto dropafterack; } acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; /* * If we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but * transmit timer is running and timed sequence * number was acked, update smoothed round trip time. * Since we now have an rtt measurement, cancel the * timer backoff (cf., Phil Karn's retransmit alg.). * Recompute the initial retransmit timer. */ /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp,tp->t_rtt); /* * If all outstanding data is acked, stop retransmit * timer and remember to restart (more output or persist). * If there is more data to be acked, restart retransmit * timer, using current (possibly backed-off) value. */ if (ti->ti_ack == tp->snd_max) { tp->t_timer[TCPT_REXMT] = 0; needoutput = 1; } else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * When new data is acked, open the congestion window. * If the window gives us less than ssthresh packets * in flight, open exponentially (maxseg per packet). * Otherwise open linearly: maxseg per window * (maxseg^2 / cwnd per packet). */ { register u_int cw = tp->snd_cwnd; register u_int incr = tp->t_maxseg; if (cw > tp->snd_ssthresh) incr = incr * incr / cw; tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); ourfinisacked = 1; } else { sbdrop(&so->so_snd, acked); tp->snd_wnd -= acked; ourfinisacked = 0; } /* * XXX sowwakup is called when data is acked and there's room for * for more data... it should read() the socket */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); */ tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; switch (tp->t_state) { /* * In FIN_WAIT_1 STATE in addition to the processing * for the ESTABLISHED state if our FIN is now acknowledged * then enter FIN_WAIT_2. */ case TCPS_FIN_WAIT_1: if (ourfinisacked) { /* * If we can't receive any more * data, then closing user can proceed. * Starting the timer is contrary to the * specification, but if we don't get a FIN * we'll hang forever. */ if (so->so_state & SS_FCANTRCVMORE) { soisfdisconnected(so); tp->t_timer[TCPT_2MSL] = tcp_maxidle; } tp->t_state = TCPS_FIN_WAIT_2; } break; /* * In CLOSING STATE in addition to the processing for * the ESTABLISHED state if the ACK acknowledges our FIN * then enter the TIME-WAIT state, otherwise ignore * the segment. */ case TCPS_CLOSING: if (ourfinisacked) { tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisfdisconnected(so); } break; /* * In LAST_ACK, we may still be waiting for data to drain * and/or to be acked, as well as for the ack of our FIN. * If our FIN is now acknowledged, delete the TCB, * enter the closed state and return. */ case TCPS_LAST_ACK: if (ourfinisacked) { tp = tcp_close(tp); goto drop; } break; /* * In TIME_WAIT state the only thing that should arrive * is a retransmission of the remote FIN. Acknowledge * it and restart the finack timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; goto dropafterack; } } /* switch(tp->t_state) */ step6: /* * Update window information. * Don't look at window if no ACK: TAC's send garbage on first SYN. */ if ((tiflags & TH_ACK) && (SEQ_LT(tp->snd_wl1, ti->ti_seq) || (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) tcpstat.tcps_rcvwinupd++; tp->snd_wnd = tiwin; tp->snd_wl1 = ti->ti_seq; tp->snd_wl2 = ti->ti_ack; if (tp->snd_wnd > tp->max_sndwnd) tp->max_sndwnd = tp->snd_wnd; needoutput = 1; } /* * Process segments with URG. */ if ((tiflags & TH_URG) && ti->ti_urp && TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * This is a kludge, but if we receive and accept * random urgent pointers, we'll crash in * soreceive. It's hard to imagine someone * actually wanting to send this much urgent data. */ if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { ti->ti_urp = 0; tiflags &= ~TH_URG; goto dodata; } /* * If this segment advances the known urgent pointer, * then mark the data stream. This should not happen * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since * a FIN has been received from the remote side. * In these states we ignore the URG. * * According to RFC961 (Assigned Protocols), * the urgent pointer points to the last octet * of urgent data. We continue, however, * to consider it to indicate the first octet * of data past the urgent section as the original * spec states (in one of two places). */ if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_urgc = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */ tp->rcv_up = ti->ti_seq + ti->ti_urp; } } else /* * If no out of band data is expected, * pull receive urgent pointer along * with the receive window. */ if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) tp->rcv_up = tp->rcv_nxt; dodata: /* * Process the segment text, merging it into the TCP sequencing queue, * and arranging for acknowledgment of receipt if necessary. * This process logically involves adjusting tp->rcv_wnd as data * is presented to the user (this happens in tcp_usrreq.c, * case PRU_RCVD). If a FIN has already been received on this * connection then we just ignore the text. */ if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { TCP_REASS(tp, ti, m, so, tiflags); /* * Note the amount of data that peer has sent into * our window, in order to estimate the sender's * buffer size. */ len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); } else { m_free(m); tiflags &= ~TH_FIN; } /* * If FIN is received ACK the FIN and let the user know * that the connection is closing. */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * If we receive a FIN we can't send more data, * set it SS_FDRAIN * Shutdown the socket if there is no rx data in the * buffer. * soread() is called on completion of shutdown() and * will got to TCPS_LAST_ACK, and use tcp_output() * to send the FIN. */ /* sofcantrcvmore(so); */ sofwdrain(so); tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch (tp->t_state) { /* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: if(so->so_emu == EMU_CTL) /* no shutdown on socket */ tp->t_state = TCPS_LAST_ACK; else tp->t_state = TCPS_CLOSE_WAIT; break; /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. */ case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; break; /* * In FIN_WAIT_2 state enter the TIME_WAIT state, * starting the time-wait timer, turning off the other * standard timers. */ case TCPS_FIN_WAIT_2: tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisfdisconnected(so); break; /* * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; } } /* * If this is a small packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. * * See above. */ /* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { */ /* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && * (so->so_iptos & IPTOS_LOWDELAY) == 0) || * ((so->so_iptos & IPTOS_LOWDELAY) && * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { */ if (ti->ti_len && (unsigned)ti->ti_len <= 5 && ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { tp->t_flags |= TF_ACKNOW; } /* * Return any desired output. */ if (needoutput || (tp->t_flags & TF_ACKNOW)) { (void) tcp_output(tp); } return; dropafterack: /* * Generate an ACK dropping incoming segment if it occupies * sequence space, where the ACK reflects our state. */ if (tiflags & TH_RST) goto drop; m_freem(m); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); return; dropwithreset: /* reuses m if m!=NULL, m_free() unnecessary */ if (tiflags & TH_ACK) tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); else { if (tiflags & TH_SYN) ti->ti_len++; tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); } return; drop: /* * Drop space held by incoming segment and return. */ m_free(m); return; } /* , ts_present, ts_val, ts_ecr) */ /* int *ts_present; * u_int32_t *ts_val, *ts_ecr; */ void tcp_dooptions(tp, cp, cnt, ti) struct tcpcb *tp; u_char *cp; int cnt; struct tcpiphdr *ti; { u_int16_t mss; int opt, optlen; DEBUG_CALL("tcp_dooptions"); DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == TCPOPT_EOL) break; if (opt == TCPOPT_NOP) optlen = 1; else { optlen = cp[1]; if (optlen <= 0) break; } switch (opt) { default: continue; case TCPOPT_MAXSEG: if (optlen != TCPOLEN_MAXSEG) continue; if (!(ti->ti_flags & TH_SYN)) continue; memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); NTOHS(mss); (void) tcp_mss(tp, mss); /* sets t_maxseg */ break; /* case TCPOPT_WINDOW: * if (optlen != TCPOLEN_WINDOW) * continue; * if (!(ti->ti_flags & TH_SYN)) * continue; * tp->t_flags |= TF_RCVD_SCALE; * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); * break; */ /* case TCPOPT_TIMESTAMP: * if (optlen != TCPOLEN_TIMESTAMP) * continue; * *ts_present = 1; * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); * NTOHL(*ts_val); * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); * NTOHL(*ts_ecr); * */ /* * * A timestamp received in a SYN makes * * it ok to send timestamp requests and replies. * */ /* if (ti->ti_flags & TH_SYN) { * tp->t_flags |= TF_RCVD_TSTMP; * tp->ts_recent = *ts_val; * tp->ts_recent_age = tcp_now; * } */ break; } } } /* * Pull out of band byte out of a segment so * it doesn't appear in the user's data queue. * It is still reflected in the segment length for * sequencing purposes. */ #ifdef notdef void tcp_pulloutofband(so, ti, m) struct socket *so; struct tcpiphdr *ti; register struct mbuf *m; { int cnt = ti->ti_urp - 1; while (cnt >= 0) { if (m->m_len > cnt) { char *cp = mtod(m, caddr_t) + cnt; struct tcpcb *tp = sototcpcb(so); tp->t_iobc = *cp; tp->t_oobflags |= TCPOOB_HAVEDATA; memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); m->m_len--; return; } cnt -= m->m_len; m = m->m_next; /* XXX WRONG! Fix it! */ if (m == 0) break; } panic("tcp_pulloutofband"); } #endif /* notdef */ /* * Collect new round-trip time estimate * and update averages and current timeout. */ void tcp_xmit_timer(tp, rtt) register struct tcpcb *tp; int rtt; { register short delta; DEBUG_CALL("tcp_xmit_timer"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("rtt = %d", rtt); tcpstat.tcps_rttupdated++; if (tp->t_srtt != 0) { /* * srtt is stored as fixed point with 3 bits after the * binary point (i.e., scaled by 8). The following magic * is equivalent to the smoothing algorithm in rfc793 with * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed * point). Adjust rtt to origin 0. */ delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); if ((tp->t_srtt += delta) <= 0) tp->t_srtt = 1; /* * We accumulate a smoothed rtt variance (actually, a * smoothed mean difference), then set the retransmit * timer to smoothed rtt + 4 times the smoothed variance. * rttvar is stored as fixed point with 2 bits after the * binary point (scaled by 4). The following is * equivalent to rfc793 smoothing with an alpha of .75 * (rttvar = rttvar*3/4 + |delta| / 4). This replaces * rfc793's wired-in beta. */ if (delta < 0) delta = -delta; delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); if ((tp->t_rttvar += delta) <= 0) tp->t_rttvar = 1; } else { /* * No rtt measurement yet - use the unsmoothed rtt. * Set the variance to half the rtt (so our first * retransmit happens at 3*rtt). */ tp->t_srtt = rtt << TCP_RTT_SHIFT; tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); } tp->t_rtt = 0; tp->t_rxtshift = 0; /* * the retransmit should happen at rtt + 4 * rttvar. * Because of the way we do the smoothing, srtt and rttvar * will each average +1/2 tick of bias. When we compute * the retransmit timer, we want 1/2 tick of rounding and * 1 extra tick because of +-1/2 tick uncertainty in the * firing of the timer. The bias will give us exactly the * 1.5 tick we need. But, because the bias is * statistical, we have to test that we don't drop below * the minimum feasible timer (which is 2 ticks). */ TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ /* * We received an ack for a packet that wasn't retransmitted; * it is probably safe to discard any error indications we've * received recently. This isn't quite right, but close enough * for now (a route might have failed after we sent a segment, * and the return path might not be symmetrical). */ tp->t_softerror = 0; } /* * Determine a reasonable value for maxseg size. * If the route is known, check route for mtu. * If none, use an mss that can be handled on the outgoing * interface without forcing IP to fragment; if bigger than * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES * to utilize large mbufs. If no route is found, route has no mtu, * or the destination isn't local, use a default, hopefully conservative * size (usually 512 or the default IP max size, but no more than the mtu * of the interface), as we can't discover anything about intervening * gateways or networks. We also initialize the congestion/slow start * window to be a single segment if the destination isn't local. * While looking at the routing entry, we also initialize other path-dependent * parameters from pre-set or cached values in the routing entry. */ int tcp_mss(tp, offer) register struct tcpcb *tp; u_int offer; { struct socket *so = tp->t_socket; int mss; DEBUG_CALL("tcp_mss"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("offer = %d", offer); mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); if (offer) mss = min(mss, offer); mss = max(mss, 32); if (mss < tp->t_maxseg || offer != 0) tp->t_maxseg = mss; tp->snd_cwnd = mss; sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); DEBUG_MISC((dfd, " returning mss = %d\n", mss)); return mss; } slirp-1.0.17/src/tcp_input.p0000644000175000017500000000052010115325666014764 0ustar roverroverint tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct mbuf *)); void tcp_input _P((register struct mbuf *, int, struct socket *)); void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); void tcp_xmit_timer _P((register struct tcpcb *, int)); int tcp_mss _P((register struct tcpcb *, u_int)); slirp-1.0.17/src/tcp_output.c0000644000175000017500000004250010115276014015144 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * 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. * * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #define max(x,y) ((x) > (y) ? (x) : (y)) #define min(x,y) ((x) < (y) ? (x) : (y)) /* * Since this is only used in "stats socket", we give meaning * names instead of the REAL names */ char *tcpstates[] = { /* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", }; u_char tcp_outflags[TCP_NSTATES] = { TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, }; #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ /* * Tcp output routine: figure out what should be sent and send it. */ int tcp_output(tp) register struct tcpcb *tp; { register struct socket *so = tp->t_socket; register long len, win; int off, flags, error; register struct mbuf *m; register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; int idle, sendalot; DEBUG_CALL("tcp_output"); DEBUG_ARG("tp = %lx", (long )tp); /* * Determine length of data that should be transmitted, * and flags that will be used. * If there is some data or critical controls (SYN, RST) * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); if (idle && tp->t_idle >= tp->t_rxtcur) /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tp->snd_cwnd = tp->t_maxseg; again: sendalot = 0; off = tp->snd_nxt - tp->snd_una; win = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero * and timer expired, we will send what we can * and go to transmit state. */ if (tp->t_force) { if (win == 0) { /* * If we still have some data to send, then * clear the FIN bit. Usually this would * happen below when it realizes that we * aren't sending all the data. However, * if we have exactly 1 byte of unset data, * then it won't clear the FIN bit below, * and if we are in persist state, we wind * up sending the packet without recording * that we sent the FIN bit. * * We can't just blindly clear the FIN bit, * because if we don't have any more data * to send then the probe will be the FIN * itself. */ if (off < so->so_snd.sb_cc) flags &= ~TH_FIN; win = 1; } else { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } len = min(so->so_snd.sb_cc, win) - off; if (len < 0) { /* * If FIN has been sent but not acked, * but we haven't been called to retransmit, * len will be -1. Otherwise, window shrank * after we sent into it. If window shrank to 0, * cancel pending retransmit and pull snd_nxt * back to (closed) window. We will enter persist * state below. If the window didn't close completely, * just wait for an ACK. */ len = 0; if (win == 0) { tp->t_timer[TCPT_REXMT] = 0; tp->snd_nxt = tp->snd_una; } } if (len > tp->t_maxseg) { len = tp->t_maxseg; sendalot = 1; } if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) flags &= ~TH_FIN; win = sbspace(&so->so_rcv); /* * Sender silly window avoidance. If connection is idle * and can send all data, a maximum segment, * at least a maximum default-size segment do it, * or are forced, do it; otherwise don't bother. * If peer's buffer is tiny, then send * when window is at least half open. * If retransmitting (possibly after persist timer forced us * to send into a small window), then must resend. */ if (len) { if (len == tp->t_maxseg) goto send; if ((1 || idle || tp->t_flags & TF_NODELAY) && len + off >= so->so_snd.sb_cc) goto send; if (tp->t_force) goto send; if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) goto send; if (SEQ_LT(tp->snd_nxt, tp->snd_max)) goto send; } /* * Compare available window to amount of window * known to peer (as advertised window less * next expected input). If the difference is at least two * max size segments, or at least 50% of the maximum possible * window, then want to send a window update to peer. */ if (win > 0) { /* * "adv" is the amount we can increase the window, * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - (tp->rcv_adv - tp->rcv_nxt); if (adv >= (long) (2 * tp->t_maxseg)) goto send; if (2 * adv >= (long) so->so_rcv.sb_datalen) goto send; } /* * Send if we owe peer an ACK. */ if (tp->t_flags & TF_ACKNOW) goto send; if (flags & (TH_SYN|TH_RST)) goto send; if (SEQ_GT(tp->snd_up, tp->snd_una)) goto send; /* * If our state indicates that FIN should be sent * and we have not yet done so, or we're retransmitting the FIN, * then we need to send. */ if (flags & TH_FIN && ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) goto send; /* * TCP window updates are not reliable, rather a polling protocol * using ``persist'' packets is used to insure receipt of window * updates. The three ``states'' for the output side are: * idle not doing retransmits or persists * persisting to move a small or zero window * (re)transmitting and thereby not persisting * * tp->t_timer[TCPT_PERSIST] * is set when we are in persist state. * tp->t_force * is set when we are called to send a persist packet. * tp->t_timer[TCPT_REXMT] * is set when we are retransmitting * The output side is idle when both timers are zero. * * If send window is too small, there is data to transmit, and no * retransmit or persist is pending, then go to persist state. * If nothing happens soon, send when timer expires: * if window is nonzero, transmit what we can, * otherwise force out a byte. */ if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) { tp->t_rxtshift = 0; tcp_setpersist(tp); } /* * No reason to send a segment, just return. */ tcpstat.tcps_didnuttin++; return (0); send: /* * Before ESTABLISHED, force sending of initial options * unless TCP set not to do any options. * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN */ optlen = 0; hdrlen = sizeof (struct tcpiphdr); if (flags & TH_SYN) { tp->snd_nxt = tp->iss; if ((tp->t_flags & TF_NOOPT) == 0) { u_int16_t mss; opt[0] = TCPOPT_MAXSEG; opt[1] = 4; mss = htons((u_int16_t) tcp_mss(tp, 0)); memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss)); optlen = 4; /* if ((tp->t_flags & TF_REQ_SCALE) && * ((flags & TH_ACK) == 0 || * (tp->t_flags & TF_RCVD_SCALE))) { * *((u_int32_t *) (opt + optlen)) = htonl( * TCPOPT_NOP << 24 | * TCPOPT_WINDOW << 16 | * TCPOLEN_WINDOW << 8 | * tp->request_r_scale); * optlen += 4; * } */ } } /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_REQ_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ /* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && * (flags & TH_RST) == 0 && * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || * (tp->t_flags & TF_RCVD_TSTMP))) { * u_int32_t *lp = (u_int32_t *)(opt + optlen); * * / * Form timestamp option as shown in appendix A of RFC 1323. * / * *lp++ = htonl(TCPOPT_TSTAMP_HDR); * *lp++ = htonl(tcp_now); * *lp = htonl(tp->ts_recent); * optlen += TCPOLEN_TSTAMP_APPA; * } */ hdrlen += optlen; /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. */ if (len > tp->t_maxseg - optlen) { len = tp->t_maxseg - optlen; sendalot = 1; } /* * Grab a header mbuf, attaching a copy of data to * be transmitted, and initialize the header from * the template for sends on this connection. */ if (len) { if (tp->t_force && len == 1) tcpstat.tcps_sndprobe++; else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { tcpstat.tcps_sndrexmitpack++; tcpstat.tcps_sndrexmitbyte += len; } else { tcpstat.tcps_sndpack++; tcpstat.tcps_sndbyte += len; } m = m_get(); if (m == NULL) { /* error = ENOBUFS; */ error = 1; goto out; } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; /* * This will always succeed, since we make sure our mbufs * are big enough to hold one MSS packet + header + ... etc. */ /* if (len <= MHLEN - hdrlen - max_linkhdr) { */ sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen); m->m_len += len; /* } else { * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); * if (m->m_next == 0) * len = 0; * } */ /* * If we're sending everything we've got, set PUSH. * (This will keep happy those implementations which only * give data to the user when a buffer fills or * a PUSH comes in.) */ if (off + len == so->so_snd.sb_cc) flags |= TH_PUSH; } else { if (tp->t_flags & TF_ACKNOW) tcpstat.tcps_sndacks++; else if (flags & (TH_SYN|TH_FIN|TH_RST)) tcpstat.tcps_sndctrl++; else if (SEQ_GT(tp->snd_up, tp->snd_una)) tcpstat.tcps_sndurg++; else tcpstat.tcps_sndwinup++; m = m_get(); if (m == NULL) { /* error = ENOBUFS; */ error = 1; goto out; } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; } ti = mtod(m, struct tcpiphdr *); memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); /* * Fill in fields, remembering maximum advertised * window for use in delaying messages about window sizes. * If resending a FIN, be sure not to use a new sequence number. */ if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && tp->snd_nxt == tp->snd_max) tp->snd_nxt--; /* * If we are doing retransmissions, then snd_nxt will * not reflect the first unsent octet. For ACK only * packets, we do not want the sequence number of the * retransmitted packet, we want the sequence number * of the next unsent octet. So, if there is no data * (and no SYN or FIN), use snd_max instead of snd_nxt * when filling in ti_seq. But if we are in persist * state, snd_max might reflect one byte beyond the * right edge of the window, so use snd_nxt in that * case, since we know we aren't doing a retransmission. * (retransmit and persist are mutually exclusive...) */ if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) ti->ti_seq = htonl(tp->snd_nxt); else ti->ti_seq = htonl(tp->snd_max); ti->ti_ack = htonl(tp->rcv_nxt); if (optlen) { memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen); ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; } ti->ti_flags = flags; /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) win = 0; if (win > (long)TCP_MAXWIN << tp->rcv_scale) win = (long)TCP_MAXWIN << tp->rcv_scale; if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) win = (long)(tp->rcv_adv - tp->rcv_nxt); ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); if (SEQ_GT(tp->snd_up, tp->snd_una)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); #ifdef notdef if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); #endif ti->ti_flags |= TH_URG; } else /* * If no urgent pointer to send, then we pull * the urgent pointer to the left edge of the send window * so that it doesn't drift into the send window on sequence * number wraparound. */ tp->snd_up = tp->snd_una; /* drag it along */ /* * Put TCP length in extended header, and then * checksum extended header and data. */ if (len + optlen) ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + optlen + len)); ti->ti_sum = cksum(m, (int)(hdrlen + len)); /* * In transmit state, time the transmission and arrange for * the retransmit. In persist state, just set snd_max. */ if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { tcp_seq startseq = tp->snd_nxt; /* * Advance snd_nxt over sequence space of this segment. */ if (flags & (TH_SYN|TH_FIN)) { if (flags & TH_SYN) tp->snd_nxt++; if (flags & TH_FIN) { tp->snd_nxt++; tp->t_flags |= TF_SENTFIN; } } tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; /* * Time this transmission if not a retransmission and * not currently timing anything. */ if (tp->t_rtt == 0) { tp->t_rtt = 1; tp->t_rtseq = startseq; tcpstat.tcps_segstimed++; } } /* * Set retransmit timer if not currently set, * and not doing an ack or a keep-alive probe. * Initial value for retransmit timer is smoothed * round-trip time + 2 * round-trip time variance. * Initialize shift counter which is used for backoff * of retransmit time. */ if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; if (tp->t_timer[TCPT_PERSIST]) { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) tp->snd_max = tp->snd_nxt + len; /* * Fill in IP length and desired time to live and * send to IP level. There should be a better way * to handle ttl and tos; we could keep them in * the template, but need a way to checksum without them. */ m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ { ((struct ip *)ti)->ip_len = m->m_len; ((struct ip *)ti)->ip_ttl = ip_defttl; ((struct ip *)ti)->ip_tos = so->so_iptos; /* #if BSD >= 43 */ /* Don't do IP options... */ /* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, * so->so_options & SO_DONTROUTE, 0); */ error = ip_output(so, m); /* #else * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, * so->so_options & SO_DONTROUTE); * #endif */ } if (error) { out: /* if (error == ENOBUFS) { * tcp_quench(tp->t_inpcb, 0); * return (0); * } */ /* if ((error == EHOSTUNREACH || error == ENETDOWN) * && TCPS_HAVERCVDSYN(tp->t_state)) { * tp->t_softerror = error; * return (0); * } */ return (error); } tcpstat.tcps_sndtotal++; /* * Data sent (as far as we can tell). * If this advertises a larger window than any other segment, * then remember the size of the advertised window. * Any pending ACK has now been sent. */ if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) tp->rcv_adv = tp->rcv_nxt + win; tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); if (sendalot) goto again; return (0); } void tcp_setpersist(tp) register struct tcpcb *tp; { register t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; /* if (tp->t_timer[TCPT_REXMT]) * panic("tcp_output REXMT"); */ /* * Start/restart persistence timer. */ TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], t * tcp_backoff[tp->t_rxtshift], TCPTV_PERSMIN, TCPTV_PERSMAX); if (tp->t_rxtshift < TCP_MAXRXTSHIFT) tp->t_rxtshift++; } slirp-1.0.17/src/tcp_output.p0000644000175000017500000000014110115325666015164 0ustar roverroverint tcp_output _P((register struct tcpcb *)); void tcp_setpersist _P((register struct tcpcb *)); slirp-1.0.17/src/tcp_subr.c0000644000175000017500000010515110117216006014556 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * 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. * * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include /* patchable/settable parameters for tcp */ int tcp_mssdflt = TCP_MSS; int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ int tcp_rcvspace; /* You may want to change this */ int tcp_sndspace; /* Keep small if you have an error prone link */ /* * Tcp initialization */ void tcp_init() { tcp_iss = 1; /* wrong */ tcb.so_next = tcb.so_prev = &tcb; /* tcp_rcvspace = our Window we advertise to the remote */ tcp_rcvspace = TCP_RCVSPACE; tcp_sndspace = TCP_SNDSPACE; /* Make sure tcp_sndspace is at least 2*MSS */ if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); } /* * Create template to be used to send tcp packets on a connection. * Call after host entry created, fills * in a skeletal tcp/ip header, minimizing the amount of work * necessary when the connection is used. */ /* struct tcpiphdr * */ void tcp_template(tp) struct tcpcb *tp; { struct socket *so = tp->t_socket; register struct tcpiphdr *n = &tp->t_template; n->ti_next = n->ti_prev = 0; n->ti_x1 = 0; n->ti_pr = IPPROTO_TCP; n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); n->ti_src = so->so_faddr; n->ti_dst = so->so_laddr; n->ti_sport = so->so_fport; n->ti_dport = so->so_lport; n->ti_seq = 0; n->ti_ack = 0; n->ti_x2 = 0; n->ti_off = 5; n->ti_flags = 0; n->ti_win = 0; n->ti_sum = 0; n->ti_urp = 0; } /* * Send a single message to the TCP at address specified by * the given TCP/IP header. If m == 0, then we make a copy * of the tcpiphdr at ti and send directly to the addressed host. * This is used to force keep alive messages out using the TCP * template for a connection tp->t_template. If flags are given * then we send a message back to the TCP which originated the * segment ti, and discard the mbuf containing it and any other * attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. */ void tcp_respond(tp, ti, m, ack, seq, flags) struct tcpcb *tp; register struct tcpiphdr *ti; register struct mbuf *m; tcp_seq ack, seq; int flags; { register int tlen; int win = 0; DEBUG_CALL("tcp_respond"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("ti = %lx", (long)ti); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("ack = %u", ack); DEBUG_ARG("seq = %u", seq); DEBUG_ARG("flags = %x", flags); if (tp) win = sbspace(&tp->t_socket->so_rcv); if (m == 0) { if ((m = m_get()) == NULL) return; #ifdef TCP_COMPAT_42 tlen = 1; #else tlen = 0; #endif m->m_data += if_maxlinkhdr; *mtod(m, struct tcpiphdr *) = *ti; ti = mtod(m, struct tcpiphdr *); flags = TH_ACK; } else { /* * ti points into m so the next line is just making * the mbuf point to ti */ m->m_data = (caddr_t)ti; m->m_len = sizeof (struct tcpiphdr); tlen = 0; #define xchg(a,b,type) { type t; t=a; a=b; b=t; } xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); xchg(ti->ti_dport, ti->ti_sport, u_int16_t); #undef xchg } ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); tlen += sizeof (struct tcpiphdr); m->m_len = tlen; ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_seq = htonl(seq); ti->ti_ack = htonl(ack); ti->ti_x2 = 0; ti->ti_off = sizeof (struct tcphdr) >> 2; ti->ti_flags = flags; if (tp) ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); else ti->ti_win = htons((u_int16_t)win); ti->ti_urp = 0; ti->ti_sum = 0; ti->ti_sum = cksum(m, tlen); ((struct ip *)ti)->ip_len = tlen; if(flags & TH_RST) ((struct ip *)ti)->ip_ttl = MAXTTL; else ((struct ip *)ti)->ip_ttl = ip_defttl; (void) ip_output((struct socket *)0, m); } /* * Create a new TCP control block, making an * empty reassembly queue and hooking it to the argument * protocol control block. */ struct tcpcb * tcp_newtcpcb(so) struct socket *so; { register struct tcpcb *tp; tp = (struct tcpcb *)malloc(sizeof(*tp)); if (tp == NULL) return ((struct tcpcb *)0); memset((char *) tp, 0, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; tp->t_maxseg = tcp_mssdflt; tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_socket = so; /* * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives * reasonable initial retransmit time. */ tp->t_srtt = TCPTV_SRTTBASE; tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; tp->t_rttmin = TCPTV_MIN; TCPT_RANGESET(tp->t_rxtcur, ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_state = TCPS_CLOSED; so->so_tcpcb = tp; return (tp); } /* * Drop a TCP connection, reporting * the specified error. If connection is synchronized, * then send a RST to peer. tcp_drop(struct tcpcb *tp, int errno) { */ struct tcpcb * tcp_drop(tp, errNo) register struct tcpcb *tp; int errNo; { DEBUG_CALL("tcp_drop"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("errno = %d", errNo); if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; (void) tcp_output(tp); tcpstat.tcps_drops++; } else tcpstat.tcps_conndrops++; /* if (errNo == ETIMEDOUT && tp->t_softerror) * errNo = tp->t_softerror; */ /* so->so_error = errNo; */ return (tcp_close(tp)); } /* * Close a TCP control block: * discard all space held by the tcp * discard internet protocol block * wake up any sleepers */ struct tcpcb * tcp_close(tp) register struct tcpcb *tp; { register struct tcpiphdr *t; struct socket *so = tp->t_socket; register struct mbuf *m; DEBUG_CALL("tcp_close"); DEBUG_ARG("tp = %lx", (long )tp); /* free the reassembly queue, if any */ t = (struct tcpiphdr *) tp->seg_next; while (t != (struct tcpiphdr *)tp) { t = (struct tcpiphdr *)t->ti_next; m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); remque_32((struct tcpiphdr *) t->ti_prev); m_freem(m); } /* It's static */ /* if (tp->t_template) * (void) m_free(dtom(tp->t_template)); */ /* free(tp, M_PCB); */ free(tp); so->so_tcpcb = 0; soisfdisconnected(so); /* clobber input socket cache if we're closing the cached connection */ if (so == tcp_last_so) tcp_last_so = &tcb; close(so->s); sbfree(&so->so_rcv); sbfree(&so->so_snd); sofree(so); tcpstat.tcps_closed++; return ((struct tcpcb *)0); } void tcp_drain() { /* XXX */ } /* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. */ #ifdef notdef void tcp_quench(i, errNo) int errNo; { struct tcpcb *tp = intotcpcb(inp); if (tp) tp->snd_cwnd = tp->t_maxseg; } #endif /* notdef */ /* * TCP protocol interface to socket abstraction. */ /* * User issued close, and wish to trail through shutdown states: * if never received SYN, just forget it. If got a SYN from peer, * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. * If already got a FIN from peer, then almost done; go to LAST_ACK * state. In all other cases, have already sent FIN to peer (e.g. * after PRU_SHUTDOWN), and just have to play tedious game waiting * for peer to send FIN or not respond to keep-alives, etc. * We can let the user exit from the close as soon as the FIN is acked. */ void tcp_sockclosed(tp) struct tcpcb *tp; { DEBUG_CALL("tcp_sockclosed"); DEBUG_ARG("tp = %lx", (long)tp); switch (tp->t_state) { case TCPS_CLOSED: case TCPS_LISTEN: case TCPS_SYN_SENT: tp->t_state = TCPS_CLOSED; tp = tcp_close(tp); break; case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: tp->t_state = TCPS_FIN_WAIT_1; break; case TCPS_CLOSE_WAIT: tp->t_state = TCPS_LAST_ACK; break; } /* soisfdisconnecting(tp->t_socket); */ if (tp && tp->t_state >= TCPS_FIN_WAIT_2) soisfdisconnected(tp->t_socket); if (tp) tcp_output(tp); } /* * Connect to a host on the Internet * Called by tcp_input * Only do a connect, the tcp fields will be set in tcp_input * return 0 if there's a result of the connect, * else return -1 means we're still connecting * The return value is almost always -1 since the socket is * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ int tcp_fconnect(so) struct socket *so; { int ret=0; DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { int opt, s=so->s; struct sockaddr_in addr; fd_nonblock(s); opt = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " "addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* We don't care what port we get */ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); /* * If it's not in progress, it failed, so we just return 0, * without clearing SS_NOFDREF */ soisfconnecting(so); } return(ret); } /* * Accept the socket and connect to the local-host * * We have a problem. The correct thing to do would be * to first connect to the local-host, and only if the * connection is accepted, then do an accept() here. * But, a) we need to know who's trying to connect * to the socket to be able to SYN the local-host, and * b) we are already connected to the foreign host by * the time it gets to accept(), so... We simply accept * here and SYN the local-host. */ void tcp_connect(inso) struct socket *inso; { struct socket *so; struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); struct tcpcb *tp; int s, opt; DEBUG_CALL("tcp_connect"); DEBUG_ARG("inso = %lx", (long)inso); /* * If it's an SS_ACCEPTONCE socket, no need to socreate() * another socket, just use the accept() socket. */ if (inso->so_state & SS_FACCEPTONCE) { /* FACCEPTONCE already have a tcpcb */ so = inso; } else { if ((so = socreate()) == NULL) { /* If it failed, get rid of the pending connection */ close(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); return; } if (tcp_attach(so) < 0) { free(so); /* NOT sofree */ return; } so->so_laddr = inso->so_laddr; so->so_lport = inso->so_lport; } (void) tcp_mss(sototcpcb(so), 0); if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { tcp_close(sototcpcb(so)); /* This will sofree() as well */ return; } fd_nonblock(s); opt = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); so->so_fport = addr.sin_port; so->so_faddr = addr.sin_addr; /* Translate connections from localhost to the real hostname */ if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) so->so_faddr = our_addr; /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { close(so->s); /* If we only accept once, close the accept() socket */ so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ /* if it's not FACCEPTONCE, it's already NOFDREF */ } so->s = s; so->so_iptos = tcp_tos(so); tp = sototcpcb(so); tcp_template(tp); /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) * tp->request_r_scale++; */ /* soisconnecting(so); */ /* NOFDREF used instead */ tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); } /* * Attach a TCPCB to a socket. */ int tcp_attach(so) struct socket *so; { if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) return -1; insque(so, &tcb); return 0; } /* * Set the socket's type of service field */ struct tos_t tcptos[] = { {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ {0, 0, 0, 0} }; struct emu_t *tcpemu = 0; /* * Return TOS according to the above table */ u_int8_t tcp_tos(so) struct socket *so; { int i = 0; struct emu_t *emup; while(tcptos[i].tos) { if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { so->so_emu = tcptos[i].emu; return tcptos[i].tos; } i++; } /* Nope, lets see if there's a user-added one */ for (emup = tcpemu; emup; emup = emup->next) { if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || (emup->lport && (ntohs(so->so_lport) == emup->lport))) { so->so_emu = emup->emu; return emup->tos; } } return 0; } int do_echo = -1; /* * Emulate programs that try and connect to us * This includes ftp (the data connection is * initiated by the server) and IRC (DCC CHAT and * DCC SEND) for now * * NOTE: It's possible to crash SLiRP by sending it * unstandard strings to emulate... if this is a problem, * more checks are needed here * * XXX Assumes the whole command came in one packet * * XXX Some ftp clients will have their TOS set to * LOWDELAY and so Nagel will kick in. Because of this, * we'll get the first letter, followed by the rest, so * we simply scan for ORT instead of PORT... * DCC doesn't have this problem because there's other stuff * in the packet before the DCC command. * * Return 1 if the mbuf m is still valid and should be * sbappend()ed * * NOTE: if you return 0 you MUST m_free() the mbuf! */ int tcp_emu(so, m) struct socket *so; struct mbuf *m; { u_int n1, n2, n3, n4, n5, n6; char buff[256]; u_int32_t laddr; u_int lport; char *bptr; DEBUG_CALL("tcp_emu"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); switch(so->so_emu) { int x, i; case EMU_IDENT: /* * Identification protocol as per rfc-1413 */ { struct socket *tmpso; struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); struct sbuf *so_rcv = &so->so_rcv; memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m->m_data[m->m_len] = 0; /* NULL terminate */ if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { HTONS(n1); HTONS(n2); /* n2 is the one on our host */ for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && tmpso->so_lport == n2 && tmpso->so_faddr.s_addr == so->so_faddr.s_addr && tmpso->so_fport == n1) { if (getsockname(tmpso->s, (struct sockaddr *)&addr, &addrlen) == 0) n2 = ntohs(addr.sin_port); break; } } } so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); so_rcv->sb_rptr = so_rcv->sb_data; so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; } m_free(m); return 0; } case EMU_RLOGIN: /* * Rlogin emulation * First we accumulate all the initial option negotiation, * then fork_exec() rlogin according to the options */ { int i, i2, n; char *ptr; char args[100]; char term[100]; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); m_free(m); return 0; } /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); /* * Check if we have all the initial options, * and build argument list to rlogin while we're here */ n = 0; ptr = so_rcv->sb_data; args[0] = 0; term[0] = 0; while (ptr < so_rcv->sb_wptr) { if (*ptr++ == 0) { n++; if (n == 2) { snprintf(args, sizeof(args), "rlogin -l %s %s", ptr, inet_ntoa(so->so_faddr)); } else if (n == 3) { i2 = so_rcv->sb_wptr - ptr; for (i = 0; i < i2; i++) { if (ptr[i] == '/') { ptr[i] = 0; #ifdef HAVE_SETENV snprintf(term, sizeof(term), "%s", ptr); #else snprintf(term, sizeof(term), "TERM=%s", ptr); #endif ptr[i] = '/'; break; } } } } } if (n != 4) return 0; /* We have it, set our term variable and fork_exec() */ #ifdef HAVE_SETENV setenv("TERM", term, 1); #else putenv(term); #endif fork_exec(so, args, 2); term[0] = 0; so->so_emu = 0; /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; return 0; } case EMU_RSH: /* * rsh emulation * First we accumulate all the initial option negotiation, * then rsh_exec() rsh according to the options */ { int n; char *ptr; char *user; char *args; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); m_free(m); return 0; } /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); /* * Check if we have all the initial options, * and build argument list to rlogin while we're here */ n = 0; ptr = so_rcv->sb_data; user=""; args=""; if (so->extra==NULL) { struct socket *ns; struct tcpcb* tp; int port=atoi(ptr); if (port <= 0) return 0; if (port > 1023 || port < 512) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); return 0; } if ((ns=socreate()) == NULL) return 0; if (tcp_attach(ns)<0) { free(ns); return 0; } ns->so_laddr=so->so_laddr; ns->so_lport=htons(port); (void) tcp_mss(sototcpcb(ns), 0); ns->so_faddr=so->so_faddr; ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ if (ns->so_faddr.s_addr == 0 || ns->so_faddr.s_addr == loopback_addr.s_addr) ns->so_faddr = our_addr; ns->so_iptos = tcp_tos(ns); tp = sototcpcb(ns); tcp_template(tp); /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) * tp->request_r_scale++; */ /*soisfconnecting(ns);*/ tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); so->extra=ns; } while (ptr < so_rcv->sb_wptr) { if (*ptr++ == 0) { n++; if (n == 2) { user=ptr; } else if (n == 3) { args=ptr; } } } if (n != 4) return 0; rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); so->so_emu = 0; so->extra=NULL; /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; return 0; } case EMU_CTL: { int num; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* * If there is binary data here, we save it in so->so_m */ if (!so->so_m) { int rxlen; char *rxdata; rxdata=mtod(m, char *); for (rxlen=m->m_len; rxlen; rxlen--) { if (*rxdata++ & 0x80) { so->so_m = m; return 0; } } } /* if(so->so_m==NULL) */ /* * Append the line */ sbappendsb(so_rcv, m); /* To avoid going over the edge of the buffer, we reset it */ if (so_snd->sb_cc == 0) so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; /* * A bit of a hack: * If the first packet we get here is 1 byte long, then it * was done in telnet character mode, therefore we must echo * the characters as they come. Otherwise, we echo nothing, * because in linemode, the line is already echoed * XXX two or more control connections won't work */ if (do_echo == -1) { if (m->m_len == 1) do_echo = 1; else do_echo = 0; } if (do_echo) { sbappendsb(so_snd, m); m_free(m); tcp_output(sototcpcb(so)); /* XXX */ } else m_free(m); num = 0; while (num < so->so_rcv.sb_cc) { if (*(so->so_rcv.sb_rptr + num) == '\n' || *(so->so_rcv.sb_rptr + num) == '\r') { int n; *(so_rcv->sb_rptr + num) = 0; if (ctl_password && !ctl_password_ok) { /* Need a password */ if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { if (strcmp(buff, ctl_password) == 0) { ctl_password_ok = 1; n = sprintf(so_snd->sb_wptr, "Password OK.\r\n"); goto do_prompt; } } n = sprintf(so_snd->sb_wptr, "Error: Password required, log on with \"pass PASSWORD\"\r\n"); goto do_prompt; } cfg_quitting = 0; n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); if (!cfg_quitting) { /* Register the printed data */ do_prompt: so_snd->sb_cc += n; so_snd->sb_wptr += n; /* Add prompt */ n = sprintf(so_snd->sb_wptr, "Slirp> "); so_snd->sb_cc += n; so_snd->sb_wptr += n; } /* Drop so_rcv data */ so_rcv->sb_cc = 0; so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; tcp_output(sototcpcb(so)); /* Send the reply */ } num++; } return 0; } case EMU_FTP: /* ftp */ *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { /* * Need to emulate the PORT command */ x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; n6 = ntohs(so->so_fport); n5 = (n6 >> 8) & 0xff; n6 &= 0xff; laddr = ntohl(so->so_faddr.s_addr); n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ /* SECURITY TODO: Length Check */ m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { /* * Need to emulate the PASV response */ x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; n6 = ntohs(so->so_fport); n5 = (n6 >> 8) & 0xff; n6 &= 0xff; laddr = ntohl(so->so_faddr.s_addr); n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ /* SECURITY TODO: length check */ m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } return 1; case EMU_KSH: /* * The kshell (Kerberos rsh) and shell services both pass * a local port port number to carry signals to the server * and stderr to the client. It is passed at the beginning * of the connection as a NUL-terminated decimal ASCII string. */ so->so_emu = 0; for (lport = 0, i = 0; i < m->m_len-1; ++i) { if (m->m_data[i] < '0' || m->m_data[i] > '9') return 1; /* invalid number */ lport *= 10; lport += m->m_data[i] - '0'; } if (m->m_data[m->m_len-1] == '\0' && lport != 0 && (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; return 1; case EMU_IRC: /* * Need to emulate DCC CHAT, DCC SEND and DCC MOVE */ *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) return 1; /* The %256s is for the broken mIRC */ if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ /* SECURITY TODO: length check */ m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), 1); } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ /* SECURITY TODO: length check */ m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); } return 1; case EMU_REALAUDIO: /* * RealAudio emulation - JP. We must try to parse the incoming * data and try to find the two characters that contain the * port number. Then we redirect an udp port and replace the * number with the real port we got. * * The 1.0 beta versions of the player are not supported * any more. * * A typical packet for player version 1.0 (release version): * * 0000:50 4E 41 00 05 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB * * Now the port number 0x1BD7 is found at offset 0x04 of the * Now the port number 0x1BD7 is found at offset 0x04 of the * second packet. This time we received five bytes first and * then the rest. You never know how many bytes you get. * * A typical packet for player version 2.0 (beta): * * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á. * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B * * Port number 0x1BC1 is found at offset 0x0d. * * This is just a horrible switch statement. Variable ra tells * us where we're going. */ bptr = m->m_data; while (bptr < m->m_data + m->m_len) { u_short p; static int ra = 0; char ra_tbl[4]; ra_tbl[0] = 0x50; ra_tbl[1] = 0x4e; ra_tbl[2] = 0x41; ra_tbl[3] = 0; switch (ra) { case 0: case 2: case 3: if (*bptr++ != ra_tbl[ra]) { ra = 0; continue; } break; case 1: /* * We may get 0x50 several times, ignore them */ if (*bptr == 0x50) { ra = 1; bptr++; continue; } else if (*bptr++ != ra_tbl[ra]) { ra = 0; continue; } break; case 4: /* * skip version number */ bptr++; break; case 5: /* * The difference between versions 1.0 and * 2.0 is here. For future versions of * the player this may need to be modified. */ if (*(bptr + 1) == 0x02) bptr += 8; else bptr += 4; break; case 6: /* This is the field containing the port * number that RA-player is listening to. */ lport = (((u_char*)bptr)[0] << 8) + ((u_char *)bptr)[1]; if (lport < 6970) lport += 256; /* don't know why */ if (lport < 6970 || lport > 7170) return 1; /* failed */ /* try to get udp port between 6970 - 7170 */ for (p = 6970; p < 7071; p++) { if (udp_listen( htons(p), so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) { break; } } if (p == 7071) p = 0; *(u_char *)bptr++ = (p >> 8) & 0xff; *(u_char *)bptr++ = p & 0xff; ra = 0; return 1; /* port redirected, we're done */ break; default: ra = 0; } ra++; } return 1; default: /* Ooops, not emulated, won't call tcp_emu again */ so->so_emu = 0; return 1; } } /* * Do misc. config of SLiRP while its running. * Return 0 if this connections is to be closed, 1 otherwise, * return 2 if this is a command-line connection */ int tcp_ctl(so) struct socket *so; { struct sbuf *sb = &so->so_snd; int command; struct ex_list *ex_ptr; int do_pty; struct socket *tmpso; DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %lx", (long )so); /* * Check if they're authorised */ if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); sb->sb_wptr += sb->sb_cc; return 0; } command = (ntohl(so->so_faddr.s_addr) & 0xff); switch(command) { default: /* Check for exec's */ /* * Check if it's pty_exec */ for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_fport == so->so_fport && command == ex_ptr->ex_addr) { do_pty = ex_ptr->ex_pty; goto do_exec; } } /* * Nothing bound.. */ /* tcp_fconnect(so); */ /* FALLTHROUGH */ case CTL_ALIAS: sb->sb_cc = sprintf(sb->sb_wptr, "Error: No application configured.\r\n"); sb->sb_wptr += sb->sb_cc; return(0); do_exec: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); return(fork_exec(so, ex_ptr->ex_exec, do_pty)); case CTL_CMD: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { if (tmpso->so_emu == EMU_CTL && !(tmpso->so_tcpcb? (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) :0)) { /* Ooops, control connection already active */ sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); sb->sb_wptr += sb->sb_cc; return 0; } } so->so_emu = EMU_CTL; ctl_password_ok = 0; sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); sb->sb_wptr += sb->sb_cc; do_echo=-1; return(2); } } slirp-1.0.17/src/tcp_subr.p0000644000175000017500000000124110117224466014577 0ustar roverrovervoid tcp_init _P((void)); void tcp_template _P((struct tcpcb *)); void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int)); struct tcpcb * tcp_newtcpcb _P((struct socket *)); struct tcpcb * tcp_drop _P((register struct tcpcb *, int)); struct tcpcb * tcp_close _P((register struct tcpcb *)); void tcp_drain _P((void)); void tcp_sockclosed _P((struct tcpcb *)); int tcp_fconnect _P((struct socket *)); void tcp_connect _P((struct socket *)); int tcp_attach _P((struct socket *)); u_int8_t tcp_tos _P((struct socket *)); int tcp_emu _P((struct socket *, struct mbuf *)); int tcp_ctl _P((struct socket *)); slirp-1.0.17/src/tcp_timer.c0000644000175000017500000002277310115276014014736 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * 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. * * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp */ #include #define max(x,y) ((x) > (y) ? (x) : (y)) #define min(x,y) ((x) < (y) ? (x) : (y)) int tcp_keepidle = TCPTV_KEEP_IDLE; int tcp_keepintvl = TCPTV_KEEPINTVL; int tcp_maxidle; int so_options = DO_KEEPALIVE; struct tcpstat tcpstat; /* tcp statistics */ u_int32_t tcp_now; /* for RFC 1323 timestamps */ /* * Fast timeout routine for processing delayed acks */ void tcp_fasttimo() { register struct socket *so; register struct tcpcb *tp; DEBUG_CALL("tcp_fasttimo"); so = tcb.so_next; if (so) for (; so != &tcb; so = so->so_next) if ((tp = (struct tcpcb *)so->so_tcpcb) && (tp->t_flags & TF_DELACK)) { tp->t_flags &= ~TF_DELACK; tp->t_flags |= TF_ACKNOW; tcpstat.tcps_delack++; (void) tcp_output(tp); } } /* * Tcp protocol timeout routine called every 500 ms. * Updates the timers in all active tcb's and * causes finite state machine actions if timers expire. */ void tcp_slowtimo() { register struct socket *ip, *ipnxt; register struct tcpcb *tp; register int i; DEBUG_CALL("tcp_slowtimo"); tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; /* * Search through tcb's and update active timers. */ ip = tcb.so_next; if (ip == 0) return; for (; ip != &tcb; ip = ipnxt) { ipnxt = ip->so_next; tp = sototcpcb(ip); if (tp == 0) continue; for (i = 0; i < TCPT_NTIMERS; i++) { if (tp->t_timer[i] && --tp->t_timer[i] == 0) { tcp_timers(tp,i); if (ipnxt->so_prev != ip) goto tpgone; } } tp->t_idle++; if (tp->t_rtt) tp->t_rtt++; tpgone: ; } tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ #ifdef TCP_COMPAT_42 if ((int)tcp_iss < 0) tcp_iss = 0; /* XXX */ #endif tcp_now++; /* for timestamps */ } /* * Cancel all timers for TCP tp. */ void tcp_canceltimers(tp) struct tcpcb *tp; { register int i; for (i = 0; i < TCPT_NTIMERS; i++) tp->t_timer[i] = 0; } int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; /* * TCP timer processing. */ struct tcpcb * tcp_timers(tp, timer) register struct tcpcb *tp; int timer; { register int rexmt; DEBUG_CALL("tcp_timers"); switch (timer) { /* * 2 MSL timeout in shutdown went off. If we're closed but * still waiting for peer to close and connection has been idle * too long, or if 2MSL time is up from TIME_WAIT, delete connection * control block. Otherwise, check again in a bit. */ case TCPT_2MSL: if (tp->t_state != TCPS_TIME_WAIT && tp->t_idle <= tcp_maxidle) tp->t_timer[TCPT_2MSL] = tcp_keepintvl; else tp = tcp_close(tp); break; /* * Retransmission timer went off. Message has not * been acked within retransmit interval. Back off * to a longer retransmit interval and retransmit one segment. */ case TCPT_REXMT: /* * XXXXX If a packet has timed out, then remove all the queued * packets for that session. */ if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { /* * This is a hack to suit our terminal server here at the uni of canberra * since they have trouble with zeroes... It usually lets them through * unharmed, but under some conditions, it'll eat the zeros. If we * keep retransmitting it, it'll keep eating the zeroes, so we keep * retransmitting, and eventually the connection dies... * (this only happens on incoming data) * * So, if we were gonna drop the connection from too many retransmits, * don't... instead halve the t_maxseg, which might break up the NULLs and * let them through * * *sigh* */ tp->t_maxseg >>= 1; if (tp->t_maxseg < 32) { /* * We tried our best, now the connection must die! */ tp->t_rxtshift = TCP_MAXRXTSHIFT; tcpstat.tcps_timeoutdrop++; tp = tcp_drop(tp, tp->t_softerror); /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ return (tp); /* XXX */ } /* * Set rxtshift to 6, which is still at the maximum * backoff time */ tp->t_rxtshift = 6; } tcpstat.tcps_rexmttimeo++; rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * If losing, let the lower level know and try for * a better route. Also, if we backed off this far, * our srtt estimate is probably bogus. Clobber it * so we'll take the next rtt measurement as our srtt; * move the current srtt into rttvar to keep the current * retransmit times until then. */ if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { /* in_losing(tp->t_inpcb); */ tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); tp->t_srtt = 0; } tp->snd_nxt = tp->snd_una; /* * If timing a segment in this window, stop the timer. */ tp->t_rtt = 0; /* * Close the congestion window down to one segment * (we'll open it by one segment for each ack we get). * Since we probably have a window's worth of unacked * data accumulated, this "slow start" keeps us from * dumping all that data as back-to-back packets (which * might overwhelm an intermediate gateway). * * There are two phases to the opening: Initially we * open by one mss on each ack. This makes the window * size increase exponentially with time. If the * window is larger than the path can handle, this * exponential growth results in dropped packet(s) * almost immediately. To get more time between * drops but still "push" the network to take advantage * of improving conditions, we switch from exponential * to linear window opening at some threshold size. * For a threshold, we use half the current window * size, truncated to a multiple of the mss. * * (the minimum cwnd that will give us exponential * growth is 2 mss. We don't allow the threshold * to go below this.) */ { u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_cwnd = tp->t_maxseg; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_dupacks = 0; } (void) tcp_output(tp); break; /* * Persistence timer into zero window. * Force a byte to be output, if possible. */ case TCPT_PERSIST: tcpstat.tcps_persisttimeo++; tcp_setpersist(tp); tp->t_force = 1; (void) tcp_output(tp); tp->t_force = 0; break; /* * Keep-alive timer went off; send something * or drop connection if idle for too long. */ case TCPT_KEEP: tcpstat.tcps_keeptimeo++; if (tp->t_state < TCPS_ESTABLISHED) goto dropit; /* if (tp->t_socket->so_options & SO_KEEPALIVE && */ if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { if (tp->t_idle >= tcp_keepidle + tcp_maxidle) goto dropit; /* * Send a packet designed to force a response * if the peer is up and reachable: * either an ACK if the connection is still alive, * or an RST if the peer has closed the connection * due to timeout or reboot. * Using sequence number tp->snd_una-1 * causes the transmitted zero-length segment * to lie outside the receive window; * by the protocol spec, this requires the * correspondent TCP to respond. */ tcpstat.tcps_keepprobe++; #ifdef TCP_COMPAT_42 /* * The keepalive packet must have nonzero length * to get a 4.2 host to respond. */ tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt - 1, tp->snd_una - 1, 0); #else tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt, tp->snd_una - 1, 0); #endif tp->t_timer[TCPT_KEEP] = tcp_keepintvl; } else tp->t_timer[TCPT_KEEP] = tcp_keepidle; break; dropit: tcpstat.tcps_keepdrops++; tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ break; } return (tp); } slirp-1.0.17/src/tcp_timer.h0000644000175000017500000001345010115276015014734 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp */ #ifndef _TCP_TIMER_H_ #define _TCP_TIMER_H_ /* * Definitions of the TCP timers. These timers are counted * down PR_SLOWHZ times a second. */ #define TCPT_NTIMERS 4 #define TCPT_REXMT 0 /* retransmit */ #define TCPT_PERSIST 1 /* retransmit persistence */ #define TCPT_KEEP 2 /* keep alive */ #define TCPT_2MSL 3 /* 2*msl quiet time timer */ /* * The TCPT_REXMT timer is used to force retransmissions. * The TCP has the TCPT_REXMT timer set whenever segments * have been sent for which ACKs are expected but not yet * received. If an ACK is received which advances tp->snd_una, * then the retransmit timer is cleared (if there are no more * outstanding segments) or reset to the base value (if there * are more ACKs expected). Whenever the retransmit timer goes off, * we retransmit one unacknowledged segment, and do a backoff * on the retransmit timer. * * The TCPT_PERSIST timer is used to keep window size information * flowing even if the window goes shut. If all previous transmissions * have been acknowledged (so that there are no retransmissions in progress), * and the window is too small to bother sending anything, then we start * the TCPT_PERSIST timer. When it expires, if the window is nonzero, * we go to transmit state. Otherwise, at intervals send a single byte * into the peer's window to force him to update our window information. * We do this at most as often as TCPT_PERSMIN time intervals, * but no more frequently than the current estimate of round-trip * packet time. The TCPT_PERSIST timer is cleared whenever we receive * a window update from the peer. * * The TCPT_KEEP timer is used to keep connections alive. If an * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, * but not yet established, then we drop the connection. Once the connection * is established, if the connection is idle for TCPTV_KEEP_IDLE time * (and keepalives have been enabled on the socket), we begin to probe * the connection. We force the peer to send us a segment by sending: * * This segment is (deliberately) outside the window, and should elicit * an ack segment in response from the peer. If, despite the TCPT_KEEP * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE * amount of time probing, then we drop the connection. */ /* * Time constants. */ #define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ #define TCPTV_SRTTBASE 0 /* base roundtrip time; if 0, no idea yet */ #define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ #define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ #define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ #define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ #define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ #define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ #define TCPTV_KEEPCNT 8 /* max probes before drop */ #define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ /* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ #define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ #define TCP_LINGERTIME 120 /* linger at most 2 minutes */ #define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ #ifdef TCPTIMERS char *tcptimers[] = { "REXMT", "PERSIST", "KEEP", "2MSL" }; #endif /* * Force a time value to be in a certain range. */ #define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ (tv) = (value); \ if ((tv) < (tvmin)) \ (tv) = (tvmin); \ else if ((tv) > (tvmax)) \ (tv) = (tvmax); \ } extern int tcp_keepidle; /* time before keepalive probes begin */ extern int tcp_keepintvl; /* time between keepalive probes */ extern int tcp_maxidle; /* time to drop after starting probes */ extern int tcp_ttl; /* time to live for TCP segs */ extern int tcp_backoff[]; #endif slirp-1.0.17/src/tcp_timer.p0000644000175000017500000000024610115325666014752 0ustar roverrovervoid tcp_fasttimo _P((void)); void tcp_slowtimo _P((void)); void tcp_canceltimers _P((struct tcpcb *)); struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); slirp-1.0.17/src/tcp_var.h0000644000175000017500000002505110115276015014404 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993, 1994 * 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. * * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp */ #ifndef _TCP_VAR_H_ #define _TCP_VAR_H_ #include "tcpip.h" #include "tcp_timer.h" #if SIZEOF_CHAR_P == 4 typedef struct tcpiphdr *tcpiphdrp_32; #else typedef u_int32_t tcpiphdrp_32; #endif /* * Tcp control block, one per tcp; fields: */ struct tcpcb { tcpiphdrp_32 seg_next; /* sequencing queue */ tcpiphdrp_32 seg_prev; short t_state; /* state of this connection */ short t_timer[TCPT_NTIMERS]; /* tcp timers */ short t_rxtshift; /* log(2) of rexmt exp. backoff */ short t_rxtcur; /* current retransmit value */ short t_dupacks; /* consecutive dup acks recd */ u_short t_maxseg; /* maximum segment size */ char t_force; /* 1 if forcing out a byte */ u_short t_flags; #define TF_ACKNOW 0x0001 /* ack peer immediately */ #define TF_DELACK 0x0002 /* ack, but try to delay it */ #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ #define TF_NOOPT 0x0008 /* don't use tcp options */ #define TF_SENTFIN 0x0010 /* have sent FIN */ #define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ #define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ #define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ #define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ /* Make it static for now */ /* struct tcpiphdr *t_template; / * skeletal packet for transmit */ struct tcpiphdr t_template; struct socket *t_socket; /* back pointer to socket */ /* * The following fields are used as in the protocol specification. * See RFC783, Dec. 1981, page 21. */ /* send sequence variables */ tcp_seq snd_una; /* send unacknowledged */ tcp_seq snd_nxt; /* send next */ tcp_seq snd_up; /* send urgent pointer */ tcp_seq snd_wl1; /* window update seg seq number */ tcp_seq snd_wl2; /* window update seg ack number */ tcp_seq iss; /* initial send sequence number */ u_int32_t snd_wnd; /* send window */ /* receive sequence variables */ u_int32_t rcv_wnd; /* receive window */ tcp_seq rcv_nxt; /* receive next */ tcp_seq rcv_up; /* receive urgent pointer */ tcp_seq irs; /* initial receive sequence number */ /* * Additional variables for this implementation. */ /* receive variables */ tcp_seq rcv_adv; /* advertised window */ /* retransmit variables */ tcp_seq snd_max; /* highest sequence number sent; * used to recognize retransmits */ /* congestion control (for slow start, source quench, retransmit after loss) */ u_int32_t snd_cwnd; /* congestion-controlled window */ u_int32_t snd_ssthresh; /* snd_cwnd size threshold for * for slow start exponential to * linear switch */ /* * transmit timing stuff. See below for scale of srtt and rttvar. * "Variance" is actually smoothed difference. */ short t_idle; /* inactivity time */ short t_rtt; /* round trip time */ tcp_seq t_rtseq; /* sequence number being timed */ short t_srtt; /* smoothed round-trip time */ short t_rttvar; /* variance in round-trip time */ u_short t_rttmin; /* minimum rtt allowed */ u_int32_t max_sndwnd; /* largest window peer has offered */ /* out-of-band data */ char t_oobflags; /* have some */ char t_iobc; /* input character */ #define TCPOOB_HAVEDATA 0x01 #define TCPOOB_HADDATA 0x02 short t_softerror; /* possible error not yet reported */ /* RFC 1323 variables */ u_char snd_scale; /* window scaling for send window */ u_char rcv_scale; /* window scaling for recv window */ u_char request_r_scale; /* pending window scaling */ u_char requested_s_scale; u_int32_t ts_recent; /* timestamp echo data */ u_int32_t ts_recent_age; /* when last updated */ tcp_seq last_ack_sent; }; #define sototcpcb(so) ((so)->so_tcpcb) /* * The smoothed round-trip time and estimated variance * are stored as fixed point numbers scaled by the values below. * For convenience, these scales are also used in smoothing the average * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). * With these scales, srtt has 3 bits to the right of the binary point, * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the * binary point, and is smoothed with an ALPHA of 0.75. */ #define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ #define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ #define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ #define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ /* * The initial retransmission should happen at rtt + 4 * rttvar. * Because of the way we do the smoothing, srtt and rttvar * will each average +1/2 tick of bias. When we compute * the retransmit timer, we want 1/2 tick of rounding and * 1 extra tick because of +-1/2 tick uncertainty in the * firing of the timer. The bias will give us exactly the * 1.5 tick we need. But, because the bias is * statistical, we have to test that we don't drop below * the minimum feasible timer (which is 2 ticks). * This macro assumes that the value of TCP_RTTVAR_SCALE * is the same as the multiplier for rttvar. */ #define TCP_REXMTVAL(tp) \ (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) /* XXX * We want to avoid doing m_pullup on incoming packets but that * means avoiding dtom on the tcp reassembly code. That in turn means * keeping an mbuf pointer in the reassembly queue (since we might * have a cluster). As a quick hack, the source & destination * port numbers (which are no longer needed once we've located the * tcpcb) are overlayed with an mbuf pointer. */ #if SIZEOF_CHAR_P == 4 typedef struct mbuf *mbufp_32; #else typedef u_int32_t mbufp_32; #endif #define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) /* * TCP statistics. * Many of these should be kept per connection, * but that's inconvenient at the moment. */ struct tcpstat { u_long tcps_connattempt; /* connections initiated */ u_long tcps_accepts; /* connections accepted */ u_long tcps_connects; /* connections established */ u_long tcps_drops; /* connections dropped */ u_long tcps_conndrops; /* embryonic connections dropped */ u_long tcps_closed; /* conn. closed (includes drops) */ u_long tcps_segstimed; /* segs where we tried to get rtt */ u_long tcps_rttupdated; /* times we succeeded */ u_long tcps_delack; /* delayed acks sent */ u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ u_long tcps_rexmttimeo; /* retransmit timeouts */ u_long tcps_persisttimeo; /* persist timeouts */ u_long tcps_keeptimeo; /* keepalive timeouts */ u_long tcps_keepprobe; /* keepalive probes sent */ u_long tcps_keepdrops; /* connections dropped in keepalive */ u_long tcps_sndtotal; /* total packets sent */ u_long tcps_sndpack; /* data packets sent */ u_long tcps_sndbyte; /* data bytes sent */ u_long tcps_sndrexmitpack; /* data packets retransmitted */ u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ u_long tcps_sndacks; /* ack-only packets sent */ u_long tcps_sndprobe; /* window probes sent */ u_long tcps_sndurg; /* packets sent with URG only */ u_long tcps_sndwinup; /* window update-only packets sent */ u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ u_long tcps_rcvtotal; /* total packets received */ u_long tcps_rcvpack; /* packets received in sequence */ u_long tcps_rcvbyte; /* bytes received in sequence */ u_long tcps_rcvbadsum; /* packets received with ccksum errs */ u_long tcps_rcvbadoff; /* packets received with bad offset */ /* u_long tcps_rcvshort; */ /* packets received too short */ u_long tcps_rcvduppack; /* duplicate-only packets received */ u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ u_long tcps_rcvpartduppack; /* packets with some duplicate data */ u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ u_long tcps_rcvoopack; /* out-of-order packets received */ u_long tcps_rcvoobyte; /* out-of-order bytes received */ u_long tcps_rcvpackafterwin; /* packets with data after window */ u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ u_long tcps_rcvafterclose; /* packets rcvd after "close" */ u_long tcps_rcvwinprobe; /* rcvd window probe packets */ u_long tcps_rcvdupack; /* rcvd duplicate acks */ u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ u_long tcps_rcvackpack; /* rcvd ack packets */ u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ u_long tcps_rcvwinupd; /* rcvd window update packets */ /* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ u_long tcps_predack; /* times hdr predict ok for acks */ u_long tcps_preddat; /* times hdr predict ok for data pkts */ u_long tcps_socachemiss; /* tcp_last_so misses */ u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ }; extern struct tcpstat tcpstat; /* tcp statistics */ extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ #endif slirp-1.0.17/src/tcpip.h0000644000175000017500000000527610115276015014074 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp */ #ifndef _TCPIP_H_ #define _TCPIP_H_ /* * Tcp+ip header, after ip options removed. */ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ struct tcphdr ti_t; /* tcp header */ }; #define ti_next ti_i.ih_next #define ti_prev ti_i.ih_prev #define ti_x1 ti_i.ih_x1 #define ti_pr ti_i.ih_pr #define ti_len ti_i.ih_len #define ti_src ti_i.ih_src #define ti_dst ti_i.ih_dst #define ti_sport ti_t.th_sport #define ti_dport ti_t.th_dport #define ti_seq ti_t.th_seq #define ti_ack ti_t.th_ack #define ti_x2 ti_t.th_x2 #define ti_off ti_t.th_off #define ti_flags ti_t.th_flags #define ti_win ti_t.th_win #define ti_sum ti_t.th_sum #define ti_urp ti_t.th_urp /* * Just a clean way to get to the first byte * of the packet */ struct tcpiphdr_2 { struct tcpiphdr dummy; char first_char; }; #endif slirp-1.0.17/src/terminal.c0000644000175000017500000000274310117206103014550 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ /* * Set/reset terminal attributes. * * If the fd is not a tty, then do nothing. This allows people * to use slirp over rsh or whatever. A tty/pty is not necessary. */ #include void term_raw(ttyp) struct ttys *ttyp; { struct termios tempio; if (!isatty(ttyp->fd)) return; tcgetattr(ttyp->fd, &tempio); ttyp->oldterm = tempio; /* fprintf(stderr, "Setting terminal %d to %d %d %d %d\n", ttyp->fd, ttyp->oldterm.c_iflag, ttyp->oldterm.c_oflag, ttyp->oldterm.c_cflag, ttyp->oldterm.c_lflag); */ tempio.c_iflag = 0; tempio.c_oflag = 0; tempio.c_lflag = 0; /* * Ok, I'm making this the default now *sigh* */ #ifndef USE_LOWCPU tempio.c_cc[VMIN] = 1; tempio.c_cc[VTIME] = 0; #else tempio.c_cc[VMIN] = 255; tempio.c_cc[VTIME] = 2; #endif #ifdef DO_CFSETSPEED cfsetospeed(&tempio, ttyp->baud); cfsetispeed(&tempio, ttyp->baud); #endif tcsetattr(ttyp->fd, TCSANOW, &tempio); } void term_restore(ttyp) struct ttys *ttyp; { if (!isatty(ttyp->fd)) return; tcsetattr(ttyp->fd, TCSANOW, &ttyp->oldterm); /* fprintf(stderr, "Restoring terminal %d to %d %d %d %d\n", ttyp->fd, ttyp->oldterm.c_iflag, ttyp->oldterm.c_oflag, ttyp->oldterm.c_cflag, ttyp->oldterm.c_lflag); */ } slirp-1.0.17/src/terminal.h0000644000175000017500000000021210115276015014551 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ slirp-1.0.17/src/terminal.p0000644000175000017500000000011410117207136014562 0ustar roverrovervoid term_raw _P((struct ttys *)); void term_restore _P((struct ttys *)); slirp-1.0.17/src/ttys.c0000644000175000017500000001244710117175055013755 0ustar roverrover/* * Copyright (c) 1995, Danny Gasparovski * Parts Copyright (c) 2001 Kelly "STrRedWolf" Price * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifdef FULL_BOLT #define WANT_SYS_IOCTL_H #endif #include struct ttys *ttys_unit[MAX_INTERFACES]; int slirp_forked; struct ttys * tty_attach(unit, device) int unit; char *device; { char buff[256], *bptr; struct ttys *ttyp, *ttyp_tmp, *ttyp_last = 0; struct stat stat; DEBUG_CALL("tty_attach"); DEBUG_ARG("unit = %d", unit); DEBUG_ARG("device = %lx", (long)device); if ((ttyp = (struct ttys *)malloc(sizeof(struct ttys))) == NULL) return 0; memset(ttyp, 0, sizeof(struct ttys)); ttyp->next = 0; ttyp->fd = 0; /* Default changed from -1 -RedWolf */ /* Only open the device if there is one */ if (device) { if ((ttyp->fd = open(device, O_RDWR )) < 0) { free(ttyp); return 0; /* XXXXX */ } lprint ("Opening device %s...\r\n\r\n", device); } /* Link it to the *tail* of the list XXXXX */ if (!ttys) { ttys = ttyp; } else { for (ttyp_tmp = ttys; ttyp_tmp; ttyp_tmp = ttyp_tmp->next) ttyp_last = ttyp_tmp; /* XXX More checks? */ ttyp_last->next = ttyp; } #ifdef FULL_BOLT fd_nonblock(ttyp->fd); #endif if (ttyp->fd >= 0 && isatty(ttyp->fd) && fstat(ttyp->fd, &stat) == 0) { /* Save the current permissions */ ttyp->mode = stat.st_mode; #ifdef HAVE_FCHMOD fchmod(ttyp->fd, S_IRUSR|S_IWUSR); #else chmod(ttyname(ttyp->fd), S_IRUSR|S_IWUSR); #endif } ttyp->unit = unit; #ifndef FULL_BOLT ttyp->towrite = towrite_max; #endif #ifndef FULL_BOLT ttyp->baud = DEFAULT_BAUD; ttyp->bytesps = ttyp->baud/10; #endif ttyp->lastime = curtime; ttyp->sc_xc_state = 0; ttyp->sc_rc_state = 0; /* Default is SLIP */ ttyp->proto = PROTO_SLIP; ttyp->up = 1; /* SLIP is always up */ ttyp->if_input = sl_input; ttyp->if_encap = sl_encap; ttys_unit[unit] = ttyp; /* Rawify the terminal, if applicable */ if (ttyp->fd >= 0) term_raw(ttyp); /* Config the new tty */ if ((bptr = (char *)getenv("HOME"))) sprintf(buff, "%s/.slirprc-%d", bptr, unit); else sprintf(buff, ".slirprc-%d", unit); config(buff, ttyp->unit); return ttyp; } void tty_detached(ttyp, exiting) struct ttys *ttyp; int exiting; { struct ttys *ttyp_tmp, *ttyp_last = 0; DEBUG_CALL("tty_detached"); DEBUG_ARG("ttyp = %lx", (long)ttyp); DEBUG_ARG("exiting = %d", exiting); /* First, remove ttyp from the queue */ if (ttyp == ttys) { ttys = ttys->next; } else { for (ttyp_tmp = ttys; ttyp_tmp; ttyp_tmp = ttyp_tmp->next) { if (ttyp_tmp == ttyp) break; ttyp_last = ttyp_tmp; } if (!ttyp_last) { /* XXX */ /* Can't find it *shrug* */ return; } ttyp_last->next = ttyp->next; } term_restore(ttyp); #ifdef FULL_BOLT fd_block(ttyp->fd); #endif /* Restore device mode */ if (ttyp->mode) fchmod(ttyp->fd, ttyp->mode); /* Bring the link down */ #ifdef USE_PPP /* * Call lcp_lowerdown if it's ppp */ if (ttyp->proto == PROTO_PPP) { lcp_lowerdown(ttyp->unit); phase = PHASE_DEAD; /* XXXXX */ } #endif /* * Kill the guardian, if it exists */ if (ttyp->pid) kill(ttyp->pid, SIGQUIT); /* * If this was the last tty and we're not restarting, exit */ if (!ttys && slirp_socket < 0 && !exiting) slirp_exit(0); if(ttyp->fd != 0) /* Dont close stdin, we need it on exit */ close(ttyp->fd); if (ttyp->m) m_free(ttyp->m); /* * If this was the controlling tty, call ctty_detached */ if ((ttyp->flags & TTY_CTTY) && !exiting) ctty_detached(); #ifdef USE_PPP /* Deallocate compress data */ ppp_ccp_closed(ttyp); #endif ttys_unit[ttyp->unit] = 0; /* * If you love it, set it free() ... * If it comes back, we have a memory leak */ free(ttyp); detach_time = curtime; } /* * Called when controlling tty has detached */ void ctty_detached() { int retval; DEBUG_CALL("ctty_detached"); ctty_closed = 0; /* * Song and dance to detach from ctty but not be orphaned. This * madness is because we don't want to stay attached to the old * tty (thus potentially blocking it, or getting random signals * from it), but if we detach from it with setsid(), we end up * as an "orphaned process group". As such we can't write to * another terminal, so we fork once and have the child start a * new process group, which makes the child not an orphan, but * clutters up the process table with yet a third slirp process. * Better ways to do this would be most appreciated. */ if (slirp_forked) { /* Shouldn't happen, but don't want to fork() again if it does */ return; } /* Really get detached */ if (fork()) exit(0); (void) setsid(); /* new session */ retval = fork(); if (retval < 0) return; /*shrug*/ if (retval) /* parent idles *sigh* */ snooze(); slirp_forked = 1; retval = setpgid(0, 0); /* child in new process group */ /* if (retval < 0) * return; */ /* * Nuke stdin to get off old, useless tty * (stdout and stderr were already nuked in main_init()) */ retval = open("/dev/null", O_RDWR); dup2(retval, 0); if (retval > 0) close(retval); } slirp-1.0.17/src/ttys.h0000644000175000017500000000422010115276015013744 0ustar roverrover/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifdef sc_flags #undef sc_flags #endif #ifndef INCLUDED_TERMIOS_H # ifdef HAVE_TERMIOS_H # include # else # include # endif # define INCLUDED_TERMIOS_H #endif struct ttys { int unit; /* Unit number of this ttys */ int proto; /* Protocol used */ int up; /* Is the interface up? */ int fd; /* File Descriptor */ int pid; /* PID of the "guardian", if any */ #define IF_OUTBUFFSIZE 2*2048+2 #ifdef FULL_BOLT char if_outbuff[IF_OUTBUFFSIZE]; int nbuff; int nbuff_written; #else int towrite; /* towrite for this tty */ #endif int zeros; /* Number of '0's typed */ int ones; /* Number of '1's typed */ struct mbuf *m; /* Input mbuf for this tty */ int msize; /* Size of the above */ u_char *mptr; /* Ptr to the above */ u_char esc; /* Flag to indicate the next byte is escaped */ int mbad; /* The receiving packet is bad */ int inpkt; /* We are receiving a packet */ #ifndef FULL_BOLT int baud; /* Baudrate */ int bytesps; /* Bytes per second */ #endif u_int lastime; /* for updtime() */ struct termios oldterm; /* Old termios for the tty */ mode_t mode; struct slirp_ifstats ifstats; /* Interface statistics */ u_int flags; /* Misc flags, see below */ void (*if_input) _P((struct ttys *, u_char *, int)); /* packet decapsulation and dispatch */ int (*if_encap) _P((char *, struct mbuf *, int, int, int)); /* packet encapsulation routine */ /* The following fields are for compression * XXX should put them around ifdef's */ u_int sc_flags; struct compressor *sc_rcomp; struct compressor *sc_xcomp; void *sc_rc_state; void *sc_xc_state; #if MS_DCC int dccpos; /* chat hack, see if got CLIENT string */ #endif struct ttys *next; /* Linked list */ }; extern struct ttys *ttys; #define TTY_CTTY 0x1 #ifdef USE_PPP #define TTY_PPPSTART 0x2 #endif /* SC flags */ #define SC_VJ_RESET 0x1 #define SC_DECOMP_RUN 0x2 #define SC_DC_ERROR 0x4 #define SC_DC_FERROR 0x8 #define SC_COMP_RUN 0x10 #define SC_CCP_UP 0x20 #define SC_CCP_OPEN 0x40 extern int slirp_forked; slirp-1.0.17/src/ttys.p0000644000175000017500000000017210117175060013756 0ustar roverroverstruct ttys * tty_attach _P((int, char *)); void tty_detached _P((struct ttys *, int)); void ctty_detached _P((void)); slirp-1.0.17/src/udp.c0000644000175000017500000003761410115276014013540 0ustar roverrover/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * 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. * * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include "ip_icmp.h" struct udpstat udpstat; struct socket udb; /* * UDP protocol implementation. * Per RFC 768, August, 1980. */ #ifndef COMPAT_42 int udpcksum = 1; #else int udpcksum = 0; /* XXX */ #endif struct socket *udp_last_so = &udb; void udp_init() { udb.so_next = udb.so_prev = &udb; } /* m->m_data points at ip packet header * m->m_len length ip packet * ip->ip_len length data (IPDU) */ void udp_input(m, iphlen) register struct mbuf *m; int iphlen; { register struct ip *ip; register struct udphdr *uh; /* struct mbuf *opts = 0;*/ int len; struct ip save_ip; struct socket *so; DEBUG_CALL("udp_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("iphlen = %d", iphlen); udpstat.udps_ipackets++; /* * Strip IP options, if any; should skip this, * make available to user, and use on returned packets, * but we don't yet have a way to check the checksum * with options still present. */ if(iphlen > sizeof(struct ip)) { ip_stripoptions(m, (struct mbuf *)0); iphlen = sizeof(struct ip); } /* * Get IP and UDP header together in first mbuf. */ ip = mtod(m, struct ip *); uh = (struct udphdr *)((caddr_t)ip + iphlen); /* * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ len = ntohs((u_int16_t)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len) { udpstat.udps_badlen++; goto bad; } m_adj(m, len - ip->ip_len); ip->ip_len = len; } /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ save_ip = *ip; save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ /* * Checksum extended UDP header and data. */ if (udpcksum && uh->uh_sum) { ((struct ipovly *)ip)->ih_next = 0; ((struct ipovly *)ip)->ih_prev = 0; ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; /* keep uh_sum for ICMP reply * uh->uh_sum = cksum(m, len + sizeof (struct ip)); * if (uh->uh_sum) { */ if(cksum(m, len + sizeof(struct ip))) { udpstat.udps_badsum++; goto bad; } } /* * Locate pcb for datagram. */ so = udp_last_so; if (so->so_lport != uh->uh_sport || so->so_laddr.s_addr != ip->ip_src.s_addr) { struct socket *tmp; for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { if (tmp->so_lport == uh->uh_sport && tmp->so_laddr.s_addr == ip->ip_src.s_addr) { tmp->so_faddr.s_addr = ip->ip_dst.s_addr; tmp->so_fport = uh->uh_dport; so = tmp; break; } } if (tmp == &udb) { so = NULL; } else { udpstat.udpps_pcbcachemiss++; udp_last_so = so; } } if (so == NULL) { /* * If there's no socket for this packet, * create one */ if ((so = socreate()) == NULL) goto bad; if(udp_attach(so) == -1) { DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); goto bad; } /* * Setup fields */ /* udp_last_so = so; */ so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; so->so_faddr = ip->ip_dst; /* XXX */ so->so_fport = uh->uh_dport; /* XXX */ if ((so->so_iptos = udp_tos(so)) == 0) so->so_iptos = ip->ip_tos; /* * XXXXX Here, check if it's in udpexec_list, * and if it is, do the fork_exec() etc. */ } iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_data += iphlen; /* * Now we sendto() the packet. */ if (so->so_emu) udp_emu(so, m); if(sosendto(so,m) == -1) { m->m_len += iphlen; m->m_data -= iphlen; *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); } m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ /* restore the orig mbuf packet */ m->m_len += iphlen; m->m_data -= iphlen; *ip=save_ip; so->so_m=m; /* ICMP backup */ return; bad: m_freem(m); /* if (opts) m_freem(opts); */ return; } int udp_output(so, m, addr) struct socket *so; struct mbuf *m; struct sockaddr_in *addr; { register struct udpiphdr *ui; int error = 0; DEBUG_CALL("udp_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("addr.sin_addr.s_addr = %lx", (long)addr->sin_addr.s_addr); /* * Adjust for header */ m->m_data -= sizeof(struct udpiphdr); m->m_len += sizeof(struct udpiphdr); /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) ui->ui_src.s_addr = so->so_faddr.s_addr; else ui->ui_src = addr->sin_addr; ui->ui_dst = so->so_laddr; ui->ui_sport = addr->sin_port; ui->ui_dport = so->so_lport; ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; if (udpcksum) { if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = m->m_len; ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = so->so_iptos; udpstat.udps_opackets++; error = ip_output(so, m); return (error); } int udp_attach(so) struct socket *so; { struct sockaddr_in addr; if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { /* * Here, we bind() the socket. Although not really needed * (sendto() on an unbound socket will bind it), it's done * here so that emulation of ytalk etc. don't have to do it */ addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { int lasterrno=errno; close(so->s); so->s=-1; errno=lasterrno; } else { /* success, insert in queue */ so->so_expire = curtime + SO_EXPIRE; insque(so,&udb); } } return(so->s); } void udp_detach(so) struct socket *so; { close(so->s); /* if (so->so_m) m_free(so->so_m); done by sofree */ sofree(so); } struct tos_t udptos[] = { {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ {0, 0, 0, 0} }; u_int8_t udp_tos(so) struct socket *so; { int i = 0; while(udptos[i].tos) { if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { so->so_emu = udptos[i].emu; return udptos[i].tos; } i++; } return 0; } #ifdef EMULATE_TALK #include "talkd.h" #endif /* * Here, talk/ytalk/ntalk requests must be emulated */ void udp_emu(so, m) struct socket *so; struct mbuf *m; { struct sockaddr_in addr; int addrlen = sizeof(addr); #ifdef EMULATE_TALK CTL_MSG_OLD *omsg; CTL_MSG *nmsg; char buff[sizeof(CTL_MSG)]; u_char type; struct talk_request { struct talk_request *next; struct socket *udp_so; struct socket *tcp_so; } *req; static struct talk_request *req_tbl = 0; #endif struct cu_header { char dest[8]; short family; u_short port; u_long addr; } *cu_head; switch(so->so_emu) { #ifdef EMULATE_TALK case EMU_TALK: case EMU_NTALK: /* * Talk emulation. We always change the ctl_addr to get * some answers from the daemon. When an ANNOUNCE comes, * we send LEAVE_INVITE to the local daemons. Also when a * DELETE comes, we send copies to the local daemons. */ if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; #define IS_OLD (so->so_emu == EMU_TALK) #define COPY_MSG(dest, src) { dest->type = src->type; \ dest->id_num = src->id_num; \ dest->pid = src->pid; \ dest->addr = src->addr; \ dest->ctl_addr = src->ctl_addr; \ memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) /* old_sockaddr to sockaddr_in */ if (IS_OLD) { /* old talk */ omsg = mtod(m, CTL_MSG_OLD*); nmsg = (CTL_MSG *) buff; type = omsg->type; OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); } else { /* new talk */ omsg = (CTL_MSG_OLD *) buff; nmsg = mtod(m, CTL_MSG *); type = nmsg->type; OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); } if (type == LOOK_UP) return; /* for LOOK_UP this is enough */ if (IS_OLD) { /* make a copy of the message */ COPY_MSG(nmsg, omsg); nmsg->vers = 1; nmsg->answer = 0; } else COPY_MSG(omsg, nmsg); /* * If if is an ANNOUNCE message, we go through the * request table to see if a tcp port has already * been redirected for this socket. If not, we solisten() * a new socket and add this entry to the table. * The port number of the tcp socket and our IP * are put to the addr field of the message structures. * Then a LEAVE_INVITE is sent to both local daemon * ports, 517 and 518. This is why we have two copies * of the message, one in old talk and one in new talk * format. */ if (type == ANNOUNCE) { int s; u_short temp_port; for(req = req_tbl; req; req = req->next) if (so == req->udp_so) break; /* found it */ if (!req) { /* no entry for so, create new */ req = (struct talk_request *) malloc(sizeof(struct talk_request)); req->udp_so = so; req->tcp_so = solisten(0, OTOSIN(omsg, addr)->sin_addr.s_addr, OTOSIN(omsg, addr)->sin_port, SS_FACCEPTONCE); req->next = req_tbl; req_tbl = req; } /* replace port number in addr field */ addrlen = sizeof(addr); getsockname(req->tcp_so->s, (struct sockaddr *) &addr, &addrlen); OTOSIN(omsg, addr)->sin_port = addr.sin_port; OTOSIN(omsg, addr)->sin_addr = our_addr; OTOSIN(nmsg, addr)->sin_port = addr.sin_port; OTOSIN(nmsg, addr)->sin_addr = our_addr; /* send LEAVE_INVITEs */ temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; omsg->type = nmsg->type = LEAVE_INVITE; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; addr.sin_port = htons(517); sendto(s, (char *)omsg, sizeof(*omsg), 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *) &addr, sizeof(addr)); close(s) ; omsg->type = nmsg->type = ANNOUNCE; OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; } /* * If it is a DELETE message, we send a copy to the * local daemons. Then we delete the entry corresponding * to our socket from the request table. */ if (type == DELETE) { struct talk_request *temp_req, *req_next; int s; u_short temp_port; temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; addr.sin_port = htons(517); sendto(s, (char *)omsg, sizeof(*omsg), 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *)&addr, sizeof(addr)); close(s); OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; /* delete table entry */ if (so == req_tbl->udp_so) { temp_req = req_tbl; req_tbl = req_tbl->next; free(temp_req); } else { temp_req = req_tbl; for(req = req_tbl->next; req; req = req_next) { req_next = req->next; if (so == req->udp_so) { temp_req->next = req_next; free(req); break; } else { temp_req = req; } } } } return; #endif case EMU_CUSEEME: /* * Cu-SeeMe emulation. * Hopefully the packet is more that 16 bytes long. We don't * do any other tests, just replace the address and port * fields. */ if (m->m_len >= sizeof (*cu_head)) { if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; cu_head = mtod(m, struct cu_header *); cu_head->port = addr.sin_port; cu_head->addr = (u_long) our_addr.s_addr; } return; } } struct socket * udp_listen(port, laddr, lport, flags) u_int port; u_int32_t laddr; u_int lport; int flags; { struct sockaddr_in addr; struct socket *so; int addrlen = sizeof(struct sockaddr_in), opt = 1; if ((so = socreate()) == NULL) { free(so); return NULL; } so->s = socket(AF_INET,SOCK_DGRAM,0); so->so_expire = curtime + SO_EXPIRE; insque(so,&udb); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = port; if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { udp_detach(so); return NULL; } setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); /* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = our_addr; else so->so_faddr = addr.sin_addr; so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) so->so_expire = 0; so->so_state = SS_ISFCONNECTED; return so; } slirp-1.0.17/src/udp.h0000644000175000017500000000744410115276015013544 0ustar roverrover/* * Copyright (c) 1982, 1986, 1993 * 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. * * @(#)udp.h 8.1 (Berkeley) 6/10/93 * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp */ #ifndef _UDP_H_ #define _UDP_H_ #define UDP_TTL 0x60 #define UDP_UDPDATALEN 16192 extern struct socket *udp_last_so; /* * Udp protocol header. * Per RFC 768, September, 1981. */ struct udphdr { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ }; /* * UDP kernel structures and variables. */ struct udpiphdr { struct ipovly ui_i; /* overlaid ip structure */ struct udphdr ui_u; /* udp header */ }; #define ui_next ui_i.ih_next #define ui_prev ui_i.ih_prev #define ui_x1 ui_i.ih_x1 #define ui_pr ui_i.ih_pr #define ui_len ui_i.ih_len #define ui_src ui_i.ih_src #define ui_dst ui_i.ih_dst #define ui_sport ui_u.uh_sport #define ui_dport ui_u.uh_dport #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum struct udpstat { /* input statistics: */ u_long udps_ipackets; /* total input packets */ u_long udps_hdrops; /* packet shorter than header */ u_long udps_badsum; /* checksum error */ u_long udps_badlen; /* data length larger than packet */ u_long udps_noport; /* no socket on port */ u_long udps_noportbcast; /* of above, arrived as broadcast */ u_long udps_fullsock; /* not delivered, input socket full */ u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ /* output statistics: */ u_long udps_opackets; /* total output packets */ }; /* * Names for UDP sysctl objects */ #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ #define UDPCTL_MAXID 2 extern struct udpstat udpstat; extern struct socket udb; #endif slirp-1.0.17/src/udp.p0000644000175000017500000000057610115325667013563 0ustar roverrovervoid udp_init _P((void)); void udp_input _P((register struct mbuf *, int)); int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *)); int udp_attach _P((struct socket *)); void udp_detach _P((struct socket *)); u_int8_t udp_tos _P((struct socket *)); void udp_emu _P((struct socket *, struct mbuf *)); struct socket * udp_listen _P((u_int, u_int32_t, u_int, int)); slirp-1.0.17/src/version.h0000644000175000017500000000007310433144606014433 0ustar roverrover#define SLIRP_VERSION "1.0.17" #define SLIRP_STATUS "BETA"