pax_global_header00006660000000000000000000000064144770342730014525gustar00rootroot0000000000000052 comment=3870ae88bcaee56113c0bcd257f874257e8188ba vpcs-0.8.3/000077500000000000000000000000001447703427300125105ustar00rootroot00000000000000vpcs-0.8.3/.circleci/000077500000000000000000000000001447703427300143435ustar00rootroot00000000000000vpcs-0.8.3/.circleci/config.yml000066400000000000000000000024431447703427300163360ustar00rootroot00000000000000# iOS CircleCI 2.1 configuration file version: 2.1 jobs: build: macos: xcode: "12.5.1" steps: - checkout - run: name: Set timezone and check current datetime command: | sudo systemsetup -settimezone Europe/Warsaw echo "Today is $(date +"%Y-%m-%d %T")" - run: name: Install gcc command: | HOMEBREW_NO_AUTO_UPDATE=1 brew install gcc - run: name: Build vpcs command: | cd src && ./mk.sh amd64 - run: name: Gather artifacts command: | mkdir artifacts mv src/vpcs artifacts/vpcs-osx - store_artifacts: path: artifacts destination: artifacts - run: name: Upload nightly builds to SF command: | if [ -n "${RUN_NIGHTLY_BUILD}" ]; then ssh-keyscan -H frs.sourceforge.net >> ~/.ssh/known_hosts echo "mkdir \"/home/frs/project/gns-3/Nightly Builds/$(date +"%Y-%m-%d")/\"" | sftp gns3build@frs.sourceforge.net echo -ne " cd \"/home/frs/project/gns-3/Nightly Builds/$(date +"%Y-%m-%d")/\" put \"artifacts/vpcs-osx\" " | sftp gns3build@frs.sourceforge.net fi vpcs-0.8.3/.github/000077500000000000000000000000001447703427300140505ustar00rootroot00000000000000vpcs-0.8.3/.github/workflows/000077500000000000000000000000001447703427300161055ustar00rootroot00000000000000vpcs-0.8.3/.github/workflows/codeql.yml000066400000000000000000000043501447703427300201010ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ "master" ] pull_request: # The branches below must be a subset of the branches above branches: [ "master" ] schedule: - cron: '40 6 * * 1' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'cpp' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Use only 'java' to analyze code written in Java, Kotlin or both # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - run: | echo "Run, Build Application using script" cd src && ./mk.sh amd64 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" vpcs-0.8.3/.gitignore000066400000000000000000000000201447703427300144700ustar00rootroot00000000000000*.o *.hist vpcs vpcs-0.8.3/.whitesource000066400000000000000000000006631447703427300150570ustar00rootroot00000000000000{ "scanSettings": { "configMode": "AUTO", "configExternalURL": "", "projectToken": "", "baseBranches": [] }, "checkRunSettings": { "vulnerableCheckRunConclusionLevel": "failure", "displayMode": "diff", "useMendCheckNames": true }, "issueSettings": { "minSeverityLevel": "LOW", "issueType": "DEPENDENCY" }, "remediateSettings": { "workflowRules": { "enabled": true } } }vpcs-0.8.3/COPYING000066400000000000000000000024671447703427300135540ustar00rootroot00000000000000Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. vpcs-0.8.3/INSTALL000066400000000000000000000002221447703427300135350ustar00rootroot00000000000000run src/mk.sh to compile Options: [i386 | amd64 | 32 | 64] [clean] i386 or 32, generate code for 32bit amd64 or 64, generate code for 64bit vpcs-0.8.3/README.md000066400000000000000000000004231447703427300137660ustar00rootroot00000000000000# VPCS This is a continuation of VPCS, based on the last development version and improved with patches wrote by various people from the community. The original VPCS code, which is unfortunately not maintained anymore, can be viewed on https://sourceforge.net/p/vpcs/code/ vpcs-0.8.3/SECURITY.md000066400000000000000000000004221447703427300142770ustar00rootroot00000000000000# Security Policy ## Reporting a Vulnerability Please use GitHub's report a vulnerability feature. More information can be found in https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability vpcs-0.8.3/man/000077500000000000000000000000001447703427300132635ustar00rootroot00000000000000vpcs-0.8.3/man/vpcs.1000066400000000000000000000513221447703427300143230ustar00rootroot00000000000000 .TH VPCS "1" "2013-12-16" "0.8" "Virtual PC Simulator" ./ Last revision: 2015-10-04 16:07:00 .hy 0 .if n .ad l .SH NAME vpcs \- Virtual PC Simulator .SH SYNOPSIS .B vpcs [\fIOPTIONS\fR] [\fIFILENAME\fR] .SH DESCRIPTION .PP VPCS provides a command line interface to nine simulated virtual PCs. You can ping/trace route from/to them, or ping/trace route other hosts/routers from the virtual PCs, making it an ideal study tool when you simulate Cisco or Juniper routers in a Dynamips or GNS3 environment. .PP Virtual PCs are able to generate and respond to ICMP (ping), TCP and UDP packets delivered to the application via a UDP pipe or Unix tap interface. If \fIscriptfile\fR is specified, then \fBvpcs \fRreads the file on start-up and executes the commands in the scriptfile. \fIscriptfile\fR must be in \fBvpcs script file format\fR. .PP \fBvpcs\fR listens for messages on nine consecutive UDP ports and sends messages on nine consecutive UDP ports. By the default, \fBvpcs\fR listens on UDP ports 20000 to 20008 and sends messages on UDP ports 30000 to 30008. Each UDP port pair (20000/30000, 20001/30001...20008/30008) represents a virtual PC. Virtual PCs are numbered 1 to 9. .SH OPTIONS .TP \fB-h\fR, \fB--help\fR Print the command line options and exit .TP \fB-v\fR Print the version information and exit .TP \fB-R\fR Disable the relay function .TP [\fB-i\fR] \fInum\fR Start \fBvpcs\fR with \fInum\fR vitrual PCs, maximum 9. If omitted \fBvpcs\fR will start with 9 virtual PCs. If \fInum\fR is 1, such as when GNS3 v1.x spawns PCs, commands that reference other PCs will have restricted options and the prompt will not display the PC number. .TP \fB-p\fR \fIport\fR Run \fBvpcs\fR as a daemon process listening on TCP port specified by \fIport\fR. As a daemon process, \fBvpcs\fR does not present a command line interface to the user, but the command line interface can be accessed remotely using a TCP stream application such as \fItelnet\fR or netcat (\fInc\fR). Once the daemon has been started, there is no internal mechanism for terminating the program, and the program must be terminated by sending a system signal 9, typically by using the command \fBkill \-9 PID\fR (where PID is the process id of the \fBvpcs \fRinstance) .TP \fB-m\fR \fInum\fR \fBvpcs\fR uses 9 consecutive MAC addresses for the 9 \fIvpcs\fR stating at 00:50:79:66:68:00 by default. The \fB-m\fR option adds \fInum\fR to the last byte of the base MAC address. Should any increment cause the last byte exceed 0xFF during this process, it will increment to 0x00. .TP [\fB-r\fR] \fIFILENAME\fR If \fIFILENAME\fR is specified, then \fBvpcs\fR reads the file on start-up and executes the commands in the \fIFILENAME\fR. \fIFILENAME \fR must be in \fBvpcs\fR script file format. By default, if a file named \fBstartup.vpc\fR exists in the directory where the \fBvpcs\fR program was started, it will be read and executed when \fBvpcs\fR starts. The \fB-r\fR option is optional if \fIFILENAME\fR is the last parameter. .TP \fB-e\fR On systems that support the \fB/dev/tapx\fR interface (Unix/Linux), run \fBvpcs\fR in tap mode rather than UDP mode. In tap mode, IP packets are sent and received via /dev/tapx interfaces rather than via UDP streams. Typically /dev/tapx interfaces are only available to the root user, meaning \fBvpcs\fR would also be required to be run by the root user (\fBsudo vpcs \-e\fR) to use tap mode. .TP [\fB-u\fR] This option is the default and not necessary, but included to contrast with the \fB-e\fR option. By default, \fBvpcs\fR sends and receives IP packets to and from specified UDP ports. \fBvpcs\fR listens on UDP port 20000 and sends to port 127.0.0.1:30000 by default. The listening and sending ports can be manipulated using the \fB-s\fR, \fB-c\fR and \fB-t\fR options. .SS "UDP Mode Options" .TP \fB-s\fR \fIport\fR \fIport\fR specifies the base port number that \fBvpcs\fR uses to listen for messages. By default \fBvpcs\fR listens for messages on UDP ports \fI20000\fR to \fI20008\fR. By changing the base port that \fBvpcs\fR listens to using the \fB-s\fR option causes nine consecutive UDP ports to be used starting at the port specified by \fIport\fR. .TP \fB-t\fR \fIip\fR \fBvpcs\fR streams packets to nine UDP ports commencing at \fI127.0.0.1:30000\fR by default. The \fB-t\fR option allows you to stream packets to a remote host as specified by IPv4 address \fIip\fR. Typically the remote host will be running dynamips with a cloud connection configured to link to this host’s IP address. .TP \fB-c\fR \fIport\fR \fBvpcs\fR streams packets to nine UDP ports commencing at \fI127.0.0.1:30000\fR. The \fB-c\fR option allows you to stream packets to a different set of nine ports commencing at the base port number specified by \fIport\fR. .SS "TAP Mode Options" .TP \fB-d\fR \fIdevice\fR Device name, works only when \fB-i\fR is set to 1 .SS "Hypervisor Mode Option" .TP \fB-H\fR \fIport\fR Run as a hypervisor, listening on TCP port specified by \fIport\fR. In the hypervisor mode, you can connect this control \fIport\fR with \fItelnet\fR, start or stop an instance of \fBvpcs\fR. .SH EXAMPLES .SS "No command line options" If you start the \fBvpcs\fR with no arguments, \fIvpcs\fR will start and look for the script \fBstartup.vpc\fR in the current directory. If it exists, it will run the script. This is the normal way of running the \fIvpcs\fR. It is simply evoked from the command line like this: .PP \fBvpcs\fR .PP .SS "Starting vpcs with an alternative startup file" To start \fBvpcs\fR with a startup script file called say \fBalternate.vpc\fR, use the file name as an argument to the \fBvpcs\fR command: .PP \fBvpcs alternate.vpc\fR .SS "Running more than nine Virtual PCs" Suppose you needed more than nine Virtual PCs, so you want to run a second instance of \fBvpcs\fR on your local host. You would have to consider: .PP 1. The VPCs MAC addresses for the second instance would need to be different, .PP 2. The "local" or listening UDP port numbers for the second instance would have to differ from the first instance. .PP 3. The remote UDP port numbers for the second instance would have to differ from the first instance. .PP Since the default local listening port is 20000, and the default remote port is 30000, you would want to start \fBvpcs\fR with a local listening port of 20009 (or greater) and remote port of 30009 (or greater) . You would also want the base MAC address to be offset by at least nine to avoid any clashes. In this case you would use the command: .PP \fBvpcs \-s 20009 \-c 30009 \-m 9\fR .PP A far better way to run more than nine Virtual PCs is to use the \fBHypervisor \fRmode. In Hypervisor mode, \fBvpcs \fRwill automatically take care of incrementing MAC addresses and UDP port numbers so here is no clash. .SH BASE INTERFACE \fBvpcs\fR presents the user with a command line interface (unless daemon mode has been invoked by the \fB-p\fR option). The interface prompt indicates which of the 9 virtual PCs currently has focus by indicating the VPC number in brackets. Eg.: .br VPCS[1]> .br Here the digit 1 inside the brackets indicates that VPC 1 has focus, and any traffic generated will be sent from VPC 1, and basic \fBshow\fR commands will relate to VPC 1. .br .br Note: When started with the \fB-i 1\fR option, VPC 1 always has focus, and the prompt does NOT display the VPC number in brackets. Eg.: .br VPCS> .br .br .SS Basic commands supported are: .TP 7 \fB?\fR Print help .TP \fIdigit\fR Switch to the VPC\fIdigit\fR. \fIdigit\fR range 1 to 9 .TP \fBarp\fR [\fIdigit\fR|\fBall\fR] Shortcut for: \fBshow arp\fR. Show arp table for VPC \fIdigit\fR (default this VPC) or all VPCs .TP \fBclear ip\fR|\fBipv6\fR|\fBarp\fR|\fBneighbor\fR|\fBhist\fR Clear IPv4/IPv6, arp/neighbor cache, command history .TP \fBdhcp\fR [\fIOPTION\fR] Shortcut for: \fBip dhcp\fR. Attempt to obtain IPv4 address, mask, gateway and DNS via DHCP .TP \fBdisconnect\fR Exit the telnet session (daemon mode) .TP \fBecho\fR \fITEXT\fR Display \fITEXT\fR in output .TP \fBhelp\fR Print help .TP \fBhistory\fR Shortcut for: \fBshow history\fR. List the command history .TP \fBip\fR \fIARG\fR ... [\fIOPTION\fR] Configure the current VPC's IP settings .br .TP ARG ...: \fIaddress\fR [\fImask\fR] [\fIgateway\fR] .br \fIaddress\fR [\fIgateway\fR] [\fImask\fR] .TP 10 .ti 10 Set the VPC's ip, default gateway ip and network mask. Default IPv4 mask is /24, IPv6 is /64. Example: .br \fBip 10.1.1.70/26 10.1.1.65\fR sets the VPC's ip to 10.1.1.70, the gateway to 10.1.1.65, the netmask to 255.255.255.192. .br In tap mode, the ip of the tapx is the maximum host ID of the subnet. In the example above the tapx ip would be 10.1.1.126 .br mask may be written as /26, 26 or 255.255.255.192 .TP \fB auto Attempt to obtain IPv6 address, mask and gateway using SLAAC .TP \fB dhcp\fR [\fIOPTION\fR] Attempt to obtain IPv4 address, mask, gateway, DNS via DHCP .br OPTION: \fB\-d\fR Show DHCP packet decode \fB\-r\fR Renew DHCP lease \fB\-x\fR Release DHCP lease .TP \fBdns\fI ip\fR Set DNS server \fIip\fR, delete if \fIip\fR is '0' .TP \fBdomain\fI NAME Set local domain name to \fINAME\fR. The domain name will be added to host names when using commands that support names. Example: If the domain name was set to \fBexample.com\fR, then a command of \fBping abcd\fR would cause the VPCS to attempt to resolve the name \fBabcd.example.com\fR. .TP 7 \fBload\fR [\fIFILENAME\fR[.vpc]] Load the configuration/scriptfile from the file \fIFILENAME\fR. If \fIFILENAME\fR ends with '.vpc', then the '.vpc' can be omitted. If \fIFILENAME\fR is omitted then \fIstartup.vpc\fR will be loaded if it exists. When the file is loaded, each line of the file is executed as a VPCS command. If the state of the echo flag is on, the command will be echoed to the console before execution, except: .TP 9 * If the command is prefixed with a '@' symbol (eg \fB@set echo color red\fR); .TP 9 * If the command is an \fBecho\fR command; .TP 9 * If the command is a \fBsleep\fR command .br Note: The command \fBsleep 0\fR will be echoed if the echo flag is on .br See \fBset echo\fR and \fBshow echo\fR Note: Press Ctrl+C to interrupt the running script. .TP 7 \fBping\fR \fIHOST\fR [\fIOPTION\fR ...] Ping the network \fIHOST\fR with ICMP (default) or TCP/UDP. \fIHOST\fR can be an ip address or name OPTIONS: \fB-1\fR ICMP mode, default \fB-2\fR UDP mode \fB-3\fR TCP mode \fB-c \fIcount\fR Packet count, default 5 \fB-D\fR Set the Don't Fragment bit \fB-f \fIFLAG\fR Tcp header FLAG |\fBC\fR|\fBE\fR|\fBU\fR|\fBA\fR|\fBP\fR|\fBR\fR|\fBS\fR|\fBF\fR| bits |7 6 5 4 3 2 1 0| \fB-i \fIms\fR Wait \fIms\fR milliseconds between sending each packet \fB-l \fIsize\fR Data size \fB-P \fIprotocol\fR Use IP \fIprotocol\fR in ping packets \fB1\fR - ICMP (default), \fB17\fR - UDP, \fB6\fR - TCP \fB-p \fIport\fR Destination port \fB-s \fIport\fR Source port \fB-T \fIttl\fR Set \fIttl\fR, default 64 \fB-t \fR Send packets until interrupted by Ctrl+C \fB-w \fIms\fR Wait \fIms\fR milliseconds to receive the response Notes: 1. Using names requires DNS to be set. 2. Use Ctrl+C to stop the command. .TP \fBquit\fR Quit program .TP \fBrelay\fR \FIARG\FR ... Configure packet relay between UDP ports. The relay command allows the VPCS to become a virtual patch panel where connections can be dynamically changed using the \fBrelay\fR command. There are three steps required to use VPCS as a virtual patch panel. .TP 10 1. A \fBrelay hub\fR port must be defined using the \fBrelay port \fIport\fR command. .TP 10 2. Remote NIO_UDP connections (cloud connections in GNS3) use this \fBhub \fBport\fR as the remote port, ensuring each NIO_UDP connection has a unique \fBlocal\fR port. (The local \fBport\fR numbers will be used to 'patch' the connection). VPC instances can be directed to use this hub port as their remote port using the command \fBset rport \fIport\fR. .TP 10 3. The 'patching' is completed using the command: .br \fBrelay add [\fIip1\fB:]\fIport1 \fB[\fIip2\fB:]\fIport2\fR, where \fIport1\fR and \fIport2\fR are the local port numbers used in step 2. .TP 12 ARG: .TP 35 \fBadd \fR[\fIip1\fR:]\fIport1 \fR[\fIip2\fR:]\fIport2\fR Relay the packets between \fIip1\fR and \fIip2\fR .TP 35 \fBdel \fR[\fIip1\fR:]\fIport1 \fR[\fIip2\fR:]\fIport2\fR Delete the relay rule .TP 35 \fBdel \fIid\fR Delete the relay rule .TP 35 \fBdump \fR[\fBon\fR|\fBoff\fR] Dump relay packets to file .TP 35 \fBport \fIport\fR Set relay hub port .TP 35 \fBshow\fR Show the relay rules Note: \fIip1\fR and i\fIp2\fR are 127.0.0.1 by default .TP 7 \fBrlogin\fR [\fIip\fR] \fIport\fR Telnet to \fIport\fr on host at \fIip\fR (relative to host PC). To attach to the console of a virtual router running on port 2000 of this host PC, use \fBrlogin 2000\fR .br To telnet to the port 2004 of a remote host 10.1.1.1, use \fBrlogin 10.1.1.1 2004 .TP \fBsave\fR [\fIFILENAME\fR[.vpc]] Save the configuration to the scriptfile \fIFILENAME.vpc\fR. If there is no '.' in \fIFILENAME\fR then a '.vpc' extension is added. If \fIFILENAME\fR is omitted then the configuration will be saved to \fIstartup.vpc\fR .TP \fBset\fR \fIARG\fR ... Set hostname, connection port, ipfrag state, dump options and echo options .TP 12 ARG: .TP 18 \fBdump\fI FLAG\fR [[\fIFLAG\fR]...] Set the packet dump flags for this VPC. .PP FLAG: .TP 18 \fIall\fR All the packets including incoming. must use [detail|mac|raw] as well as 'all' .TP \fBdetail\fR Print protocol .TP \fBfile\fR Dump packets to file vpcs[id]_yyyymmddHHMMSS.pcap' .TP \fBoff\fR Clear all the flags .TP \fBmac\fR Print hardware MAC address .TP \fBraw\fR Print the first 40 bytes .TP \fBecho on|off|[color \fBclear|\fIFGCOLOR\fR [\fIBGCOLOR\fR]] Sets the state of the echo flag used when executing script files, or sets the color of text to \fIFGCOLOR\fR with optional \fIBGCOLOR\fR. \fBset echo color clear\fR resets colors to their defaults. .br Color list: black, red, green, yellow, blue, magenta, cyan, white .TP \fBlport \fIport\fR Local port .TP \fBmtu \fIvalue\fR Set the size of the maximum transmission unit of the interface .TP \fBpcname \fINAME\fR Set the hostname of the current VPC to \fINAME\fR .TP \fBrport \fIport\fR Remote peer port .TP \fBrhost \fIip\fR Remote peer host IPv4 address .TP 7 \fBshow\fR [\fIARG\fR ...] Show information for ARG .TP 18 ARG: .TP \fBarp\fR [\fIdigit\fR|\fBall\fR] Show arp table for VPC digit or all VPCs .TP \fBdump\fR [\fIdigit\fR|\fBall\fR] Show dump flags for VPC digit or all VPCs .TP \fBecho Show the status of the echo flag. See set echo ? .TP \fBhistory List the command history .TP \fBip \fR[\fIdigit\fR|\fBall\fR] Show IPv4 details for VPC digit or all VPCs. Shows VPC Name, IP address, mask, gateway, DNS, MAC, lport, rhost:rport and MTU .TP \fBipv6 \fR[\fIdigit\fR|\fBall\fR] Show IPv6 details for VPC digit or all VPCs. Shows VPC Name, IPv6 addresses/mask, gateway, MAC, lport, rhost:rport and MTU .TP \fBversion Show the version information Notes: .br 1. If no parameter is given, the key information of all VPCs will be displayed .br 2. If no parameter is given for arp/dump/ip/ipv6 information for the current VPC will be displayed. .TP 7 \fBsleep\fR [\fIseconds\fR] [\fItext\fR] Print \fItext\fR and pause execution of script for \fItime\fR seconds. If \fIseconds\fR is zero or missing, pause until a key is pressed. Default text when no parameters given: 'Press any key to continue' .TP \fBtrace\fI HOST\fR [\fIOPTION\fR ...] Print the path packets take to the network \fI HOST\fR. \fI HOST\fR can be an ip address or name. .TP 18 OPTIONS: .TP \fB-P \fIprotocol Use IP \fIprotocol\fR in trace packets \fB1\fR - icmp, \fB17\fR - udp (default), \fB6\fR - tcp .TP \fB-m \fIttl Maximum \fIttl\fR, default 8 .PP Notes: 1. Using names requires DNS to be set. 2. Use Ctrl+C to stop the command. .TP 7 \fBversion\fR Shortcut for: \fBshow version\fR .TP \fBwrite\fR [\fIFILENAME\fR[.vpc]] Do the same as \fBsave\fR .SS "VPCS script file format" Any text file consisting of valid vpcs commands can be used as a vpcs script file. Lines in the file beginning with the \fB#\fR character will be treated as comments and ignored. As the script is being executed, the VPCS will either display each command immediately before it is executed or not depending on the state of the \fBecho flag\fR. The \fB@\fR character can also be used to supress command echoing. Commands pre-pended by the \fB@\fR character are not echoed. The \fBecho\fR and \fBsleep\fR commands are never echoed except the \fBsleep 0\fR command which is always echoed. Command files can make use of the \fBecho\fR and \fBsleep\fR commands to create some form of interactive script. Script file exececution can be aborted at any time by pressing Ctrl+c. This means that the \fBping HOST \-t\fR command (which must be terimated by Ctrl+c) is not useful in \fBvpcs \fRscript files. .SH HYPERVISOR INTERFACE .PP When \fBvpcs \fRis started with the \fB-H \fIport \fRoption, \fBvpcs \fRstarts in \fBhypervisor \fRmode as a daemon process. .PP To access the \fBvpcs \fRhypervisor interface, you need to start a telnet session to the \fIport \fRnumber you specified with the \fB-H \fRoption. If for example you started \fBvpcs \fRwith a command of \fBvpcs -H 20000\fR, then you would typically open a telnet session to port \fI20000 \fR on your \fIlocalhost \fR IP address (\fI127.0.0.1\fR). .PP In this mode, an alternative interface is presented to allow the user to create and kill multiple \fBvpcs \fRsessions. These sessions are always run as a daemon process and must be accessed via either an external telnet application, or by using the \fBtelnet \fRor \fBrlogin \fR command within the \fBvpcs \fRhypervisor session. .TP 25 In \fBhypervisor \fR mode, the commands supported are: .TP \fBhelp | ?\fR Print help .TP \fBdisconnect\fR Exit the telnet session .TP \fBlist\fR List \fBvpcs\fR process and ids .TP \fBquit\fR [-f] Stop all \fBvpcs\fR processes and hypervisor, \fI-f\fR force quit without prompting .TP \fBstop \fIid\fR Stop \fBvpcs\fR process number \fIid .TP \fBrlogin [\fIip\fB] \fIport\fR Same as telnet .TP \fBtelnet [\fIip\fB] \fIport\fR Telnet to \fIport\fR at \fIip\fB (default 127.0.0.1) .TP \fBvpcs\fR [parameters] Start \fBvpcs\fR daemon with parameters. .PP A typical \fBhypervisor \fRsession might run something like this: .PP ------------------------------------------------------- .br ~$ \fBvpcs -H 20000\fR .br ~$ \fBtelnet 127.0.0.1 20000\fR .br Trying 127.0.0.1... .br Connected to localhost. .br Escape character is '^]'. .br HV > \fBvpcs\fR .br 100-VPCS started with -p \fI20001\fR -s 20000 -c 30000 .br HV > \fBrlogin \fI20001\fR .br .br Connect 127.0.0.1:20001, press Ctrl+X to quit .br NOTES: you will be back to the starting point, NOT THE LAST, .br if using Ctrl+X to quit. Welcome to Virtual PC Simulator, \fR\.\.\. \.\.\. .br VPCS[1] \fBdisconnect\fR .br Good-bye .br Disconnected from 127.0.0.1:20001 .br HV > .br ------------------------------------------------------- .PP Note that when the \fBvpcs \fRinstance was initiated from within the \fBhypervisor \fRinterface, it spawned a \fBvpcs \fRdaemon process listening on TCP port \fI20001\fR. To access that process, the \fBrlogin \fRcommand was used to port \fI20001\fR initiating a session with that instance. However, you could have just as easily started another independent telnet session in another shell instance to \fI127.0.0.1 20001\fR. .PP Also note that once you have finished with the \fbvpcs \fRsession, you can exit either using the \fBdisconnect \fRcommand, or use the key combination of Ctrl+X. If you have nested \fBrlogin \fRsessions, Ctrl+X will return you to the hypervisor, \fBdisconnect \fRwill take you back one level in the nesting. .SH BUGS IPv6 implementation is a basic implementation that is not fully implemented. .PP The \fBping HOST \-t\fR command (which must be terminated by Ctrl+c) can not be used in \fBvpcs \fRscript files because when Ctrl+c is pressed to stop the ping, it also aborts the script file execution. .PP Please send problems, bugs, questions, desirable enhancements, patches etc to the author. .SH AUTHOR Paul Meng .br Documentation by Chris Welsh .SH COPYRIGHT VPCS is free software, distributed under the terms of the "BSD" licence. .br Source code and license can be found at vpcs.sf.net. .br For more information, please visit wiki.freecode.com.cn. vpcs-0.8.3/man/vpcs.pdf000066400000000000000000000316551447703427300147430ustar00rootroot00000000000000%PDF-1.4 %쏢 5 0 obj <> stream xZr8}Wm- &xT{TMyIx /+ !v6y-@tӍ|'.eſӿYur'.?~d'5<#+z4B~:q:q͂X%1 X/sX8e7\t% CPdR%d OMXe~ ;_~\|4L|#~m\+d~q۬'?ȥ. !a%hŵ)v]&qOFnė̕Rw]meSZ'm 0J(\MYWbngPHc/_U"+z]op\˼IJ:'۲.HYEw`fR㧽ɣFOE80X80Il lC嚴meb)uL@ARrqg%YQޜ'}[dE~6UH2]= XvÒ V4aDcUPʖcXeb)x|jN5ܝ]'eM*V[xA4]4𘆱AA쇢<OKdZL ^,a.' UG滞i FobbMܯQWq ]n%wL0[t~^ *Npj5[C~U x.<#}|aAk,_t ]f=ᛝ5N(|{[ "+Z *`?,>\2(R 'Ja}$Ecu[ Q1 t.y<.scI~:OZ\>rXн MxR)W 1{y䫹+߁r$]wܮ+|`ތ#|D;dd0ΐ-AW'@xAU%xp7/S#"~BTIڗWxYnڦ=FMAahRjkY^c͵ c>Z0'# %yZT qON >V}IUvgtځe,2dC1Fh \k9]*㙑V! ^Mnp'GcUDwB $&=HOoPΠ! U-۫tM=1;~z2Ca؏* X*RP:/#jV0n\BG>iY{Wt@B(jT'`D!˾=|X5HrV3>н*.U\@ dEEK] o#)7 J_Ȳ?ru&@<#$-sQ\a'$q3b%21zS4 jGs⽎Ts h6<9IUV <0CD$B)Jzu߅U.E;nF?ad<\F^2sU`#2湝ŁBm9</L;M{}УD57*Lf7%͸\ seӍVx:C*R$AјS9+ ]_%؉LBiRϮW c}/0+!N5r_qed`2J(o< ilMa@"ҠJ88L;T3: EuYL[R59HOQ4jo~\!8iĎ\U> kA:x`:d5Qo}eF/kxdn? />Ѭ:=ZQH^np` :8Lye9s Ј؃oJ 5;' w(SYB\!!@il{I{3ox ~rDc{oe\1>5r#N'8g \6, iVPYt#hxdt2Bendstream endobj 6 0 obj 3203 endobj 14 0 obj <> stream xXݎ۸S\"lMlo DՑ%$wȫ{Ii&EML|ħ[,'_~ɏD(kX $ z`1>\~%\}, Nc^kr[u>rŢq˿X1 ]T5;6MܓÇaGrR$E4~?v$CKyî  ɺX!Ix%|3&sYE^Yv)LhXLSfUcS#m7L&Cѫc8AY;Na,qꉡG7!B [z~/Ö',4V S* Cd#Z+ډs,7I/f%iFw8p Qk=VP|? `䤬SHi{[щf HU$ wy>渿>RZ]xwIT?c[H|1ebiW!38n nKA,(Q˜`uܼU9G]X2XyU!4h CkJTr)Iv=iLN;ѐUE17Gu}x>ێ͜Y~;6Ӝ@e?zn)O Td6YHK|P|x^_48"dfg zBw,4SƑu!W+U`WL~䉬IVJl!ȧ}U1Xێ wL3[U#O+2d|Omw6D4Z1o[eHd<#?+RZ?\EﭱB~hnɰX~F[\c|4၍7^E^O B>h&XFMԑ[o#LcMFgKuYɡݫĺ%QW^XzhD`z5k@(Ec[ %(&+)Q8?%hO N>B0&5"m=rܬ &Me&5Ug@3&hA,eG4\::0 pHJ #a^{- Ocnq 'N݄,=4QFLewP?,/Z"zQB=3ldϼ"}+-W!FhrӸQJӘCGWurR.}F䠦d* |t௭K PǓ)C{KG֒[|#§XnDma 6U)WhUR<%k5̼=yqf:> stream xYێF}W4v6  yF)(G7+ǭj6MJ 8ɮ9:_I1;fW>93f_fL<$8#?l<̺o-;d3ZԳ\yVG}f, \`፭TMd$$kӨ).c0mdE Ãޢ1_d SZ47_9z/]]ja ead,TuJQ;ek75i5cID"ˢ|O$$^=!\<q yM~#@w$od>ɮofUI˛V/5r>I<6yŅ4@$}Sg*a.Nv5Ǩ!SQ!,B=c̀Q(PQEP=kL<B|TlӦ3I|,:5m$`>XGqx^؃Oº8QtH,c>x<.&×u[EADv; {(HW`yZN(ע`ߍQNYI7V|S"TQ~P?x%-K[#$u#D `@ՁXb:?1iO|6T*}|up(H4^o*I҉\,,Q*23Nz=ض00mipm˃TKܮNWUΓqWT$#3(1<+КgswGv&=mlX$* **T y#&~_a_8%y~&teZ`x 7iD9Rg@&cQ|u1HΛGoEȗŨv =yԦ ̷ 5w \SM 3< PEY/w/pc hFr}bYahs{9Zv8db`I nE{Viqv\:U:)䋎cFe>)T4ִH>"ϧ}5` f^ኩiAu2hQq0>̩l_ u9., #hLĉ^;J荽SeyXn2FSoHalǢxoH!x,pxcg}q^dd]`a;%gnYO G~hWMO{F%P} "({:ΤO *82apql"ܪs^!ñ,h`%_\h+\-e,4ߕQX0nᅡh> 鑝t6k!  ^s)i`ࢳ/.*";! `6ݰݯP[F5_CTQ su[Q쉈bX(Ǖ cM"2 MӸKrx/m]:~t'z1 Pq}:0>FFuySqG] {RNib6FmEVE8Pճ9W<;u/V|8!Â"H۸e3oz[ž@@w`yUw][+7':~c E9[ 7ֈ+OF`%Alov(H`dK 0-/lQ1XZz%{uoY WI&p ^u nE\{hS$ӄk5Ulm@~Kr[v}S+UW^բ^VkWCx!ضXYy-80*MTMjeC yO,4JO´[%I&aU`%ɅِrG]%^/><~ёB.v*,@R]B_h ԇyY`_u<[glf?ß󃟍endstream endobj 20 0 obj 2374 endobj 24 0 obj <> stream xmUn6}W\K%4fIL; ZSNhjH?W{Iv~e^,W@ j?ӷg?ݦ3 ÌCD db;0HHz$A ~}[,/X5YL0A[Yc9ICZ+o}{ϳ< I{Kv/R !l ;Yu}+Ro6Pɳ8NJ %w1aPƄNLFFY2n^H^ `3ٍ%y ]#FX].7WΜ `b+8'Y|%2z| %82y0NUSik \84F%HO`0L%8B`K.@EA p"yz[TcZ"h5B/`vaǟU׶p7DK#@e>z?F<2Gk9)܂$Ll3aA_77TUR1\Uq5& kZ1tjEQH~6-&Y.{i0Nac\3kOŹ|LSOv[m{ܵ[A(sRʲ88X=FxݺwRB"#S mvmv#vv1(k4¶ŌvY'%V:ȐKqlR|'l{}];Q]@]?ءmOL"&e'8i@QQF1IRDA@Y4 l#X0??Xendstream endobj 25 0 obj 1030 endobj 4 0 obj <> /Contents 5 0 R >> endobj 13 0 obj <> /Contents 14 0 R >> endobj 18 0 obj <> /Contents 19 0 R >> endobj 23 0 obj <> /Contents 24 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 13 0 R 18 0 R 23 0 R ] /Count 4 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 11 0 obj <> endobj 12 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> endobj 21 0 obj <> endobj 22 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 10 0 obj <> endobj 28 0 obj <> endobj 9 0 obj <> endobj 29 0 obj <> endobj 8 0 obj <> endobj 30 0 obj <> endobj 31 0 obj <>stream 2014-06-30T12:14:34+08:00 2014-06-30T12:14:34+08:00 groff version 1.22.2 Untitled endstream endobj 2 0 obj <>endobj xref 0 32 0000000000 65535 f 0000010008 00000 n 0000012281 00000 n 0000009928 00000 n 0000009282 00000 n 0000000015 00000 n 0000003288 00000 n 0000010073 00000 n 0000010710 00000 n 0000010563 00000 n 0000010423 00000 n 0000010114 00000 n 0000010144 00000 n 0000009442 00000 n 0000003308 00000 n 0000005671 00000 n 0000010194 00000 n 0000010224 00000 n 0000009604 00000 n 0000005692 00000 n 0000008138 00000 n 0000010274 00000 n 0000010304 00000 n 0000009766 00000 n 0000008159 00000 n 0000009261 00000 n 0000010343 00000 n 0000010373 00000 n 0000010507 00000 n 0000010644 00000 n 0000010792 00000 n 0000010858 00000 n trailer << /Size 32 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 12435 %%EOF vpcs-0.8.3/readme.txt000066400000000000000000000123531447703427300145120ustar00rootroot00000000000000 Welcome to Virtual PC Simulator, Ver 0.8. VPCS is free software, distributed under the terms of the "BSD" licence. Source code and license can be found at vpcs.sf.net. For more information, please visit wiki.freecode.com.cn. The VPCS can simulate up to 9 PCs. You can ping/traceroute them, or ping/traceroute the other hosts/routers from the VPCS when you study the Cisco routers in the dynamips. VPCS is not the traditional PC, it is just a program running on the Linux, Windows or OS X(need more testing), and only few network commands can be used in it. But VPCS can give you a big hand when you study the Cisco devices in the Dynamips. VPCS can replace the routers or VMware boxes which are used as PCs in the dynamips network. Now, VPCS can be run in udp or ether mode. In the udp mode, VPCS sends or receives the packets via udp. In the ether mode, via /dev/tap, not support on the Windows. When VPCS started, it listens the ports from 20000 to 20008 and waits the dynamips to connect, and sends the packets to the ports from 30000 to 30008 which should be listened by the dynamips. VPCS will look for the file named 'startup.vpc' in the current directory, and execute the commands in it if you are not set the startup file from the command line. All the commands in the startup file are the internal commands of the VPCS. The line started with '#' or '!' will be discarded. usage: vpcs [OPTIONS] [FILENAME] OPTIONS: -h print this help then exit -v print version information then exit -i num number of vpc instances to start (default is 9) -p port run as a daemon listening on the tcp port -m num start byte of ether address, default from 0 [-r] FILENAME load and execute script file FILENAME -e tap mode, using /dev/tapx by default (linux only) [-u] udp mode, default udp mode options: -s port local udp base port, default from 20000 -c port remote udp base port (dynamips udp port), default from 30000 -t ip remote host IP, default 127.0.0.1 tap mode options: -d device device name, works only when -i is set to 1 hypervisor mode option: -H port run as the hypervisor listening on the tcp port If no FILENAME specified, vpcs will read and execute the file named startup.vpc if it exists in the current directory. NOTE: 1. The cygwin1.dll used by VPCS maybe conflicted with other version. Please keep the latest cygwin1.dll in your system. 2. Set telnet LINEMODE to 'character at a time' while running as the daemon 'telnet> mode character' Website: http://wiki.freecode.com.cn or http://mirnshi.cublog.cn History: 0.8 Support IPv6 fragmentation Support DNS AAAA record Add an option to disable the relay function from the command line 0.6 bugfix: use MAC of gateway while replying in the background bugfix: command with more than 20 arguments will cause core dump check mtu when receiving the packet, reply the packet is too big drop 'ip mtu', add 'set mtu' dump relay packets to file reformat help text renew the dhcp4 lease automatically support ip fragmentation zero, loopback and broadcast address are invalid now 0.5b2 fix: using getenv+access to the real path of VPCS. patch for Debian GNU/kFreeBSD from Daniel Lintott flush out the output buffer while running 'echo ...' increase the maxinum number of tcp sessions and decrease tcp keep alive time fix: arp table, the source ether address is not saved 0.5b1 support for a specified number of vpc instances (between 1 and 9) support for TAP device name (only with 1 VPC instance) support default filename (startup.vpc) for load & save commands. 0.5b0 support hypervisor mode 0.4b2 support DNS support 'dump' packets add 'rlogin' command to connect the remote host 0.4a support daemon mode 0.3 under BSD license 0.20a support IPv6 linklocal, stateless autoconfiguration new 'ping' with many optins, and implement the tcp state machine support load/save the VPCS configuration support save/load the command history automatically 0.16a Support IPv6 0.15a Add configure the host ip using dhcp 0.14g Fix the traceroute loop running bug 0.14f Fix the traceroute TTL bug 0.14e Fix the bug, parse 'echo' and 'traceroute' command line error. 0.14d Fix the bug which reply the arp request with broadcast address as the source MAC address. 0.14c Change the TTL to 64. 0.14b Fix the bug about the I/O queue. 0.14a Add arp function that shows the current arp table, 120 seconds expired. Add echo function that sends upd/tcp packet to the remote hosts. Now, you can test acl in your routers network. 0.13a Add ping localhost Fix a ping bug: get reply from any host ip. 0.12s Fix the tracert argument bug 0.10s Support udp mode 0.02s Fix a string copy bug 0.01s First version vpcs-0.8.3/readme_cn.txt000066400000000000000000000113071447703427300151700ustar00rootroot00000000000000 ӭʹ VPCS, °汾Ϊ 0.8. VPCS BSD ɵַ ԴЭԴ vpcs.sf.net ȡ Ϣ wiki.freecode.com.cn. VPCS ģ 9 PC ping/traceroute Щ PC Щ PC ping/traceroute ·ȻЩ PC ȫϵ PCֻһ Linux Windows ϵӦó򣬽 ʹйڽ Dynamips ѧϰ Cisco 豸ĹУ 𵽷dzİʵг䵱 PC ·ʹ Vmware PCͨЩ߻ռôڴ CPU Դ VPCS UDP ̫ģʽ UDP ʽ£VPCS ͨ UDP ͺͽ ݰ̫ʽ£ʹ /dev/tapx ͺͽݰ Windows ֻ֧ UDP ʽ VPCS ȱʡ 20000 20008 UDP ˿ڣ 30000 30008 ݰûָļҵǰĿ¼´ȱʡļ ļΪstartup.vpcVPCS ͻԶļִа startup.vpc ԰Ϊ VPCS ڲ VPCS ѡ usage: vpcs [OPTIONS] [FILENAME] OPTIONS: -h print this help then exit -v print version information then exit -i num number of vpc instances to start (default is 9) -p port run as a daemon listening on the tcp port -m num start byte of ether address, default from 0 [-r] FILENAME load and execute script file FILENAME -e tap mode, using /dev/tapx by default (linux only) [-u] udp mode, default udp mode options: -s port local udp base port, default from 20000 -c port remote udp base port (dynamips udp port), default from 30000 -t ip remote host IP, default 127.0.0.1 tap mode options: -d device device name, works only when -i is set to 1 hypervisor mode option: -H port run as the hypervisor listening on the tcp port If no FILENAME specified, vpcs will read and execute the file named startup.vpc if it exists in the current directory. ע⣺ 1. VPCS ʹõ cygwin1.dll cygwin1.dll ݡһϵͳ ֻ°汾ġ 2. ̨ģʽʱtelnet LINEMODEΪ'һδһַ' 'telnet> mode character' վ㣺http://wiki.freecode.com.cn http://mirnshi.cublog.cn ʷ汾 0.8 ֧IPv6Ƭ ֧DNS IPv6 AAAA ѡ--ֹrelay 0.6 ޶ 1. ̨ӦʱδʹصMACַ 2. 20± 3. ʷ± ޶ 1. Ƴ'ip mtu'滻Ϊ'set mtu' 2. ֽ֧relayݰתļļʽΪpcap Զ̬˲ɷڵݡ 3. dhcp4Զ 4. ֧IPƬ/ 5. ping֧'-D'ѡǿƲƬ 6. ݺͽݰȶMTUMTUӦʾ 7. ػַ鲥ַַжΪǷַʹ 8. ¸ʽ 9. echoֲ֧ɫʾ'@'ʾ 10. ӱdnsrelay 0.5b2 ޶ʹgetenv+accessʽȡVPCSʵ· Debian GNU/kFreeBSDIJDaniel Lintott echoʱˢ tcpỰСtcpʱ ޶ԴMACַδ浽arp 0.5b1 ֧vpc ֧TAP豸ֻ1VPC loadsave֧ȱʡļ 0.5b0 ֧hypervisor 0.4b2 ֧DNS ֧ݰЭʾ ֧Զ̵¼豸ȼ ǿ޶ 0.4a Ӻ̨ģʽ 0.3 BSD 0.20a һǿIPv6֧LinkLocal״̬Զãֹeui-64 ָ֧pingʵtcpӵرյ״̬ ֱ֧/ ֧ʷԶ/ 0.16a ֧IPv6 0.15a DHCPȡIPַ ַʱԲָصַ 0.14g ޶tracerouteѭ 0.14f ޶tracerouteTTL 0.14e ޶echotracerouteд 0.14d ޶Arp󣬴ؽ㲥ַΪԴַӦArp 0.14c ޶TTLΪ64 0.14b ޶ I/O д 0.14a arp ʾǰ arp 120Ĺˢ echo Զ udp/tcp ݰڲ ACL DZȽõġ ޶ͬȽϴ 0.13a ping/tracert IP Ӧ ޶ ping κ IPڴ 0.12s ޶ tracert 0.10s ֧ udp ʽ 0.02s ޶һַ 0.01s ʼ汾 vpcs-0.8.3/src.drivers/000077500000000000000000000000001447703427300147545ustar00rootroot00000000000000vpcs-0.8.3/src.drivers/freebsd/000077500000000000000000000000001447703427300163665ustar00rootroot00000000000000vpcs-0.8.3/src.drivers/freebsd/Makefile000066400000000000000000000001231447703427300200220ustar00rootroot00000000000000.PATH: ${.CURDIR}/../../net KMOD= if_utun SRCS= if_utun.c .include vpcs-0.8.3/src.drivers/freebsd/README000066400000000000000000000013511447703427300172460ustar00rootroot000000000000001. how to compile cp if_utun.c /sys/net/. mkdir /sys/modules/if_utun cp Makefile /sys/modules/if_utun/. cd /sys/modules/if_utun make 2. how to load kldload ./if_utun.ko ifconfig utun create a.b.c.d netmask A.B.C.D 3. config sysctl net.link.utun.0.sport=40001 sysctl net.link.utun.0.dport=40002 sysctl net.link.utun.0.destaddr="127.0.0.1" receive the udp packets from 127.0.0.1:40002 send the packets to 127.0.0.1:40002 sysctl net.link.utun.0.sport=40001 sysctl net.link.utun.0.dport=40002 sysctl net.link.utun.0.destaddr="192.168.1.1" receive the udp packets from 192.168.1.1:40002 send the packets to 192.168.1.1:40002 Plesae note, port 40001 should not be used by local application. vpcs-0.8.3/src.drivers/freebsd/if_utun.c000066400000000000000000000414321447703427300202070ustar00rootroot00000000000000/*- * Copyright (c) 2013 Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* $Id$ * * utun, pseudo interface driver * encapsulates the traffic into UDP packets. * * outgoing path * --> utun -- UDP(*) --> 127.0.0.1 --> ip_input() * \ * \--> 'real' NIC * * incoming path * --> ip_input() --> strip UDP header --> utun * (PFIL hook) * * Makefile: * .PATH: ${.CURDIR}/../../net * KMOD= if_utun * SRCS= if_utun.c * .include * * usage: kldload if_utun.ko * ifconfig utun create a.b.c.d netmask A.B.C.D * sysctl net.link.utun.0.sport=40001 * sysctl net.link.utun.0.dport=40002 * sysctl net.link.utun.0.destaddr="127.0.0.1" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UTUNNAME "utun" #define UTUNMTU 1400 #define MTAG_UTUN 20130824 LIST_HEAD(utun_softc_head, utun_softc); struct utun_softc { struct ifnet *ifp; char destip[16]; /* destination address, sysctl */ struct in_addr src_addr; /* local address */ struct in_addr dst_addr; /* destination address */ int src_port; int dst_port; struct sysctl_ctx_list ctx; /* sysctl list */ LIST_ENTRY(utun_softc) sc_list; int (*ether_output_p)(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct route *ro); }; #define UTUN_BPF_MTAP(_ifp, _m) do { \ if (bpf_peers_present((_ifp)->if_bpf)) { \ bpf_mtap((_ifp)->if_bpf, (_m)); \ } \ } while (0) static void utun_init(void *foo); static int utun_ioctl(struct ifnet *, u_long, caddr_t); static void utun_start(struct ifnet *ifp); static int utun_clone_match(struct if_clone *, const char *); static int utun_clone_create(struct if_clone *, char *, size_t, caddr_t); static int utun_clone_destroy(struct if_clone *, struct ifnet *); static void utun_sysctl(struct utun_softc *sc); static void utun_setaddr(struct ifnet *ifp); static u_char *utun_etheraddr(int idx); static int utun_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct route *ro); static int utun_input(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir, struct inpcb *inp); static struct sockaddr_in *utun_route(struct route *ro, struct in_addr dest, struct mbuf *m); static int utun_encap(struct ifnet *ifp, struct mbuf **m, struct sockaddr *dst); static MALLOC_DEFINE(M_UTUN, UTUNNAME, "Virtual Interface"); static struct rwlock utun_mtx; static struct utun_softc_head utun_softc_list; static struct if_clone utun_cloner = IFC_CLONE_INITIALIZER(UTUNNAME, NULL, IF_MAXUNIT, NULL, utun_clone_match, utun_clone_create, utun_clone_destroy); SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, OID_AUTO, utun, CTLFLAG_RW, 0, "Virtual Interface"); #if 0 #include static char *fmtstr(char *fmt, ...); #define BUFSIZE (2048) static char fmtbuf[4][BUFSIZE]; static char * fmtstr(char *fmt, ...) { static int idx = 0; va_list ap; int off = 0, max; char *pbuf; union { u_int32_t ui; u_int16_t us[2]; u_int8_t uc[4]; } u32; va_start(ap, fmt); pbuf = fmtbuf[idx]; while (*fmt) { if (*fmt != '%') { off += snprintf(pbuf + off, BUFSIZE - off, "%c", *fmt); fmt ++; continue; } fmt ++; switch (*fmt) { case 'd': off += snprintf(pbuf + off, BUFSIZE - off, "%d", va_arg(ap, int)); break; case 'I': u32.ui = va_arg(ap, int); off += snprintf(pbuf + off, BUFSIZE - off, "%d.%d.%d.%d", u32.uc[0], u32.uc[1], u32.uc[2], u32.uc[3]); break; } fmt++; } idx++; idx %= 4; return pbuf; } #endif static int utun_clone_match(struct if_clone *ifc, const char *name) { const char *cp; if (strncmp(UTUNNAME, name, sizeof(UTUNNAME) - 1) != 0) return 0; for (cp = name + sizeof(UTUNNAME) - 1; *cp != '\0'; cp++) { if (*cp < '0' || *cp > '9') return 0; } return 1; } static int utun_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) { struct utun_softc *sc = ifp->if_softc; int unit = ifp->if_dunit; rw_wlock(&utun_mtx); LIST_REMOVE(sc, sc_list); rw_wunlock(&utun_mtx); sysctl_ctx_free(&sc->ctx); ether_ifdetach(ifp); if_free_type(ifp, IFT_ETHER); free(sc, M_UTUN); ifc_free_unit(ifc, unit); return 0; } static int utun_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) { char *dp; int wildcard; int unit; int error; struct utun_softc *sc; struct ifnet *ifp; if (params) { sc = (struct utun_softc *)params; ifp = sc->ifp; ether_ifattach(ifp, utun_etheraddr(ifp->if_index)); strlcpy(name, sc->ifp->if_xname, len); goto fin; } error = ifc_name2unit(name, &unit); if (error != 0) return error; wildcard = (unit < 0); error = ifc_alloc_unit(ifc, &unit); if (error != 0) return error; /* In the wildcard case, we need to update the name. */ if (wildcard) { for (dp = name; *dp != '\0'; dp++); if (snprintf(dp, len - (dp-name), "%d", unit) > len - (dp-name) - 1) { panic("%s: interface name too long", __func__); } } sc = malloc(sizeof(struct utun_softc), M_UTUN, M_WAITOK | M_ZERO); ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { ifc_free_unit(ifc, unit); free(sc, M_UTUN); return ENOSPC; } sc->src_port = sc->dst_port = 0; ifp->if_softc = sc; strlcpy(ifp->if_xname, name, IFNAMSIZ); ifp->if_dname = ifc->ifc_name; ifp->if_dunit = unit; ifp->if_type = IFT_ETHER; ifp->if_start = utun_start; ifp->if_init = utun_init; ifp->if_ioctl = utun_ioctl; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ether_ifattach(ifp, utun_etheraddr(ifp->if_index)); /* change mtu */ ifp->if_mtu = UTUNMTU; ifp->if_drv_flags |= IFF_DRV_RUNNING; /* save ether_output, in /sys/net/if_ethersubr.c */ sc->ether_output_p = ifp->if_output; ifp->if_output = utun_output; fin: /* create sysctl node */ utun_sysctl(sc); rw_wlock(&utun_mtx); LIST_INSERT_HEAD(&utun_softc_list, sc, sc_list); rw_wunlock(&utun_mtx); return 0; } static void utun_sysctl(struct utun_softc *sc) { struct sysctl_oid *oid; char num[8]; sysctl_ctx_init(&sc->ctx); snprintf(num, sizeof(num), "%d", sc->ifp->if_dunit); oid = SYSCTL_ADD_NODE(&sc->ctx, &SYSCTL_NODE_CHILDREN(_net_link, utun), OID_AUTO, num, CTLFLAG_RD, NULL, ""); SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "sport", CTLTYPE_INT|CTLFLAG_RW, &sc->src_port, sc->src_port, "Source port"); SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "dport", CTLTYPE_INT|CTLFLAG_RW, &sc->dst_port, sc->dst_port, "Destination port"); SYSCTL_ADD_STRING(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "destaddr", CTLTYPE_INT|CTLFLAG_RW, sc->destip, 16, "Destination ip address"); } /* PFIL hook function */ static int utun_input(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir, struct inpcb *inp) { struct ip *ip = NULL; struct udphdr *uh; struct mbuf *m = *mp; struct m_tag *mtag; struct utun_softc *sc; /* check mtag */ mtag = m_tag_locate(m, MTAG_UTUN, 0, NULL); if (mtag && (*(int *)(mtag + 1)) == MTAG_UTUN) { m_tag_delete(m, mtag); ifp->if_ipackets++; return 0; } ip = mtod(m, struct ip *); if (ip->ip_p == IPPROTO_UDP) { uh = (struct udphdr *)(ip + 1); rw_rlock(&utun_mtx); LIST_FOREACH(sc, &utun_softc_list, sc_list) { if (sc->src_port != ntohs(uh->uh_dport)) continue; if (sc->dst_port != ntohs(uh->uh_sport)) continue; if (sc->dst_addr.s_addr == 0) utun_setaddr(sc->ifp); if (ip->ip_src.s_addr != sc->dst_addr.s_addr) continue; if (ip->ip_dst.s_addr != sc->src_addr.s_addr) continue; break; } rw_runlock(&utun_mtx); if (sc) { /* create tag */ mtag = m_tag_alloc(MTAG_UTUN, 0, sizeof(int), M_NOWAIT); if (mtag) { *(int *)(mtag + 1) = MTAG_UTUN; m_tag_prepend(m, mtag); /* skip udp header */ m_adj(m, sizeof(struct udpiphdr)); m->m_pkthdr.rcvif = sc->ifp; (*sc->ifp->if_input)(sc->ifp, m); *mp = NULL; } } } return 0; } static int utun_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst0, struct route *ro0) { struct utun_softc *sc; struct route ro; struct sockaddr_in *dst = NULL; struct in_addr dest; int error; int olen; sc = ifp->if_softc; /* set destination address and port */ if (!sc->dst_addr.s_addr || !sc->src_addr.s_addr) utun_setaddr(ifp); if (!sc->dst_addr.s_addr || !sc->src_addr.s_addr) { ifp->if_oerrors++; error = EINVAL; goto bad; } olen = m_length(m, 0); if (utun_encap(ifp, &m, dst0)) { ifp->if_oerrors++; if (m) { m_free(m); error = EINVAL; } else error = ENOBUFS; goto bad; } /* encapsulate and * send to upper layer if the destination is local host */ if (ntohl(sc->dst_addr.s_addr) == 0x7f000001) { m->m_pkthdr.rcvif = V_loif; m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; ifp->if_opackets++; ifp->if_obytes += olen; return netisr_queue(NETISR_IP, m); } dest.s_addr = sc->dst_addr.s_addr; if ((dst = utun_route(&ro, dest, m)) == NULL) { ifp->if_oerrors++; m_free(m); return ENETUNREACH; } /* send out */ ifp->if_opackets++; ifp->if_obytes += olen; ifp = ro.ro_rt->rt_ifp; error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, &ro); RTFREE(ro.ro_rt); bad: return error; } static int utun_encap(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst) { struct utun_softc *sc; struct llentry *lle = NULL; u_char edst[ETHER_ADDR_LEN]; struct mbuf *m; struct ether_header *eh; struct arphdr *ah; struct ip *ip; struct udpiphdr *ui; u_short type; int error; int hlen, olen; char b[9]; sc = ifp->if_softc; m = *mp; type = 0; switch (dst->sa_family) { case AF_ARP: ah = mtod(m, struct arphdr *); ah->ar_hrd = htons(ARPHRD_ETHER); switch(ntohs(ah->ar_op)) { case ARPOP_REQUEST: case ARPOP_REPLY: default: type = htons(ETHERTYPE_ARP); break; } if (m->m_flags & M_BCAST) bcopy(ifp->if_broadcastaddr, edst, ETHER_ADDR_LEN); else bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN); break; case AF_INET: error = arpresolve(ifp, NULL, m, dst, edst, &lle); if (error) goto ret; type = htons(ETHERTYPE_IP); break; } if (!type) return 1; olen = m_length(m, 0); hlen = sizeof(struct udpiphdr) + 2 * ETHER_HDR_LEN; M_PREPEND(m, hlen, M_DONTWAIT); if (m == NULL) { *mp = NULL; error = ENOBUFS; goto ret; } *mp = m; error = 0; m_adj(m, ETHER_HDR_LEN); ip = mtod(m, struct ip *); ui = (struct udpiphdr *)(ip); eh = (struct ether_header *)(ui + 1); (void)memcpy(&eh->ether_type, &type, sizeof(eh->ether_type)); (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); (void)memcpy(eh->ether_shost, IF_LLADDR(ifp), sizeof(eh->ether_shost)); ip->ip_v = 4; ip->ip_hl = 5; ip->ip_len = htons(m->m_pkthdr.len); ip->ip_id = ip_newid(); ip->ip_tos = 0; ip->ip_ttl = IPDEFTTL; ip->ip_off = htons(IP_DF); ip->ip_p = IPPROTO_UDP; if (ntohl(sc->dst_addr.s_addr) == 0x7f000001) ip->ip_src.s_addr = sc->dst_addr.s_addr; else ip->ip_src.s_addr = sc->src_addr.s_addr; ip->ip_dst.s_addr = sc->dst_addr.s_addr; ui->ui_sport = htons(sc->src_port); ui->ui_dport = htons(sc->dst_port); ui->ui_ulen = htons(sizeof(struct udphdr) + olen + ETHER_HDR_LEN); ui->ui_len = ui->ui_ulen; ui->ui_sum = 0; #if 1 bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ui->ui_len = ui->ui_ulen; ui->ui_sum = in_cksum(m, ntohs(ui->ui_ulen) + sizeof (struct ip)); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); #endif ip->ip_sum = 0; ip->ip_sum = in_cksum_hdr(ip); ret: return error; } static void utun_init(void *foo __unused) { } static void utun_start(struct ifnet *ifp) { } static int utun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { return ether_ioctl(ifp, cmd, data); #if 0 int error = 0; struct utun_softc *sc; struct ifreq *ifr; sc = ifp->if_softc; ifr = (struct ifreq *)data; switch (cmd) { default: error = ether_ioctl(ifp, cmd, data); break; } return error; #endif } static int utun_hook(void) { struct pfil_head *ph_inet; ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (ph_inet == NULL) return ENODEV; pfil_add_hook((void *)utun_input, NULL, PFIL_IN|PFIL_WAITOK, ph_inet); return 0; } static int utun_unhook(void) { struct pfil_head *ph_inet; ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (ph_inet != NULL) { pfil_remove_hook((void *)utun_input, NULL, PFIL_IN|PFIL_WAITOK, ph_inet); } return 0; } static int utun_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: rw_init(&utun_mtx, "utun_mtx"); LIST_INIT(&utun_softc_list); if_clone_attach(&utun_cloner); utun_hook(); break; case MOD_UNLOAD: utun_unhook(); if_clone_detach(&utun_cloner); rw_destroy(&utun_mtx); break; default: return EOPNOTSUPP; } return 0; } static moduledata_t utun_mod = { "utun", utun_modevent, 0 }; DECLARE_MODULE(utun, utun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); /* try to get the ether address of the first 'real' interface * and convert it to LAA, to be as my address */ static u_char * utun_etheraddr(int idx) { static u_char sea[ETHER_ADDR_LEN] = {0}; struct ifnet *ifp; u_char *ea; int found = 0; if (sea[0] & 0x2) { sea[5] = idx & 0xff; return sea; } IFNET_RLOCK_NOSLEEP(); TAILQ_FOREACH(ifp, &V_ifnet, if_link) { if ((ifp->if_type & IFT_ETHER) == 0) continue; ea = IF_LLADDR(ifp); if (*ea & 0x2) continue; found = 1; memcpy(sea, ea, sizeof(sea)); sea[0] |= 0x2; break; } IFNET_RUNLOCK_NOSLEEP(); if (!found) { sea[0] = 0x02; sea[1] = 0x50; sea[2] = 0x79; sea[3] = 0x68; sea[4] = 0x66; sea[5] = idx & 0xff; } return sea; } static void utun_setaddr(struct ifnet *ifp) { struct utun_softc *sc; struct ifaddr *ifa; struct in_addr in; struct sockaddr_in *si, sin; sc = ifp->if_softc; if (sc->dst_addr.s_addr == 0 && sc->destip[0] != '\0' && inet_aton(sc->destip, &in)) { sin.sin_family = AF_INET; sin.sin_len = sizeof(si); sin.sin_addr.s_addr = in.s_addr; ifa = ifa_ifwithnet(sintosa(&sin), 0); if (ifa) { si = (struct sockaddr_in *)ifa->ifa_addr; sc->src_addr.s_addr = si->sin_addr.s_addr; sc->dst_addr.s_addr = in.s_addr; } } } static struct sockaddr_in * utun_route(struct route *ro, struct in_addr dest, struct mbuf *m) { struct sockaddr_in *dst; struct rtentry *rt; bzero(ro, sizeof(*ro)); dst = (struct sockaddr_in *)&ro->ro_dst; dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr.s_addr = dest.s_addr; in_rtalloc_ign(ro, 0, M_GETFIB(m)); rt = ro->ro_rt; if (rt && (rt->rt_flags & RTF_UP) && (rt->rt_ifp->if_flags & IFF_UP) && (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) { if (rt->rt_flags & RTF_GATEWAY) dst = (struct sockaddr_in *)rt->rt_gateway; } else { if (rt) RTFREE(rt); return NULL; } return dst; } /* end of file */ vpcs-0.8.3/src/000077500000000000000000000000001447703427300132775ustar00rootroot00000000000000vpcs-0.8.3/src/Makefile.cygwin000066400000000000000000000012001447703427300162270ustar00rootroot00000000000000RM=rm -f CC=gcc $(CCOPT) OSTYPE=Linux CPUTYPE=i386 HVOPT=-DHV CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) -Dcygwin $(HVOPT) -Wall -I. LDFLAGS=-static -lpthread -s -static-libgcc -lutil OBJS=vpcs.o \ daemon.o \ readline.o \ packets.o \ getopt.o \ utils.o \ queue.o \ command.o \ dev.o \ dhcp.o \ command6.o \ packets6.o \ ip.o \ tcp.o \ inet6.o \ dns.o \ remote.o \ help.o \ dump.o \ relay.o \ hv.o \ frag.o \ frag6.o all: vpcs vpcs: $(OBJS) $(CC) $(OBJS) -o vpcs $(LDFLAGS) .c.o: keys.h vpcs.h packets.h dhcp.h $(CC) $(INCLUDE_PATH) $(CFLAGS) -c $< clean: $(RM) *.o vpcs vpcs.exe vpcs-0.8.3/src/Makefile.fbsd000066400000000000000000000012421447703427300156530ustar00rootroot00000000000000RM=rm -f CC=clang $(CCOPT) OSTYPE=FreeBSD CPUTYPE=i386 OPT=-Wall HVOPT=-DHV CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) $(OPT) $(HVOPT) $(DBGOPT) -I. LDFLAGS=-lpthread -lutil -static $(STRIP) OBJS=vpcs.o \ daemon.o \ readline.o \ packets.o \ utils.o \ queue.o \ command.o \ dev.o \ dhcp.o \ command6.o \ packets6.o \ ip.o \ tcp.o \ inet6.o \ dns.o \ remote.o \ help.o \ dump.o \ relay.o \ hv.o \ frag.o \ frag6.o debug: all all: vpcs vpcs: $(OBJS) $(CC) $(.ALLSRC) -o $(.TARGET) $(LDFLAGS) .c.o: vpcs.h packets.h dhcp.h $(CC) $(INCLUDE_PATH) $(CFLAGS) -c $< clean: $(RM) *.o vpcs .if make(debug) DBGOPT=-DDEBUG -g .else DBGOPT=-O2 STRIP=-s .endif vpcs-0.8.3/src/Makefile.linux000066400000000000000000000010601447703427300160720ustar00rootroot00000000000000RM=rm -f CC=gcc $(CCOPT) OSTYPE=Linux CPUTYPE:=$(shell uname -m) HVOPT=-DHV CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) $(HVOPT) -Wall -DTAP LDFLAGS=-lpthread -lutil OBJS=vpcs.o \ daemon.o \ readline.o \ packets.o \ utils.o \ queue.o \ command.o \ dev.o \ dhcp.o \ command6.o \ packets6.o \ ip.o \ tcp.o \ inet6.o \ dns.o \ remote.o \ help.o \ dump.o \ relay.o \ hv.o \ frag.o \ frag6.o all: vpcs vpcs: $(OBJS) $(CC) $(OBJS) -o vpcs $(LDFLAGS) .c.o: keys.h vpcs.h packets.h dhcp.h $(CC) $(INCLUDE_PATH) $(CFLAGS) -c $< clean: $(RM) *.o vpcs vpcs-0.8.3/src/Makefile.obsd000066400000000000000000000013541447703427300156700ustar00rootroot00000000000000RM=rm -f CC=clang $(CCOPT) OSTYPE=OpenBSD CPUTYPE=i386 OPT=-Wall HVOPT=-DHV #CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) $(OPT) $(HVOPT) $(DBGOPT) -D_BSD_SOURCE -I. CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) $(OPT) $(HVOPT) $(DBGOPT) -I. LDFLAGS=-lpthread -lutil -static $(STRIP) OBJS=vpcs.o \ daemon.o \ readline.o \ packets.o \ utils.o \ queue.o \ command.o \ dev.o \ dhcp.o \ command6.o \ packets6.o \ ip.o \ tcp.o \ inet6.o \ dns.o \ remote.o \ help.o \ dump.o \ relay.o \ hv.o \ frag.o \ frag6.o debug: all all: vpcs vpcs: $(OBJS) $(CC) $(.ALLSRC) -o $(.TARGET) $(LDFLAGS) .c.o: vpcs.h packets.h dhcp.h $(CC) $(INCLUDE_PATH) $(CFLAGS) -c $< clean: $(RM) *.o vpcs .if make(debug) DBGOPT=-DDEBUG -g .else DBGOPT=-O2 STRIP=-s .endif vpcs-0.8.3/src/Makefile.osx000066400000000000000000000010511447703427300155440ustar00rootroot00000000000000RM=rm -f CC=gcc $(CCOPT) OSTYPE=Darwin CPUTYPE=i386 HVOPT=-DHV CFLAGS=-D$(OSTYPE) -D$(CPUTYPE) $(HVOPT) -Wall LDFLAGS=-lpthread OBJS=vpcs.o \ daemon.o \ readline.o \ packets.o \ utils.o \ queue.o \ command.o \ dev.o \ dhcp.o \ command6.o \ packets6.o \ ip.o \ tcp.o \ inet6.o \ dns.o \ remote.o \ help.o \ dump.o \ relay.o \ hv.o \ frag.o \ frag6.o all: vpcs vpcs: $(OBJS) $(CC) $(OBJS) -o vpcs $(LDFLAGS) debug: vpcs .c.o: keys.h vpcs.h packets.h dhcp.h $(CC) $(INCLUDE_PATH) $(CFLAGS) $(OPT) -c $< clean: $(RM) *.o vpcs vpcs-0.8.3/src/command.c000066400000000000000000001345301447703427300150670ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include #include "command.h" #include "command6.h" #include "utils.h" #include "vpcs.h" #include "dev.h" #include "packets.h" #include "packets6.h" #include "queue.h" #include "dhcp.h" #include "tcp.h" #include "dns.h" #include "remote.h" #include "readline.h" #include "help.h" #include "dump.h" #include "relay.h" extern int pcid; extern int devtype; extern int ctrl_c; extern int ctrl_z; extern u_int time_tick; extern u_long ip_masks[33]; extern struct echoctl echoctl; //int canEcho; extern void clear_hist(void); extern const char *ver; extern struct rls *rls; extern int runLoad; extern int runStartup; extern const char *default_startupfile; extern int num_pths; static const char *color_name[8] = { "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"}; static int set_dump(int argc, char **argv); static int show_dump(int argc, char **argv); static int show_ip(int argc, char **argv); static int show_echo(int argc, char **argv); static int show_arp(int argc, char **argv); static int run_dhcp_new(int renew, int dump); static int run_dhcp_release(int dump); static int str2color(const char *cstr); /* * 1 2 3 4 5 6 * 012345678901234567890123456789012345678901234567890123456789012345678 * name ip/cidr gw LPort RHost:RPort */ int run_show(int argc, char **argv) { int i, j, k; struct in_addr in; char buf[128]; memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); if (argc > 1) { if (help_show(argc, argv)) return 1; if (!strncmp("arp", argv[1], strlen(argv[1]))) return show_arp(argc, argv); if (!strncmp("dump", argv[1], strlen(argv[1]))) return show_dump(argc, argv); if (!strcmp("ip", argv[1])) return show_ip(argc, argv); if (!strncmp("ipv6", argv[1], strlen(argv[1]))) return show_ipv6(argc, argv); if (!strncmp("mtu6", argv[1], strlen(argv[1]))) return show_mtu6(argc, argv); if (!strncmp("echo", argv[1], strlen(argv[1]))) return show_echo(argc, argv); if (!strncmp("version", argv[1], strlen(argv[1]))) return run_ver(0, NULL); if (!strncmp("history", argv[1], strlen(argv[1]))) return run_hist(0, NULL); printf("Invalid arguments\n"); return 1; } printf("\n"); switch(devtype) { case DEV_TAP: j = sprintf(buf, "NAME"); buf[j] = ' '; j = sprintf(buf + 7, "IP/MASK"); buf[j + 7] = ' '; j = sprintf(buf + 28, "GATEWAY"); buf[j + 28] = ' '; j = sprintf(buf + 64, "GATEWAY"); printf("%s\n", buf); for (i = 0; i < num_pths; i++) { memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); if (strcmp(vpc[i].xname, "VPCS")== 0) j = sprintf(buf, "%s%d", vpc[i].xname, i + 1); else j = sprintf(buf, "%s", vpc[i].xname); buf[j] = ' '; in.s_addr = vpc[i].ip4.ip; j = sprintf(buf + 7, "%s/%d", inet_ntoa(in), vpc[i].ip4.cidr); buf[j + 7] = ' '; in.s_addr = vpc[i].ip4.gw; sprintf(buf + 28, "%s", inet_ntoa(in)); for (k = 0; k < 6; k++) sprintf(buf + 46 + k * 3, "%2.2x:", vpc[i].ip4.mac[k]); printf("%s\n", buf); run_show6(&vpc[i]); } break; case DEV_UDP: j = sprintf(buf, "NAME"); buf[j] = ' '; j = sprintf(buf + 7, "IP/MASK"); buf[j + 7] = ' '; j = sprintf(buf + 28, "GATEWAY"); buf[j + 28] = ' '; j = sprintf(buf + 46, "MAC"); buf[j + 46] = ' '; j = sprintf(buf + 65, "LPORT"); buf[j + 65] = ' '; j = sprintf(buf + 72, "RHOST:PORT"); printf("%s\n", buf); for (i = 0; i < num_pths; i++) { memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); if (strcmp(vpc[i].xname, "VPCS")== 0) j = sprintf(buf, "%s%d", vpc[i].xname, i + 1); else j = sprintf(buf, "%s", vpc[i].xname); buf[j] = ' '; in.s_addr = vpc[i].ip4.ip; j = sprintf(buf + 7, "%s/%d", inet_ntoa(in), vpc[i].ip4.cidr); buf[j + 7] = ' '; in.s_addr = vpc[i].ip4.gw; j = sprintf(buf + 28, "%s", inet_ntoa(in)); buf[j + 28] = ' '; for (k = 0; k < 6; k++) sprintf(buf + 46 + k * 3, "%2.2x:", vpc[i].ip4.mac[k]); buf[63] = ' '; buf[64] = ' '; j = sprintf(buf + 65, "%d", vpc[i].lport); buf[j + 65] = ' '; in.s_addr = vpc[i].rhost; j = sprintf(buf + 72, "%s:%d", inet_ntoa(in), vpc[i].rport); printf("%s\n", buf); run_show6(&vpc[i]); } break; } return 1; } /* ping host */ int run_ping(int argc, char **argv) { int i, j; int gip; u_int gwip; struct in_addr in; struct packet *m; pcs *pc = &vpc[pcid]; char dname[256]; u_char flags; char ipstr[64]; char proto_seq[16]; int count = 5; int interval = 1000; if (argc < 2 || (argc == 2 && strlen(argv[1]) == 1 && argv[1][0] == '?')) { return help_ping(argc, argv); } pc->mscb.frag = true; pc->mscb.mtu = pc->mtu; pc->mscb.waittime = 1000; pc->mscb.ipid = time(0) & 0xffff; pc->mscb.seq = time(0); pc->mscb.proto = IPPROTO_ICMP; pc->mscb.ttl = TTL; pc->mscb.dsize = PAYLOAD56; pc->mscb.sport = (random() % (65000 - 1024)) + 1024; pc->mscb.dport = 7; pc->mscb.sip = pc->ip4.ip; memcpy(pc->mscb.smac, pc->ip4.mac, 6); strcpy(proto_seq, "icmp_seq"); i = 2; while (i < argc) { int c; if (argv[i++][0] != '-') continue; c = argv[i - 1][1]; switch (c) { case 'D': pc->mscb.frag = false; break; case 'u': if (i < argc) pc->mscb.mtu = atoi(argv[i++]); if (pc->mscb.mtu < 576 || pc->mscb.mtu > 65535) pc->mscb.mtu = 1500; case '1': pc->mscb.proto = IPPROTO_ICMP; strcpy(proto_seq, "icmp_seq"); break; case '2': pc->mscb.proto = IPPROTO_UDP; strcpy(proto_seq, "udp_seq"); break; case '3': pc->mscb.proto = IPPROTO_TCP; strcpy(proto_seq, "tcp_seq"); break; case 'P': if (i < argc) { int pro = atoi(argv[i++]); if (pro == IPPROTO_ICMP) { pc->mscb.proto = IPPROTO_ICMP; strcpy(proto_seq, "icmp_seq"); } else if (pro == IPPROTO_UDP) { pc->mscb.proto = IPPROTO_UDP; strcpy(proto_seq, "udp_seq"); } else if (pro == IPPROTO_TCP) { pc->mscb.proto = IPPROTO_TCP; strcpy(proto_seq, "tcp_seq"); } } break; case 'c': if (i < argc) count = atoi(argv[i++]); break; case 'l': if (i < argc) pc->mscb.dsize = atoi(argv[i++]); break; case 'T': if (i < argc) pc->mscb.ttl = atoi(argv[i++]); break; case 's': if (i < argc) pc->mscb.sport = atoi(argv[i++]); break; case 'p': if (i < argc) pc->mscb.dport = atoi(argv[i++]); break; case 'a': if (i < argc) pc->mscb.aproto = atoi(argv[i]); break; case 'f': if (i < argc) { for (j = 0; j < strlen(argv[i]); j++) { switch (argv[i][j] | 0x20) { case 'c': pc->mscb.flags |= 0x80; break; case 'e': pc->mscb.flags |= 0x40; break; case 'u': pc->mscb.flags |= 0x20; break; case 'a': pc->mscb.flags |= 0x10; break; case 'p': pc->mscb.flags |= 0x08; break; case 'r': pc->mscb.flags |= 0x04; break; case 's': pc->mscb.flags |= 0x02; break; case 'f': pc->mscb.flags |= 0x01; break; default: printf("Invalid options\n"); return 0; } } i++; } break; case 'i': if (i < argc) interval = atoi(argv[i++]); if (interval < 1) interval = 1000; break; case 'w': if (i < argc) pc->mscb.waittime = atoi(argv[i++]); if (pc->mscb.waittime < 1) pc->mscb.waittime = 1000; break; case 't': count = -1; break; default: printf("Invalid options\n"); return 0; break; } } if (pc->mscb.winsize == 0) pc->mscb.winsize = 0xb68; /* 1460 * 4 */ if (strchr(argv[1], ':') == NULL) { pc->mscb.dip = inet_addr(argv[1]); if (pc->mscb.dip == -1 || pc->mscb.dip == 0) { strcpy(dname, argv[1]); if (hostresolv(pc, dname, ipstr) == 0) { printf("Cannot resolve %s\n", argv[1]); return 0; } printf("%s resolved to ", argv[1]); if (strcmp(argv[1], dname) == 0) printf("%s\n", ipstr); else printf("%s(%s)\n", dname, ipstr); if (strchr(ipstr, ':')) { pc->mscb.mtu = pc->mtu; argv[1] = ipstr; return run_ping6(argc, argv); } pc->mscb.dip = inet_addr(ipstr); } } else { pc->mscb.mtu = pc->mtu; return run_ping6(argc, argv); } printf("\n"); /* find ether address of destination host or gateway */ if (pc->mscb.dip == pc->ip4.ip) { i = 1; in.s_addr = pc->mscb.dip; while ((i <= count || count == -1) && !ctrl_c) { printf("%s icmp_seq=%d ttl=%d time=0.001 ms\n", inet_ntoa(in), i++, pc->mscb.ttl); delay_ms(1); } return 1; } gwip = pc->ip4.gw; flags = pc->mscb.flags; redirect: if (sameNet(pc->mscb.dip, pc->ip4.ip, pc->ip4.cidr)) gip = pc->mscb.dip; else { if (gwip == 0) { printf("No gateway found\n"); return 0; } else gip = gwip; } in.s_addr = pc->mscb.dip; /* try to get the ether address of the destination */ if (!arpResolve(pc, gip, pc->mscb.dmac)) { in.s_addr = gip; printf("host (%s) not reachable\n", inet_ntoa(in)); return 0; } pc->mscb.flags = flags; if (pc->mscb.proto == IPPROTO_TCP && pc->mscb.flags == 0) { i = 0; while ((i++ < count || count == -1) && !ctrl_c) { struct timeval ts0, ts; u_int usec; int k; int dsize; int traveltime = 1; if (i > 1) delay_ms(pc->mscb.waittime); /* clear the input queue */ while ((m = deq(&pc->iq)) != NULL) del_pkt(m); /* connect the remote */ gettimeofday(&(ts), (void*)0); dsize = pc->mscb.dsize; pc->mscb.dsize = PAYLOAD56; k = tcp_open(pc, 4); /* restore data size */ pc->mscb.dsize = dsize; gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; if (k == 0) { printf("Connect %d@%s timeout\n", pc->mscb.dport, argv[1]); continue; } else if (k == 2) { struct in_addr din; din.s_addr = pc->mscb.rdip; if (pc->mscb.icmptype == ICMP_REDIRECT && pc->mscb.icmpcode == ICMP_REDIRECT_NET) { din.s_addr = pc->ip4.gw; printf("Redirect Network, gateway %s", inet_ntoa(din)); din.s_addr = pc->mscb.rdip; printf(" -> %s\n", inet_ntoa(din)); gwip = pc->mscb.rdip; delay_ms(100); goto redirect; } printf("*%s %s=%d ttl=%d time=%.3f ms", inet_ntoa(din), proto_seq, i++, pc->mscb.rttl, usec / 1000.0); printf(" (ICMP type:%d, code:%d, %s)\n", pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(4, pc->mscb.icmptype, pc->mscb.icmpcode)); continue; } else if (k == 3) { printf("Connect %d@%s RST returned\n", pc->mscb.dport, argv[1]); continue; } printf("Connect %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); traveltime = 0.6 * usec / 1000; /* send data after 1.5 * time2travel */ delay_ms(traveltime); gettimeofday(&(ts), (void*)0); k = tcp_send(pc, 4); if (k == 0) { printf("SendData %d@%s timeout\n", pc->mscb.dport, argv[1]); continue; } gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; printf("SendData %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); /* close after 1.5 * time2travel */ if (k != 2) delay_ms(traveltime); gettimeofday(&(ts), (void*)0); dsize = pc->mscb.dsize; pc->mscb.dsize = PAYLOAD56; k = tcp_close(pc, 4); pc->mscb.dsize = dsize; gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; if (k == 0) { printf("Close %d@%s timeout(%.3fms)\n", pc->mscb.dport, argv[1], usec / 1000.0); continue; } printf("Close %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); } } else { i = 1; while ((i <= count || count == -1) && !ctrl_c) { struct packet *p = NULL; struct timeval tv; u_int usec; int respok = 0; pc->mscb.sn = i; pc->mscb.timeout = time_tick; m = packet(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* clean input queue */ while ((p = deq(&pc->iq)) != NULL) del_pkt(p); gettimeofday(&(tv), (void*)0); enq(&pc->oq, m); while (!timeout(tv, pc->mscb.waittime) && !respok && !ctrl_c) { delay_ms(1); respok = 0; while ((p = deq(&pc->iq)) != NULL && !respok && !ctrl_c) { pc->mscb.icmptype = pc->mscb.icmpcode = 0; respok = response(p, &pc->mscb); usec = (p->ts.tv_sec - tv.tv_sec) * 1000000 + p->ts.tv_usec - tv.tv_usec; del_pkt(p); if (respok == 0) continue; //tv.tv_sec = 0; if ((pc->mscb.proto == IPPROTO_ICMP && pc->mscb.icmptype == ICMP_ECHOREPLY) || (pc->mscb.proto == IPPROTO_UDP && respok == IPPROTO_UDP) || (pc->mscb.proto == IPPROTO_TCP && respok == IPPROTO_TCP)) { printf("%d bytes from %s %s=%d ttl=%d time=%.3f ms\n", pc->mscb.rdsize, inet_ntoa(in), proto_seq, i++, pc->mscb.rttl, usec / 1000.0); break; } if (respok == IPPROTO_ICMP) { struct in_addr din; if (pc->mscb.icmptype == ICMP_REDIRECT && pc->mscb.icmpcode == ICMP_REDIRECT_NET) { din.s_addr = pc->ip4.gw; printf("Redirect Network, gateway %s", inet_ntoa(din)); din.s_addr = pc->mscb.rdip; printf(" -> %s\n", inet_ntoa(din)); gwip = pc->mscb.rdip; delay_ms(100); goto redirect; } din.s_addr = pc->mscb.rdip; printf("*%s %s=%d ttl=%d time=%.3f ms", inet_ntoa(din), proto_seq, i++, pc->mscb.rttl, usec / 1000.0); printf(" (ICMP type:%d, code:%d, %s)\n", pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(4, pc->mscb.icmptype, pc->mscb.icmpcode)); break; } } } if (!respok && !ctrl_c) printf("%s %s=%d timeout\n", argv[1], proto_seq, i++); delay_ms(interval); } } return 1; } static int run_dhcp_new(int renew, int dump) { int i; struct packet *m; int ok; pcs *pc = &vpc[pcid]; int ts[3] = {1, 3, 9}; struct packet *p; struct in_addr in; u_char mac[6]; pc->ip4.dynip = 1; srand(time(0)); pc->ip4.dhcp.xid = rand(); /* discover */ i = 0; ok = 0; while (i < 3 && !ok) { if (!dump) { printf("D"); fflush(stdout); } m = dhcp4_discover(pc, renew); if (m == NULL) { printf("out of memory\n"); return 0; } if (dump) dmp_dhcp(pc, m); enq(&pc->oq, m); sleep(ts[i]); while ((p = deq(&pc->iq)) != NULL && !ok) { if ((ok = isDhcp4_Offer(pc, p))) { if (dump) dmp_dhcp(pc, p); else { printf("O"); fflush(stdout); } } free(p); } i++; } if (i == 3) { printf("\nCan't find dhcp server\n"); return 1; } /* request */ i = 0; ok = 0; while (i < 3 && !ok) { m = dhcp4_request(pc); if (m == NULL) { printf("out of memory\n"); return 0; } if (dump) dmp_dhcp(pc, m); else { printf("R"); fflush(stdout); } enq(&pc->oq, m); sleep(1); while ((p = deq(&pc->iq)) != NULL && !ok) { if ((ok = isDhcp4_packer(pc, p))) { if (dump) dmp_dhcp(pc, p); else { printf("A"); fflush(stdout); } } free(p); } i++; } if (i == 3) { printf("\nCan't get ip address from dhcp server\n"); return 1; } /* check ip address via gratuitous ARP */ if (arpResolve(pc, pc->ip4.ip, mac) == 1) { in.s_addr = pc->ip4.ip; PRINT_MAC(mac); printf(" use my ip %s\n", inet_ntoa(in)); memset(pc->ipmac4, 0, sizeof(pc->ipmac4)); /* clear ip address */ pc->ip4.ip = 0; pc->ip4.cidr = 0; pc->ip4.gw = 0; return 0; } in.s_addr = pc->ip4.ip; printf(" IP %s/%d", inet_ntoa(in), pc->ip4.cidr); if (pc->ip4.gw != 0) { in.s_addr = pc->ip4.gw; printf(" GW %s\n", inet_ntoa(in)); } pc->mtu = MTU; if (pc->ip4.dhcp.renew == 0) pc->ip4.dhcp.renew = pc->ip4.dhcp.lease / 2; if (pc->ip4.dhcp.rebind == 0) pc->ip4.dhcp.rebind = pc->ip4.dhcp.lease * 7 / 8; pc->ip4.dhcp.timetick = time_tick; return 1; } static int run_dhcp_release(int dump) { struct packet *m; pcs *pc = &vpc[pcid]; m = dhcp4_release(pc); if (m == NULL) { printf("out of memory\n"); return 0; } if (dump) dmp_dhcp(pc, m); enq(&pc->oq, m); pc->ip4.ip = 0; pc->ip4.cidr = 0; pc->ip4.gw = 0; return 0; } int run_ipconfig(int argc, char **argv) { char buf[MAX_LEN]; struct in_addr in; int icidr = 24; u_int rip, gip, tip; int i, j; int hasgip = 1; pcs *pc = &vpc[pcid]; u_char mac[6]; if (argc < 2 || (argc == 2 && strlen(argv[1]) == 1 && argv[1][0] == '?')) { return help_ip(argc, argv); } if (strchr(argv[1], ':') != NULL) return run_ipset6(argc, argv); if (!strncmp("dhcp", argv[1], strlen(argv[1]))) { int dump = 0; int flag = 0; i = 1; while (++i < argc) { if (!strcmp(argv[i], "-d")) { dump = 1; continue; } if (!strcmp(argv[i], "-r")) { flag = (flag << 4) + 0x5; continue; } if (!strcmp(argv[i], "-x")) { flag = (flag << 4) + 0xa; continue; } flag = -1; break; } if (flag == -1) return help_ip(argc, argv); switch (flag) { case 0: run_dhcp_new(0, dump); break; case 0x5: run_dhcp_new(1, dump); break; case 0xa: run_dhcp_release(dump); break; case 0x5a: run_dhcp_new(1, dump); run_dhcp_release(dump); break; case 0xa5: run_dhcp_release(dump); run_dhcp_new(1, dump); break; } return 1; } if (!strncmp("auto", argv[1], strlen(argv[1]))) return ipauto6(); if (!strncmp("domain", argv[1], strlen(argv[1]))) { if (argc != 3) { printf("Incomplete command.\n"); return 1; } if (strlen(argv[2]) > 64 || strstr(argv[2], "..")) { printf("Invalid domain name.\n"); return 1; } char *p = argv[2]; while (*p) { if (*p == '.') p++; else { strcpy(vpc[pcid].ip4.domain, p); p = vpc[pcid].ip4.domain; if (p[strlen(p) - 1] == '.') p[strlen(p) - 1] = '\0'; return 1; } } return 1; } if (!strncmp("dns", argv[1], strlen(argv[1]))) { if (!strcmp(argv[argc - 1] , "?")) return help_ip(argc, argv); if (argc == 3) { if (!strcmp(argv[2], "0")) { pc->ip4.dns[0] = 0; return 1; } rip = inet_addr(argv[2]); if (rip == -1 || rip == 0) { printf("Invalid address\n"); return 0; } pc->ip4.dns[0] = rip; } if (argc == 4) { if (!strcmp(argv[2], "0")) { pc->ip4.dns[0] = 0; return 1; } rip = inet_addr(argv[2]); if (rip == -1 || rip == 0) { printf("Invalid address: %s\n", argv[2]); return 0; } pc->ip4.dns[0] = rip; if (!strcmp(argv[3], "0")) { pc->ip4.dns[0] = 0; return 1; } rip = inet_addr(argv[3]); if (rip == -1 || rip == 0) { printf("Invalid address: %s\n", argv[3]); return 0; } pc->ip4.dns[1] = rip; } return 1; } if (!strncmp("dns6", argv[1], strlen(argv[1]))) { return run_ipdns6(argc, argv); } rip = inet_addr(argv[1]); hasgip = gip = 0; icidr = 24; i = 1; while (++i < argc) { /* netmask */ if (digitstring(argv[i]) && strlen(argv[i]) < 3) { icidr = atoi(argv[i]); continue; } if ((strlen(argv[i]) > 8) && (!strncmp(argv[i], "255.", 4))) { gip = inet_addr(argv[i]); for (j = 0; i < 33; j++) { if (ip_masks[j] == ntohl(gip)) { icidr = j; break; } } continue; } j = strlen(argv[i]); if (j > 6 && j < 16) { hasgip = 1; gip = inet_addr(argv[i]); continue; } else { printf("Invalid options\n"); return 0; } } if (icidr < 1 || icidr > 30) icidr = 24; if (rip == -1 || gip == -1 || rip == gip || #if (defined(Linux) || defined(OpenBSD)) ((rip & 0x7f) == 0x7f) || rip == 0 || IN_MULTICAST(ntohl(rip))) { #else IN_LOOPBACK(ntohl(rip)) || IN_ZERONET(ntohl(rip)) || IN_MULTICAST(ntohl(rip))) { #endif printf("Invalid address\n"); return 0; } tip = ntohl(rip) & (~ip_masks[icidr]); if (tip == 0 || ((tip | ip_masks[icidr]) == 0xffffffff)) { printf("Invalid host address\n"); return 0; } if (hasgip) { tip = ntohl(gip) & (~ip_masks[icidr]); if (tip == 0 || ((tip | ip_masks[icidr]) == 0xffffffff)) { printf("Invalid gateway address\n"); return 0; } if ((ntohl(rip) & ip_masks[icidr]) != (ntohl(gip) & ip_masks[icidr])) { printf("not same subnet\n"); return 0; } } /* check ip address via gratuitous ARP */ pc->ip4.ip = rip; printf("Checking for duplicate address...\n"); if ((arpResolve(pc, rip, mac) == 1) && (memcmp(mac, pc->ip4.mac, ETH_ALEN) != 0)) { in.s_addr = rip; printf("%s is being used by MAC ", inet_ntoa(in)); PRINT_MAC(mac); printf("\nAddress not changed\n"); memset(pc->ipmac4, 0, sizeof(pc->ipmac4)); /* clear ip address */ pc->ip4.ip = 0; pc->ip4.cidr = 0; pc->ip4.gw = 0; return 0; } pc->ip4.dynip = 0; pc->ip4.ip = rip; pc->ip4.gw = gip; pc->ip4.cidr = icidr; pc->mtu = MTU; /* set tap ip address */ if (DEV_TAP == devtype) { tip = (ntohl(rip) | (~ip_masks[icidr])) - 1; in.s_addr = ntohl(tip); i = sprintf(buf, "ifconfig tap%d %s ", pcid, inet_ntoa(in)); in.s_addr = ntohl(ip_masks[icidr]); sprintf(buf + i, " netmask %s up", inet_ntoa(in)); i = system(buf); } /* display configuration */ in.s_addr = pc->ip4.ip; printf("%s : %s", vpc[pcid].xname, inet_ntoa(in)); in.s_addr = ntohl(ip_masks[icidr]); printf(" %s", inet_ntoa(in)); if (hasgip) { in.s_addr = pc->ip4.gw; printf(" gateway %s", inet_ntoa(in)); } printf("\n"); return 1; } int run_tracert(int argc, char **argv) { int i; u_int gip, gwip; struct in_addr in; int count = 128; struct packet *m; pcs *pc = &vpc[pcid]; int ok = 0; int pktnum = 3; int prn_ip = 1; char outbuf[1024]; int buf_off = 0; char dname[256]; char ipstr[64]; pc->mscb.seq = time(0); pc->mscb.proto = IPPROTO_UDP; pc->mscb.dsize = 64; pc->mscb.mtu = pc->mtu; pc->mscb.sport = rand() & 0xfff1; pc->mscb.dport = pc->mscb.sport + 1; pc->mscb.sip = pc->ip4.ip; pc->mscb.waittime = 1000; pc->mscb.timeout = time_tick; memcpy(pc->mscb.smac, pc->ip4.mac, 6); if (argc < 2 || (argc == 2 && !strcmp(argv[1], "?"))) { return help_trace(argc, argv); } if (strchr(argv[1], ':')) { pc->mscb.mtu = pc->mtu; return run_tracert6(argc, argv); } if (argc > 2) { i = 2; while (i < argc) { if (!strcmp(argv[i], "-P")) { if (i + 1 >= argc) { printf("Missing protocol\n"); return 0; } i++; if (!digitstring(argv[i])) { printf("Invalid protocol\n"); return 0; } int j = atoi(argv[i]); if (j == IPPROTO_ICMP) { pc->mscb.proto = IPPROTO_ICMP; } else if (j == IPPROTO_UDP) { pc->mscb.proto = IPPROTO_UDP; } else if (j == IPPROTO_TCP) { pc->mscb.proto = IPPROTO_TCP; pc->mscb.flags |= 0x02; } else { printf("Invalid protocol\n"); return 0; } i++; continue; } if (!strcmp(argv[i], "-m")) { if (i + 1 >= argc) { printf("Missing TTL\n"); return 0; } if (!digitstring(argv[i + 1])) { printf("Invalid TTL\n"); return 0; } i++; int j = atoi(argv[i]); if (j > 0 && j <= 64) count = j; else { printf("Invalid TTL\n"); return 0; } i++; continue; } if (digitstring(argv[i])) { if (count == 128) { int j = atoi(argv[i]); if (j > 0 && j <= 64) count = j; else { printf("Invalid TTL\n"); return 0; } i++; continue; } } return help_trace(argc, argv); } } /* no TTL given */ if (count == 128) count = 8; pc->mscb.dip = inet_addr(argv[1]); if (pc->mscb.dip == -1 || pc->mscb.dip == 0) { strcpy(dname, argv[1]); if (hostresolv(pc, dname, ipstr) == 0) { printf("Cannot resolve %s\n", argv[1]); return 0; } printf("%s resolved to %s\n", dname, ipstr); if (strchr(ipstr, ':')) { pc->mscb.mtu = pc->mtu; argv[1] = ipstr; return run_tracert6(argc, argv); } pc->mscb.dip = inet_addr(ipstr); } if (pc->mscb.dip == pc->ip4.ip) { i = 1; in.s_addr = pc->mscb.dip; printf("traceroute to %s, %d hops max\n", argv[1], count); printf(" 1 %s 0.001 ms\n", inet_ntoa(in)); return 1; } printf("trace to %s, %d hops max", argv[1], count); if (pc->mscb.proto == IPPROTO_ICMP) printf("%s", " (ICMP)"); else if (pc->mscb.proto == IPPROTO_TCP) printf("%s", " (TCP)"); printf(", press Ctrl+C to stop\n"); gwip = pc->ip4.gw; redirect: if (sameNet(pc->mscb.dip, pc->ip4.ip, pc->ip4.cidr)) gip = pc->mscb.dip; else { if (gwip == 0) { printf("No gateway found\n"); return 0; } else gip = gwip; } /* try to get the ether address of destination */ if (!arpResolve(pc, gip, pc->mscb.dmac)) { in.s_addr = gip; printf("host (%s) not reachable\n", inet_ntoa(in)); return 0; } /* send the udp packets */ i = 1; while (i <= count && !ctrl_c) { struct packet *p; struct timeval tv; u_int usec; int j; /* clean input queue */ while ((p = deq(&pc->iq)) != NULL) del_pkt(p); prn_ip = 1; buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, "%2d ", i); for (j = 0; j < pktnum && !ctrl_c; j++) { pc->mscb.ttl = i; pc->mscb.icmptype = 0; pc->mscb.rdip = pc->mscb.dip; m = packet(pc); if (m == NULL) { printf("out of memory\n"); return false; } gettimeofday(&(tv), (void*)0); enq(&pc->oq, m); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); ok = 0; while ((p = deq(&pc->iq)) != NULL && !ok && !timeout(tv, pc->mscb.waittime) && !ctrl_c) { ok = response(p, &pc->mscb); usec = (p->ts.tv_sec - tv.tv_sec) * 1000000 + p->ts.tv_usec - tv.tv_usec; del_pkt(p); if (pc->mscb.icmptype == ICMP_REDIRECT && pc->mscb.icmpcode == ICMP_REDIRECT_NET) { in.s_addr = pc->ip4.gw; buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, "Redirect Network, gateway %s", inet_ntoa(in)); in.s_addr = pc->mscb.rdip; buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, " -> %s\n", inet_ntoa(in)); gwip = pc->mscb.rdip; delay_ms(100); goto redirect; } if (pc->mscb.icmptype == ICMP_TIMXCEED) { in.s_addr = pc->mscb.rdip; if (prn_ip) { buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, "%s ", inet_ntoa(in)); prn_ip = 0; } buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, " %.3f ms", usec / 1000.0); tv.tv_sec = 0; break; } else if (pc->mscb.icmptype == ICMP_UNREACH) { in.s_addr = pc->mscb.rdip; if (prn_ip) { buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, "*%s %.3f ms (ICMP type:%d, code:%d, %s)", inet_ntoa(in), usec / 1000.0, pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(4, pc->mscb.icmptype, pc->mscb.icmpcode)); prn_ip = 0; } tv.tv_sec = 0; ok = 99999; break; } else if (pc->mscb.dip == pc->mscb.rdip) { in.s_addr = pc->mscb.rdip; if (prn_ip) { buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, "%s ", inet_ntoa(in)); prn_ip = 0; } buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, " %.3f ms", usec / 1000.0); tv.tv_sec = 0; ok = 99999; break; } //printf("IP %4.4x-%4.4x\n", pc->mscb.dip, pc->mscb.rdip); } } if (!ok && !ctrl_c) { buf_off += snprintf(outbuf + buf_off, sizeof(outbuf) - buf_off, " *"); fflush(stdout); } } printf("%s\n", outbuf); buf_off = 0; i++; if (ok == 99999) break; } return 1; } int run_set(int argc, char **argv) { int value; int fd; pcs *pc = &vpc[pcid]; u_int ip; if (argc < 2 || (argc == 2 && strlen(argv[1]) == 1 && argv[1][0] == '?')) { return help_set(argc, argv); } if (!strncmp("dump", argv[1], strlen(argv[1]))) { if (!strcmp(argv[argc - 1], "?")) return help_set(argc, argv); return set_dump(argc, argv); } if (!strncmp("mtu", argv[1], strlen(argv[1]))) { if (argc == 2 || argc > 3 || (argc == 3 && !digitstring(argv[2]))) { argc = 3; argv[2] = "?"; return help_set(argc, argv); } value = atoi(argv[2]); if (value < 576) { printf("Invalid MTU, should bigger than 576\n"); } else pc->mtu = value; return 1; } if (!strncmp("lport", argv[1], strlen(argv[1]))) { if (argc != 3) { printf("Incomplete command.\n"); return 1; } value = atoi(argv[2]); if (value < 1024 || value > 65000) { printf("Invalid port. 1024 > port < 65000.\n"); } else { fd = open_udp(value); if (fd <= 0) { fd = 0; printf("Device(%d) open error [%s]\n", pcid, strerror(errno)); return 0; } close(pc->fd); pc->fd = fd; pc->lport = value; } } else if (!strncmp("rport", argv[1], strlen(argv[1]))) { if (argc != 3) { printf("Incomplete command.\n"); return 1; } value = atoi(argv[2]); if (value < 1024 || value > 65000) { printf("Invalid port. 1024 > port < 65000.\n"); } else pc->rport = value; } else if (!strncmp("rhost", argv[1], strlen(argv[1]))) { if (argc != 3) { printf("Incomplete command.\n"); return 1; } ip = inet_addr(argv[2]); if (ip == -1) { printf("Invalid address: %s\n", argv[2]); return 0; } pc->rhost = ip; } else if (!strncmp("pcname", argv[1], strlen(argv[1]))) { if (argc != 3) { printf("Incomplete command.\n"); return 1; } if (strlen(argv[2]) > MAX_NAMES_LEN) printf("Hostname is too long. (Maximum %d characters)\n", MAX_NAMES_LEN); else strcpy(vpc[pcid].xname, argv[2]); } else if (!strncmp("echo", argv[1], strlen(argv[1]))) { if (!strcmp(argv[argc - 1], "?")) return help_set(argc, argv); if (argc < 3) { printf("Incomplete command.\n"); return 1; } if (!strcasecmp(argv[2], "on")) { echoctl.enable = 1; } else if (!strcasecmp(argv[2], "off")) { echoctl.enable = 0; } if (argc > 3 && !strcasecmp(argv[2], "color")) { if (argc == 4) { if (!strcasecmp(argv[3], "clear")) { echoctl.fgcolor = 0; echoctl.bgcolor = 0; } else echoctl.fgcolor = str2color(argv[3]); } if (argc == 5) { echoctl.fgcolor = str2color(argv[3]); echoctl.bgcolor = str2color(argv[4]) + 10; } } else if (argc > 4 && !strcasecmp(argv[3], "color")) { if (argc == 5) { if (!strcasecmp(argv[3], "clear")) { echoctl.fgcolor = 0; echoctl.bgcolor = 0; } else echoctl.fgcolor = str2color(argv[4]); } if (argc == 6) { echoctl.fgcolor = str2color(argv[4]); echoctl.bgcolor = str2color(argv[5]) + 10; } } } else printf("Invalid command.\n"); return 1; } int run_sleep(int argc, char **argv) { int t; int ac = argc; int i; t = 0; if (argc == 2) { if (digitstring(argv[1])) { t = atoi(argv[1]); ac = 2; } else ac = 1; } else if (argc > 2) { ac = 1; if (digitstring(argv[1])) { t = atoi(argv[1]); ac = 2; } } if (argc != 1) { for (i = ac; i < argc; i++) printf("%s ", argv[i]); printf("\n"); } if (t == 0) { if (argc == 1) printf("Press any key to continue\n"); kbhit(0); } else sleep(t); return 1; } int run_clear(int argc, char **argv) { u_char mac[6]; if (argc < 2 || (argc == 2 && strlen(argv[1]) == 1 && argv[1][0] == '?')) { return help_clear(argc, argv); } if (!strcmp("ip", argv[1])) { memcpy(mac, vpc[pcid].ip4.mac, 6); memset(&vpc[pcid].ip4, 0, sizeof(vpc[pcid].ip4)); memcpy(&vpc[pcid].ip4.mac, mac, 6); printf("IPv4 address/mask, gateway, DNS, and DHCP cleared\n"); } else if (!strncmp("ipv6", argv[1], strlen(argv[1]))) { memset(&vpc[pcid].ip6, 0, sizeof(vpc[pcid].ip6)); printf("IPv6 address/mask and router link-layer address cleared\n"); } else if (!strncmp("arp", argv[1], strlen(argv[1]))) memset(&vpc[pcid].ipmac4, 0, sizeof(vpc[pcid].ipmac4)); else if (!strncmp("neighbor", argv[1], strlen(argv[1]))) memset(&vpc[pcid].ipmac6, 0, sizeof(vpc[pcid].ipmac6)); else if (!strncmp("hist", argv[1], strlen(argv[1]))) clear_hist(); else printf("Invalid options\n"); return 1; } int run_echo(int argc, char **argv) { int i; if (echoctl.fgcolor != 0) { if (echoctl.bgcolor != 0) printf("\033[%d;%dm", echoctl.fgcolor, echoctl.bgcolor); else printf("\033[%dm", echoctl.fgcolor); } for (i = 1; i < argc; i++) printf("%s ", argv[i]); if (echoctl.fgcolor != 0) printf("\033[0m"); // printf("\n"); return 1; } int run_remote(int argc, char **argv) { if (!strcmp(argv[argc - 1], "?")) return help_rlogin(argc, argv); if (argc == 2) { if (!digitstring(argv[1])) { printf("Invalid port\n"); return help_rlogin(argc, argv); } return open_remote(0, "127.0.0.1", atoi(argv[1])); } else if (argc == 3) { if (!digitstring(argv[2])) { printf("Invalid port\n"); return help_rlogin(argc, argv); } return open_remote(0, argv[1], atoi(argv[2])); } return help_rlogin(argc, argv); } static int set_dump(int argc, char **argv) { int ok = 1; int i = 2; pcs *pc = &vpc[pcid]; int dmpflag = 0; if (argc == 2) ok = 0; while (i < argc) { if (!strncmp(argv[i], "mac", strlen(argv[i]))) dmpflag |= DMP_MAC; else if (!strncmp(argv[i], "raw", strlen(argv[i]))) dmpflag |= DMP_RAW; else if (!strncmp(argv[i], "detail", strlen(argv[i]))) dmpflag |= DMP_DETAIL; else if (!strncmp(argv[i], "all", strlen(argv[i]))) dmpflag |= DMP_ALL; else if (!strncmp(argv[i], "file", strlen(argv[i]))) { if (pc->dmpfile == NULL) { char tfname[1024]; sprintf(tfname, "vpcs%d", pc->id + 1); pc->dmpfile = open_dmpfile(tfname); } dmpflag |= DMP_FILE; } else if (!strncmp(argv[i], "off", strlen(argv[i]))) { dmpflag = 0; /* give pthread reader/writer a little time */ usleep(1000); if (pc->dmpfile) { close_dmpfile(pc->dmpfile); pc->dmpfile = NULL; } } else { printf("Invalid options\n"); ok = 0; break; } i++; } if (ok) { if (dmpflag == 0) pc->dmpflag = 0; else pc->dmpflag |= dmpflag; printf("\ndump flags:"); if (pc->dmpflag & DMP_MAC) printf(" mac"); if (pc->dmpflag & DMP_RAW) printf(" raw"); if (pc->dmpflag & DMP_DETAIL) printf(" detail"); if (pc->dmpflag & DMP_ALL) printf(" all"); if (pc->dmpflag & DMP_FILE) printf(" file"); if (pc->dmpflag == 0) printf(" (none)"); printf("\n"); return 1; } return 1; } int show_arp(int argc, char **argv) { pcs *pc; int i, j; struct in_addr in; char buf[19]; u_char zero[ETH_ALEN] = {0}; int empty = 1; int si; printf("\n"); if (argc == 3) { if (!strncmp(argv[2], "all", strlen(argv[2]))) { for (si = 0; si < num_pths; si++) { pc = &vpc[si]; printf("%s[%d]:\n", pc->xname, si + 1); for (i = 0; i < POOL_SIZE; i++) { if (pc->ipmac4[i].ip == 0) continue; if (memcmp(pc->ipmac4[i].mac, zero, ETH_ALEN) == 0) continue; if (time_tick - pc->ipmac4[i].timeout > POOL_TIMEOUT) continue; for (j = 0; j < 6; j++) sprintf(buf + j * 3, "%2.2x:", pc->ipmac4[i].mac[j]); buf[17] = '\0'; in.s_addr = pc->ipmac4[i].ip; printf("%s %s expires in %d seconds \n", buf, inet_ntoa(in), POOL_TIMEOUT - (time_tick - pc->ipmac4[i].timeout)); empty = 0; } if (empty) printf("arp table is empty\n"); } return 1; } else if (strlen(argv[2]) == 1 && digitstring(argv[2])) { si = atoi(argv[2]) - 1; if (si < 0) { printf("Invalid ID\n"); return 1; } } else { printf("Invalid ID\n"); return 1; } } else { si = pcid; } if (si != pcid) printf("%s[%d]:\n", vpc[si].xname, si + 1); pc = &vpc[si]; for (i = 0; i < POOL_SIZE; i++) { if (pc->ipmac4[i].ip == 0) continue; if (etherIsZero(pc->ipmac4[i].mac)) continue; if (time_tick - pc->ipmac4[i].timeout < POOL_TIMEOUT) { for (j = 0; j < 6; j++) sprintf(buf + j * 3, "%2.2x:", pc->ipmac4[i].mac[j]); buf[17] = '\0'; in.s_addr = pc->ipmac4[i].ip; printf("%s %s expires in %d seconds \n", buf, inet_ntoa(in), POOL_TIMEOUT - (time_tick - pc->ipmac4[i].timeout)); empty = 0; } } if (empty) printf("arp table is empty\n"); return 1; } static int show_dump(int argc, char **argv) { int i; pcs *pc = &vpc[pcid]; printf("\n"); if (argc == 3) { if (!strncmp(argv[2], "all", strlen(argv[2]))) { for (i = 0; i < num_pths; i++) { printf("%s[%d] dumpflag:", vpc[i].xname, i + 1); if (vpc[i].dmpflag & DMP_MAC) printf(" mac"); if (vpc[i].dmpflag & DMP_RAW) printf(" raw"); if (vpc[i].dmpflag & DMP_DETAIL) printf(" detail"); if (vpc[i].dmpflag & DMP_ALL) printf(" all"); if (vpc[i].dmpflag & DMP_FILE) printf(" file"); if (vpc[i].dmpflag == 0) printf(" (none)"); printf("\n"); } return 1; } if (strlen(argv[2]) == 1 && digitstring(argv[2])) { i = atoi(argv[2]) - 1; pc = &vpc[i]; } else { printf( "\033[1mshow dump [all]\033[0m\n" " all all vpc's dump flags\n"); } return 1; } printf("dump flags:"); if (pc->dmpflag & DMP_MAC) printf(" mac"); if (pc->dmpflag & DMP_RAW) printf(" raw"); if (pc->dmpflag & DMP_DETAIL) printf(" detail"); if (pc->dmpflag & DMP_ALL) printf(" all"); if (pc->dmpflag & DMP_FILE) printf(" file"); if (pc->dmpflag == 0) printf(" (none)"); printf("\n"); return 1; } static int show_ip(int argc, char **argv) { int i, j, k; struct in_addr in; char buf[128]; int id = -1; if (argc == 3) { if (!strncmp(argv[2], "all", strlen(argv[2]))) { memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); j = sprintf(buf, "NAME"); buf[j] = ' '; j = sprintf(buf + 7, "IP/MASK"); buf[j + 7] = ' '; j = sprintf(buf + 28, "GATEWAY"); buf[j + 28] = ' '; j = sprintf(buf + 46, "MAC"); buf[j + 46] = ' '; j = sprintf(buf + 65, "DNS"); printf("\n%s\n", buf); for (i = 0; i < num_pths; i++) { memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); if (strcmp(vpc[i].xname, "VPCS")== 0) j = sprintf(buf, "%s%d", vpc[i].xname, i + 1); else j = sprintf(buf, "%s", vpc[i].xname); buf[j] = ' '; in.s_addr = vpc[i].ip4.ip; j = sprintf(buf + 7, "%s/%d", inet_ntoa(in), vpc[i].ip4.cidr); buf[j + 7] = ' '; in.s_addr = vpc[i].ip4.gw; j = sprintf(buf + 28, "%s", inet_ntoa(in)); buf[j + 28] = ' '; for (k = 0; k < 6; k++) sprintf(buf + 46 + k * 3, "%2.2x:", vpc[i].ip4.mac[k]); buf[63] = ' '; buf[64] = ' '; buf[65] = '\0'; k = 65; if (vpc[i].ip4.dns[0]) { in.s_addr = vpc[i].ip4.dns[0]; j = sprintf(buf + k, "%s", inet_ntoa(in)); } if (vpc[i].ip4.dns[1]) { in.s_addr = vpc[i].ip4.dns[1]; buf[j + 65] = ' '; k = j + 66; j = sprintf(buf + k, "%s", inet_ntoa(in)); } printf("%s\n", buf); } return 1; } if (strlen(argv[2]) == 1 && digitstring(argv[2])){ id = argv[2][0] - '1'; } } else if (argc == 2) id = pcid; if (id != -1) { printf("\n"); printf("NAME : %s[%d]\n", vpc[id].xname, id + 1); in.s_addr = vpc[id].ip4.ip; printf("IP/MASK : %s/%d\n", inet_ntoa(in), vpc[id].ip4.cidr); in.s_addr = vpc[id].ip4.gw; printf("GATEWAY : %s\n", inet_ntoa(in)); printf("DNS : "); if (vpc[id].ip4.dns[0]) { in.s_addr = vpc[id].ip4.dns[0]; printf("%s ", inet_ntoa(in)); } if (vpc[id].ip4.dns[1]) { in.s_addr = vpc[id].ip4.dns[1]; printf("%s", inet_ntoa(in)); } printf("\n"); if (vpc[id].ip4.dhcp.svr) { in.s_addr = vpc[id].ip4.dhcp.svr; printf("DHCP SERVER : %s\n", inet_ntoa(in)); k = time_tick - vpc[id].ip4.dhcp.timetick; k = vpc[id].ip4.dhcp.lease - k; printf("DHCP LEASE : %d, %u/%u/%u\n", k > 0 ? k : 0, vpc[id].ip4.dhcp.lease, vpc[id].ip4.dhcp.renew, vpc[id].ip4.dhcp.rebind); } if (vpc[id].ip4.domain[0]) { printf("DOMAIN NAME : %s\n", vpc[id].ip4.domain); } else if (vpc[id].ip4.dhcp.domain[0]) { printf("DOMAIN NAME : %s\n", vpc[id].ip4.dhcp.domain); } printf("MAC : "); PRINT_MAC(vpc[id].ip4.mac); printf("\n"); printf("LPORT : %d\n", vpc[id].lport); in.s_addr = vpc[id].rhost; printf("RHOST:PORT : %s:%d\n", inet_ntoa(in), vpc[id].rport); printf("MTU : %d\n", vpc[id].mtu); return 1; } argv[argc - 1 ] = "?"; help_show(argc, argv); return 1; } static int show_echo(int argc, char **argv) { printf("\n"); esc_prn("Echo {H%s}\n", (echoctl.enable) ? "On" : "Off"); printf("Foreground color: %s\n", (echoctl.fgcolor >= 30 && echoctl.fgcolor <= 37) ? color_name[echoctl.fgcolor - 30] : "default"); printf("Background color: %s\n", (echoctl.bgcolor >= 40 && echoctl.bgcolor <= 47) ? color_name[echoctl.bgcolor - 40] : "default"); return 1; } int run_ver(int argc, char **argv) { printf ("\r\n" "Welcome to Virtual PC Simulator, version %s\r\n" "Dedicated to Daling.\r\n" "Build time: %s %s\r\n" "Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com)\r\n" "All rights reserved.\r\n\r\n" "VPCS is free software, distributed under the terms of the \"BSD\" licence.\r\n" "Source code and license can be found at vpcs.sf.net.\r\n" "For more information, please visit wiki.freecode.com.cn.\r\n", ver, __DATE__, __TIME__ ); return 1; } int run_hist(int argc, char **argv) { int i; for (i = 0; i < rls->hist_total; i++) printf("%s\n", rls->history[i]); return 1; } int run_load(int argc, char **argv) { FILE *fp; char buf[MAX_LEN]; char fname[PATH_MAX]; char *filename = "startup.vpc"; if (argc > 2 || (argc == 2 && !strcmp(argv[1], "?"))) { return help_load(argc, argv); } else if (argc == 2) { filename = argv[1]; } fp = fopen(filename, "r"); if (fp == NULL) { /* try to open .vpc */ if (!strrchr(filename, '.') && (strlen(filename) < PATH_MAX - 5)) { memset(fname, 0, PATH_MAX); strncpy(fname, filename, PATH_MAX - 1); strcat(fname, ".vpc"); fp = fopen(fname, "r"); } } if (fp == NULL) { printf("Can't open \"%s\"\n", filename); return -1; } if (runStartup) printf("\nExecuting the startup file\n"); else printf("\nExecuting the file \"%s\"\n", filename); while (!feof(fp) && !ctrl_c) { runLoad = 1; if (fgets(buf, MAX_LEN, fp) == NULL) break; ttrim(buf); /* if (buf[strlen(buf) - 1] == '\n') { buf[strlen(buf) - 1] = '\0'; if (buf[strlen(buf) - 1] == '\r') buf[strlen(buf) - 1] = '\0'; }*/ if (buf[0] == '#' || buf[0] == ';') continue; if (strlen(buf) > 0) parse_cmd(buf); } runLoad = 0; fclose(fp); return 1; } int run_save(int argc, char **argv) { FILE *fp; int i; char *p; char buf[64]; u_int local_ip; struct in_addr in; char fname[PATH_MAX]; memset(fname, 0, PATH_MAX); if (argc > 2 || (argc == 2 && !strcmp(argv[1], "?"))) { return help_save(argc, argv); } else if (argc == 1) { strncpy(fname, default_startupfile, PATH_MAX - 1); } else { if (strlen(argv[1]) > PATH_MAX - 5) { printf("%s is too long\n", argv[1]); return 1; } else { strncpy(fname, argv[1], PATH_MAX - 1); } } if (!strrchr(fname, '.')) strcat(fname, ".vpc"); fp = fopen(fname, "w"); if (fp == NULL) { printf("failed: %s\n", strerror(errno)); return 1; } printf("Saving startup configuration to %s\n", fname); local_ip = inet_addr("127.0.0.1"); for (i = 0; i < num_pths; i++) { if (num_pths > 1) fprintf(fp, "%d\n", i + 1); sprintf(buf, "VPCS[%d]", i + 1); //if (strncmp(vpc[i].xname, buf, 6)) fprintf(fp, "set pcname %s\n", vpc[i].xname); if (num_pths > 1) { if (vpc[i].lport != (20000 + i)) fprintf(fp, "set lport %d\n", vpc[i].lport); if (vpc[i].rport != (30000 + i)) fprintf(fp, "set rport %d\n", vpc[i].rport); if (vpc[i].rhost != local_ip) { in.s_addr = vpc[i].rhost; fprintf(fp, "set rhost %s\n", inet_ntoa(in)); } } if (vpc[i].ip4.dynip == 1) fputs("dhcp\n", fp); else { p = (char *)ip4Info(i); if (p != NULL) fprintf(fp, "%s\n", p); p = (char *)ip6Info(i); if (p != NULL) fprintf(fp, "%s\n", p); if (vpc[i].ip4.domain[0]) fprintf(fp, "ip domain %s\n", vpc[i].ip4.domain); if (vpc[i].ip4.dns[0]) { in.s_addr = vpc[i].ip4.dns[0]; fprintf(fp, "ip dns %s", inet_ntoa(in)); if (vpc[i].ip4.dns[1]) { in.s_addr = vpc[i].ip4.dns[1]; fprintf(fp, " %s", inet_ntoa(in)); } fprintf(fp, "\n"); } } if (vpc[i].ip6auto == 1) fputs("ip auto\n", fp); if (vpc[i].mtu != 1500) fprintf(fp, "set mtu %d\n", vpc[i].mtu); printf("."); } save_relay(fp); if (num_pths > 1) fprintf(fp, "1\n"); fclose(fp); printf(" done\n"); return 1; } const char *ip4Info(const int id) { struct in_addr in; static char buf[128]; int pos = 0; memset(buf, 0, sizeof(buf)); if (vpc[id].ip4.ip != 0) { in.s_addr = vpc[id].ip4.ip; pos = sprintf(buf, "ip %s", (char*)inet_ntoa(in)); in.s_addr = vpc[id].ip4.gw; if (vpc[id].ip4.gw != 0) { in.s_addr = vpc[id].ip4.gw; pos += sprintf(buf + pos, " %s", inet_ntoa(in)); } sprintf(buf + pos, " %d", vpc[id].ip4.cidr); } else return NULL; return buf; } int str2color(const char *cstr) { int i; for (i = 0; i < 8; i++) if (!strncasecmp(cstr, color_name[i], strlen(color_name[i]))) break; if (i == 8) return 0; else return 30 + i; } /* end of file */ vpcs-0.8.3/src/command.h000066400000000000000000000037621447703427300150760ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _CMD_H_ #define _CMD_H_ int run_dhcp(int argc, char **argv); int run_show(int argc, char **argv); int run_ping(int argc, char **argv); int run_ipconfig(int argc, char **argv); int run_tracert(int argc, char **argv); int run_set(int argc, char **argv); int run_sleep(int argc, char **argv); int run_clear(int argc, char **argv); int run_echo(int argc, char **argv); int run_ver(int argc, char **argv); int run_hist(int argc, char **argv); int run_remote(int argc, char **argv); int run_load(int argc, char **argv); int run_save(int argc, char **argv); const char *ip4Info(const int id); #endif /* end of file */ vpcs-0.8.3/src/command6.c000066400000000000000000000556331447703427300151630ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include "globle.h" #include "command6.h" #include "utils.h" #include "vpcs.h" #include "dev.h" #include "packets6.h" #include "queue.h" #include "tcp.h" #include "help.h" extern int pcid; extern int devtype; extern int ctrl_c; extern u_int time_tick; extern int num_pths; int run_net6(char *cmdstr); #include "inet6.h" extern int vinet_pton6(int af, const char * __restrict src, void * __restrict dst); extern const char *vinet_ntop6(int af, const void *src, char *dst, socklen_t cnt); /* ping host , char *cmdstr*/ int run_ping6(int argc, char **argv) { pcs *pc = &vpc[pcid]; struct in6_addr ipaddr; struct packet *m = NULL; int i; char proto_seq[16]; int count = 5; printf("\n"); i = 2; for (i = 2; i < argc; i++) { if (!strcmp(argv[i], "-c")) { if ((i + 1) < argc && digitstring(argv[i + 1])) count = atoi(argv[i + 1]); break; } } if (vinet_pton6(AF_INET6, argv[1], &ipaddr) != 1) { printf("Invalid address: %s\n", argv[1]); return 0; } memcpy(pc->mscb.dip6.addr8, ipaddr.s6_addr, 16); if (pc->mscb.dip6.addr16[0] != IPV6_ADDR_INT16_ULL) memcpy(pc->mscb.sip6.addr8, pc->ip6.ip.addr8, 16); else memcpy(pc->mscb.sip6.addr8, pc->link6.ip.addr8, 16); /* ping self, discard options */ if (IP6EQ(&pc->mscb.sip6, &pc->mscb.dip6)) { i = 1; while (i < 6) { printf("%s icmp_seq=%d ttl=%d time=0.001 ms\n", argv[1], i++, pc->mscb.ttl); delay_ms(1); } return 1; } /* find destination */ char *p = (char*)nbDiscovery(pc, &pc->mscb.dip6); if (p == NULL) { printf("host (%s) not reachable\n", argv[1]); return 0; } memcpy(pc->mscb.dmac, p, 6); if (pc->mscb.proto == IPPROTO_ICMP) { pc->mscb.proto = IPPROTO_ICMPV6; strcpy(proto_seq, "icmp6_seq"); } else if (pc->mscb.proto == IPPROTO_TCP) { strcpy(proto_seq, "tcp6_seq"); } else if (pc->mscb.proto == IPPROTO_UDP) { strcpy(proto_seq, "udp6_seq"); } if (pc->mscb.proto == IPPROTO_TCP && pc->mscb.flags == 0) { i = 0; while ((i++ < count || count == -1) && !ctrl_c) { struct timeval ts0, ts; int usec; int k; int dsize = pc->mscb.dsize; int traveltime = 1; if (i > 1) delay_ms(pc->mscb.waittime); /* clear the input queue */ while ((m = deq(&pc->iq)) != NULL); /* connect the remote */ gettimeofday(&(ts), (void*)0); k = tcp_open(pc, IPV6_VERSION); /* restore data size */ pc->mscb.dsize = dsize; gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; if (usec < 0) usec = 0; if (k == 0) { printf("Connect %d@%s timeout\n", pc->mscb.dport, argv[1]); continue; } else if (k == 2) { char buf[INET6_ADDRSTRLEN + 1]; memset(buf, 0, sizeof(buf)); vinet_ntop6(AF_INET6, &pc->mscb.rdip6, buf, INET6_ADDRSTRLEN + 1); printf("*%s %s=%d ttl=%d time=%.3f ms", buf, proto_seq, i++, pc->mscb.rttl, usec / 1000.0); printf(" (ICMP type:%d, code:%d, %s)\n", pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode)); continue; } else if (k == 3) { printf("Connect %d@%s RST returned\n", pc->mscb.dport, argv[1]); continue; } printf("Connect %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); traveltime = 0.6 * usec / 1000; /* send data */ delay_ms(traveltime); gettimeofday(&(ts), (void*)0); k = tcp_send(pc, IPV6_VERSION); if (k == 0) { printf("SendData %d@%s timeout\n", pc->mscb.dport, argv[1]); continue; } gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; if (usec < 0) usec = 0; printf("SendData %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); /* close */ if (k != 2) delay_ms(traveltime); gettimeofday(&(ts), (void*)0); k = tcp_close(pc, IPV6_VERSION); if (k == 0) { printf("Close %d@%s timeout\n", pc->mscb.dport, argv[1]); continue; } gettimeofday(&(ts0), (void*)0); usec = (ts0.tv_sec - ts.tv_sec) * 1000000 + ts0.tv_usec - ts.tv_usec; if (usec < 0) usec = 0; printf("Close %d@%s seq=%d ttl=%d time=%.3f ms\n", pc->mscb.dport, argv[1], i, pc->mscb.rttl, usec / 1000.0); } } else { i = 1; while ((i <= count || count == -1) && !ctrl_c) { struct packet *packet; struct timeval tv; int usec; int respok = 0; if (i > 1) delay_ms(pc->mscb.waittime); new_mtu6: pc->mscb.sn = i; pc->mscb.timeout = time_tick; m = packet6(pc); if (m == NULL) { printf("out of memory\n"); return false; } gettimeofday(&(tv), (void*)0); enq(&pc->oq, m); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); respok = 0; while ((packet = deq(&pc->iq)) != NULL && !respok && !timeout(tv, pc->mscb.waittime) && !ctrl_c) { pc->mscb.icmptype = pc->mscb.icmpcode = 0; respok = response6(packet, &pc->mscb); usec = (packet->ts.tv_sec - tv.tv_sec) * 1000000 + packet->ts.tv_usec - tv.tv_usec; if (usec < 0) usec = 0; del_pkt(packet); if (respok == 0) continue; tv.tv_sec = 0; if ((pc->mscb.proto == IPPROTO_ICMPV6 && pc->mscb.icmptype == ICMP6_ECHO_REPLY) || (pc->mscb.proto == IPPROTO_UDP && respok == IPPROTO_UDP)|| (pc->mscb.proto == IPPROTO_TCP && respok == IPPROTO_TCP)) { printf("%s %s=%d ttl=%d time=%.3f ms\n", argv[1], proto_seq, i++, pc->mscb.rttl, usec / 1000.0); break; } if (respok == IPPROTO_ICMPV6) { char buf[INET6_ADDRSTRLEN + 1]; memset(buf, 0, sizeof(buf)); vinet_ntop6(AF_INET6, &pc->mscb.rdip6, buf, INET6_ADDRSTRLEN + 1); printf("*%s %s=%d ttl=%d time=%.3f ms", buf, proto_seq, i, pc->mscb.rttl, usec / 1000.0); if (pc->mscb.icmptype == ICMP6_PACKET_TOO_BIG) { printf(" (new MTU %d)\n", pc->mscb.mtu); goto new_mtu6; } printf(" (ICMP type:%d, code:%d, %s)\n", pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode)); i++; break; } } } if (!respok && !ctrl_c) printf("%s %s=%d timeout\n", argv[1], proto_seq, i++); } } return 1; } int ipauto6(void) { struct packet *m = NULL; char buf6[INET6_ADDRSTRLEN + 1]; struct in6_addr ipaddr; int n = 100; m = nbr_sol(&vpc[pcid]); vpc[pcid].ip6auto = 1; if (m != NULL) enq(&vpc[pcid].oq, m); do { usleep(10000); if (vpc[pcid].ip6.ip.addr32[0] != 0 || vpc[pcid].ip6.ip.addr32[1] != 0 || vpc[pcid].ip6.ip.addr32[2] != 0 || vpc[pcid].ip6.ip.addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[pcid].ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("GLOBAL SCOPE : %s/%d\n", buf6, vpc[pcid].ip6.cidr); printf("ROUTER LINK-LAYER : "); PRINT_MAC(vpc[pcid].ip6.gmac); printf("\n"); return 1; } } while (--n > 0); printf("No router answered ICMPv6 Router Solicitation\n"); return 1; } int run_ipset6(int argc, char **argv) { char buf[INET6_ADDRSTRLEN + 1]; pcs *pc = &vpc[pcid]; struct in6_addr ipaddr; int hasMask = 0; struct packet *m; int eui64 = 0; switch (argc) { case 1: run_show6(pc); return 1; case 4: if (!strcasecmp(argv[3], "eui-64") || !strcasecmp(argv[3], "eui64")) eui64 = 1; case 3: if (!strcasecmp(argv[2], "eui-64") || !strcasecmp(argv[2], "eui64")) eui64 = 1; else { pc->ip6.cidr = atoi(argv[2]); if (pc->ip6.cidr == 0) pc->ip6.cidr = 64; hasMask = 1; } case 2: if (!hasMask) pc->ip6.cidr = 64; if (vinet_pton6(AF_INET6, argv[1], &ipaddr) == 1) { vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1); memcpy(pc->ip6.ip.addr8, ipaddr.s6_addr, 16); if (eui64) { pc->ip6.ip.addr8[15] = pc->ip4.mac[5]; pc->ip6.ip.addr8[14] = pc->ip4.mac[4]; pc->ip6.ip.addr8[13] = pc->ip4.mac[3]; pc->ip6.ip.addr8[12] = 0xfe; pc->ip6.ip.addr8[11] = 0xff; pc->ip6.ip.addr8[10] = pc->ip4.mac[2]; pc->ip6.ip.addr8[9] = pc->ip4.mac[1]; pc->ip6.ip.addr8[8] = (pc->ip4.mac[0] &0x20) ? pc->ip4.mac[0] & 0xef : (pc->ip4.mac[0] | 0x20); pc->ip6.type = IP6TYPE_EUI64; } else pc->ip6.type = IP6TYPE_NONE; memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, pc->ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf,INET6_ADDRSTRLEN + 1); printf("PC%d : %s/%d %s\n", pcid + 1, buf, pc->ip6.cidr, (pc->ip6.type == IP6TYPE_EUI64) ? "eui-64" : ""); m = nbr_sol(pc); if (m == NULL) { printf("out of memory\n"); return 1; } enq(&pc->oq, m); } else { printf("Invalid ipv6 address.\n"); } break; default: printf("Invalid.\n"); break; } return 1; } int run_tracert6(int argc, char **argv) { int i, j; struct packet *m; pcs *pc = &vpc[pcid]; u_char *dmac; int ok = 0; struct in6_addr ipaddr; ip6 ip; int pktnum = 3; int count = 99; printf("\n"); if (argc < 2) { printf("incompleted command.\n"); return 0; } i = 2; for (i = 2; i < argc; i++) { if (!strcmp(argv[i], "-c")) { if ((i + 1) < argc && digitstring(argv[i + 1])) count = atoi(argv[i + 1]); break; } } if (count == 99 && digitstring(argv[argc - 1])) count = atoi(argv[argc - 1]); if (optind < argc && digitstring(argv[optind])) count = atoi(argv[optind]); if (count < 1 || count > 64) count = 64; if (vinet_pton6(AF_INET6, argv[1], &ipaddr) != 1) { printf("Invalid address: %s\n", argv[1]); return 0; } memcpy(pc->mscb.dip6.addr8, ipaddr.s6_addr, 16); if (pc->mscb.dip6.addr16[0] != IPV6_ADDR_INT16_ULL) memcpy(pc->mscb.sip6.addr8, pc->ip6.ip.addr8, 16); else memcpy(pc->mscb.sip6.addr8, pc->link6.ip.addr8, 16); dmac = nbDiscovery(pc, &ip); if (dmac == NULL) { printf("host (%s) not reachable\n", argv[1]); return 0; } memcpy(pc->mscb.dmac, dmac, 6); printf("trace to %s, %d hops max\n", argv[1], count); /* send the udp packets */ i = 1; while (i <= count && !ctrl_c) { struct packet *p; struct timeval tv; u_int usec; int k; printf("%2d ", i); for (j = 0; j < pktnum && !ctrl_c; j++) { pc->mscb.ttl = i; m = packet6(pc); if (m == NULL) { printf("out of memory\n"); return 0; } gettimeofday(&(tv), (void*)0); enq(&pc->oq, m); k = 0; while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); ok = 0; while ((p = deq(&pc->iq)) != NULL && !ok && !timeout(tv, pc->mscb.waittime) && !ctrl_c) { ok = response6(p, &pc->mscb); usec = (p->ts.tv_sec - tv.tv_sec) * 1000000 + p->ts.tv_usec - tv.tv_usec; del_pkt(p); if (pc->mscb.icmptype == ICMP6_TIME_EXCEEDED || IP6EQ(&(pc->mscb.dip6), &(pc->mscb.rdip6))) { if (j == 0) { char buf[128]; memcpy(ipaddr.s6_addr, pc->mscb.rdip6.addr8, 16); memset(buf, 0, 128); vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1); printf("%s ", buf); } printf(" %.3f ms", usec / 1000.0);fflush(stdout); tv.tv_sec = 0; break; } else if (pc->mscb.icmptype == ICMP6_DST_UNREACH || pc->mscb.icmptype == ICMP6_DST_UNREACH_NOPORT) { if (j == 0) { char buf[128]; memcpy(ipaddr.s6_addr, pc->mscb.rdip6.addr8, 16); memset(buf, 0, 128); vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1); printf("*%s %.3f ms (ICMP type:%d, code:%d, %s)\n", buf, usec / 1000.0, pc->mscb.icmptype, pc->mscb.icmpcode, icmpTypeCode2String(6, pc->mscb.icmptype, pc->mscb.icmpcode)); } tv.tv_sec = 0; return 1; } } k++; } if (!ok && !ctrl_c) printf(" *"); } printf("\n"); i++; if (pc->mscb.icmptype == ICMP6_DST_UNREACH) break; } return 1; } int run_show6(pcs *pc) { char buf[INET6_ADDRSTRLEN + 1]; struct in6_addr ipaddr; memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, pc->link6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf,INET6_ADDRSTRLEN + 1); printf(" %s/%d\n", buf, pc->link6.cidr); if (pc->ip6.ip.addr32[0] != 0 || pc->ip6.ip.addr32[1] != 0 || pc->ip6.ip.addr32[2] != 0 || pc->ip6.ip.addr32[3] != 0) { memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, pc->ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf,INET6_ADDRSTRLEN + 1); printf(" %s/%d %s\n", buf, pc->ip6.cidr, (pc->ip6.type == IP6TYPE_EUI64) ? "eui-64" : ""); } return 1; } int run_ipdns6(int argc, char **argv) { pcs *pc = &vpc[pcid]; struct in6_addr ipaddr; if (!strcmp(argv[argc - 1] , "?")) return help_ip(argc, argv); if (argc == 3) { if (!strcmp(argv[2], "0")) { memset(pc->ip6.dns[0].addr8, 0, 16); return 1; } if (vinet_pton6(AF_INET6, argv[2], &ipaddr) != 1) { printf("Invalid address: %s\n", argv[2]); return 0; } memcpy(pc->ip6.dns[0].addr8, ipaddr.s6_addr, 16); } if (argc == 4) { if (!strcmp(argv[2], "0")) { memset(pc->ip6.dns[0].addr8, 0, 16); return 1; } if (vinet_pton6(AF_INET6, argv[2], &ipaddr) != 1) { printf("Invalid address: %s\n", argv[2]); return 0; } memcpy(pc->ip6.dns[0].addr8, ipaddr.s6_addr, 16); if (!strcmp(argv[3], "0")) { memset(pc->ip6.dns[1].addr8, 0, 16); return 1; } if (vinet_pton6(AF_INET6, argv[3], &ipaddr) != 1) { printf("Invalid address: %s\n", argv[3]); return 0; } memcpy(pc->ip6.dns[1].addr8, ipaddr.s6_addr, 16); } return 1; } int show_ipv6(int argc, char **argv) { int i, j, k; char buf[128]; char buf6[INET6_ADDRSTRLEN + 1]; struct in6_addr ipaddr; struct in_addr in; int off1, off2, off3; int max6 = 0; int id = -1; printf("\n"); if (argc == 3) { if (!strncmp(argv[2], "all", strlen(argv[2]))) { for (i = 0; i < num_pths; i++) { if (vpc[i].ip6.ip.addr32[0] != 0 || vpc[i].ip6.ip.addr32[1] != 0 || vpc[i].ip6.ip.addr32[2] != 0 || vpc[i].ip6.ip.addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[i].ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); j = sprintf(buf, "%s/%d", buf6, vpc[i].ip6.cidr); if (j > max6) max6 = j; } } memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); off1 = 7; off2 = off1 + max6 + 2; off3 = off2 + 17 + 2; j = sprintf(buf, "NAME"); buf[j] = ' '; j = sprintf(buf + off1, "IP/MASK"); buf[j + off1] = ' '; j = sprintf(buf + off2, "ROUTER LINK-LAYER"); buf[j + off2] = ' '; j = sprintf(buf + off3, "MTU"); printf("%s\n", buf); for (i = 0; i < num_pths; i++) { memset(buf, 0, sizeof(buf)); memset(buf, ' ', sizeof(buf) - 1); if (strcmp(vpc[i].xname, "VPCS")== 0) j = sprintf(buf, "%s%d", vpc[i].xname, i + 1); else j = sprintf(buf, "%s", vpc[i].xname); buf[j] = ' '; memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[i].link6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); sprintf(buf + 7, "%s/%d", buf6, vpc[i].link6.cidr); j = printf("%s", buf); if (vpc[i].ip6.ip.addr32[0] != 0 || vpc[i].ip6.ip.addr32[1] != 0 || vpc[i].ip6.ip.addr32[2] != 0 || vpc[i].ip6.ip.addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[i].ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("\n"); for (k = 0; k < off1; k++) printf(" "); j = printf("%s/%d", buf6, vpc[i].ip6.cidr); j += off1; } for (k = j; k < off2; k++) printf(" "); if (etherIsZero(vpc[i].ip6.gmac)) { j = sprintf(buf, " "); } else { j = 0; for (k = 0; k < 6; k++) j += sprintf(buf + k * 3, "%2.2x:", vpc[i].ip6.gmac[k]); } buf[j - 1] = ' '; if (vpc[i].mtu) j += sprintf(buf + j, " %4.4d", vpc[i].mtu); else j += sprintf(buf + j, " "); //buf[j] = ' '; printf("%s\n", buf); } return 1; } if (strlen(argv[2]) == 1 && digitstring(argv[2])){ id = argv[2][0] - '1'; } } else if (argc == 2) id = pcid; if (id != -1) { printf("NAME : %s[%d]\n", vpc[id].xname, id + 1); printf("LINK-LOCAL SCOPE : "); memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[id].link6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("%s/%d\n", buf6, vpc[id].link6.cidr); printf("GLOBAL SCOPE : "); if (vpc[id].ip6.ip.addr32[0] != 0 || vpc[id].ip6.ip.addr32[1] != 0 || vpc[id].ip6.ip.addr32[2] != 0 || vpc[id].ip6.ip.addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[id].ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("%s/%d", buf6, vpc[id].ip6.cidr); } printf("\n"); printf("DNS : "); if (vpc[id].ip6.dns[0].addr32[0] != 0 || vpc[id].ip6.dns[0].addr32[1] != 0 || vpc[id].ip6.dns[0].addr32[2] != 0 || vpc[id].ip6.dns[0].addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[id].ip6.dns[0].addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("%s", buf6); } if (vpc[id].ip6.dns[1].addr32[0] != 0 || vpc[id].ip6.dns[1].addr32[1] != 0 || vpc[id].ip6.dns[1].addr32[2] != 0 || vpc[id].ip6.dns[1].addr32[3] != 0) { memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[id].ip6.dns[1].addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf(" %s", buf6); } printf("\n"); printf("ROUTER LINK-LAYER : "); if (!etherIsZero(vpc[id].ip6.gmac)) PRINT_MAC(vpc[id].ip6.gmac); printf("\n"); printf("MAC : "); PRINT_MAC(vpc[id].ip4.mac); printf("\n"); printf("LPORT : %d\n", vpc[id].lport); in.s_addr = vpc[id].rhost; printf("RHOST:PORT : %s:%d\n", inet_ntoa(in), vpc[id].rport); printf("MTU: : "); if (vpc[id].mtu) printf("%d", vpc[id].mtu); printf("\n"); return 1; } argv[argc - 1 ] = "?"; help_show(argc, argv); return 1; } void show_pc_mtu6(pcs *pc) { int i; char buf6[INET6_ADDRSTRLEN + 1]; struct in6_addr ipaddr; int empty = 1; for (i = 0; i < POOL_SIZE; i++) { if (IP6ZERO(&(pc->ip6mtu[i].ip))) continue; if (time_tick - pc->ip6mtu[i].timeout > POOL_TIMEOUT) continue; memset(buf6, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, pc->ip6mtu[i].ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf6, INET6_ADDRSTRLEN + 1); printf("%5d\t%3d\t%s/%d\n", pc->ip6mtu[i].mtu, POOL_TIMEOUT - (time_tick - pc->ip6mtu[i].timeout), buf6, pc->link6.cidr); empty = 0; } if (empty) printf("IPV6 MTU table is empty\n"); } int show_mtu6(int argc, char **argv) { pcs *pc; int si; printf("\n"); if (argc == 3) { if (!strncmp(argv[2], "all", strlen(argv[2]))) { for (si = 0; si < num_pths; si++) { pc = &vpc[si]; printf("%s[%d]:\n", pc->xname, si + 1); show_pc_mtu6(pc); } return 1; } else if (strlen(argv[2]) == 1 && digitstring(argv[2])) { si = atoi(argv[2]) - 1; if (si < 0) { printf("Invalid ID\n"); return 1; } } else { printf("Invalid ID\n"); return 1; } } else { si = pcid; } if (si != pcid) printf("%s[%d]:\n", vpc[si].xname, si + 1); pc = &vpc[si]; show_pc_mtu6(pc); return 1; } int run_nb6(int argc, char **argv) { pcs *pc = &vpc[pcid]; char buf[INET6_ADDRSTRLEN + 1]; struct in6_addr ipaddr; int i, j; printf("\n"); for (i = 0; i < POOL_SIZE; i++) { if (pc->ipmac6[i].timeout > 0) { for (j = 0; j < 6; j++) sprintf(buf + j * 3, "%2.2x:", pc->ipmac6[i].mac[j]); buf[17] = '\0'; printf("%s", buf); memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, pc->ipmac6[i].ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, buf,INET6_ADDRSTRLEN + 1); printf(" %s/%d\n", buf, pc->ipmac6[i].cidr); } } return 1; } void locallink6(pcs *pc) { pc->link6.ip.addr8[15] = pc->ip4.mac[5]; pc->link6.ip.addr8[14] = pc->ip4.mac[4]; pc->link6.ip.addr8[13] = pc->ip4.mac[3]; pc->link6.ip.addr8[12] = 0xfe; pc->link6.ip.addr8[11] = 0xff; pc->link6.ip.addr8[10] = pc->ip4.mac[2]; pc->link6.ip.addr8[9] = pc->ip4.mac[1]; pc->link6.ip.addr8[8] = (pc->ip4.mac[0] ^ 0x2); pc->link6.ip.addr8[1] = 0x80; pc->link6.ip.addr8[0] = 0xfe; pc->link6.cidr = 64; pc->link6.type = IP6TYPE_LOCALLINK; /* try auto-configure stateless */ struct packet *m = nbr_sol(pc); if (m != NULL) enq(&pc->oq, m); } void autoconf6(void) { int i; struct packet *m = NULL; for (i = 0; i < num_pths; i++) { m = nbr_sol(&vpc[pcid]); if (m != NULL) enq(&vpc[pcid].oq, m); } } const char *ip6Info(const int id) { struct in6_addr ipaddr; static char buf[4 + INET6_ADDRSTRLEN + sizeof(vpc[0].ip6.cidr) + 1]; char tmp[INET6_ADDRSTRLEN + 1]; if (vpc[id].ip6.ip.addr32[0] != 0 || vpc[id].ip6.ip.addr32[1] != 0 || vpc[id].ip6.ip.addr32[2] != 0 || vpc[id].ip6.ip.addr32[3] != 0) { memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, vpc[id].ip6.ip.addr8, 16); vinet_ntop6(AF_INET6, &ipaddr, tmp, INET6_ADDRSTRLEN + 1); sprintf(buf, "ip %s/%d", tmp, vpc[id].ip6.cidr); } else return NULL; return buf; } /* end of file */ vpcs-0.8.3/src/command6.h000066400000000000000000000035641447703427300151640ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _CMD6_H_ #define _CMD6_H_ #include "ip.h" #include "vpcs.h" int run_ping6(int argc, char **argv); int run_ipset6(int argc, char **argv); int run_tracert6(int argc, char **argv); int run_nb6(int argc, char **argv); int run_ipdns6(int argc, char **argv); int run_show6(pcs *); int show_ipv6(int argc, char **argv); int show_mtu6(int argc, char **argv); const char *ip6Info(const int id); void autoconf6(void); int ipauto6(void); void locallink6(pcs *pc); #endif /* end of file */ vpcs-0.8.3/src/daemon.c000066400000000000000000000153001447703427300147050ustar00rootroot00000000000000/* * Copyright (c) 2007-2016, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #define _XOPEN_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Darwin #include #elif Linux || GNUkFreeBSD #include #elif FreeBSD #include #elif OpenBSD #include #endif #ifdef cygwin #include #endif extern int ctrl_c; static int cmd_quit = 0; static pid_t fdtty_pid; static int daemon_port; #ifdef cygwin BOOL WINAPI handler_routine(DWORD e); #endif static void daemon_proc(int sock, int fdtty); static void sig_usr1(int sig); static void sig_usr2(int sig); static void sig_quit(int sig); static void sig_term(int sig); static void sig_int(int sig); static int set_telnet_mode(int s); static void set_nonblock(int fd); static int pipe_rw(int fds, int fdd); int daemonize(int port, int bg) { int sock = 0; struct sockaddr_in serv; int on = 1; int fdtty; pid_t pid; if (bg) { pid = fork(); if (pid < 0) { perror("Daemon fork"); return (-1); } if (pid > 0) exit(0); } daemon_port = port; setsid(); #ifdef cygwin SetConsoleCtrlHandler(handler_routine, TRUE); #endif signal(SIGTERM, &sig_term); signal(SIGQUIT, &sig_quit); signal(SIGINT, &sig_int); signal(SIGHUP, SIG_IGN); signal(SIGUSR1, &sig_usr1); signal(SIGUSR2, &sig_usr2); signal(SIGCHLD, SIG_IGN); signal(SIGPIPE, SIG_IGN); /* open an tty as standard I/O for vpcs */ fdtty_pid = forkpty(&fdtty, NULL, NULL, NULL); if (fdtty_pid < 0) { perror("Daemon fork tty\n"); return (-1); } /* child process, the 'real' vpcs */ if (fdtty_pid == 0) return 0; set_nonblock(fdtty); /* daemon socket */ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { perror("Daemon socket"); goto err; } (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); memset((char *) &serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = htonl(INADDR_ANY); serv.sin_port = htons(port); if (bind(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) { perror("Daemon bind port"); goto err; } if (listen(sock, 5) < 0) { perror("Daemon listen"); goto err; } daemon_proc(sock, fdtty); err: printf("error\n"); if (sock >= 0) close(sock); close(fdtty); kill(fdtty_pid, 9); exit(-1); } static int pipe_rw(int fds, int fdd) { fd_set set; struct timeval tv; int rc, len; int n; unsigned char buf[512]; tv.tv_sec = 0; tv.tv_usec = 10 * 1000; n = 0; while (1) { FD_ZERO(&set); FD_SET(fds, &set); rc = select(fds + 1, &set, NULL, NULL, &tv); if (rc < 0) return rc; if (rc == 0) { n++; if (n < 10) continue; else return 0; } n = 0; if (FD_ISSET(fds, &set)) { memset(buf, 0, sizeof(buf)); len = read(fds, buf, sizeof(buf)); if (len <= 0) return (-1); rc = write(fdd, buf, len); if (rc < 0) return rc; } } } static void daemon_proc(int sock, int fdtty) { char *goodbye = "\r\nGood-bye\r\n"; int sock_cli; struct sockaddr_in cli; int slen; int rc; int fsess = 1; slen = sizeof(cli); while (1) { cmd_quit = 0; sock_cli = accept(sock, (struct sockaddr *) &cli, (socklen_t *)&slen); if (sock_cli < 0) continue; set_telnet_mode(sock_cli); set_nonblock(fdtty); /* to show the prompt if it is not the first connection */ if (!fsess) rc = write(fdtty, "\n", 2); fsess = 0; while (!cmd_quit) { if ((rc = pipe_rw(fdtty, sock_cli)) < 0) break; rc = pipe_rw(sock_cli, fdtty); /* error */ if (rc < 0) break; /* time out */ if (rc == 0) continue; } pipe_rw(fdtty, sock_cli); rc = write(sock_cli, goodbye, strlen(goodbye)); close(sock_cli); } } static void set_nonblock(int fd) { int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #ifdef cygwin /* to stop VPCS from another process on Windows */ BOOL WINAPI handler_routine(DWORD e) { if (e == CTRL_BREAK_EVENT) { sig_term(21); return TRUE; } return FALSE; } #endif /* to stop VPCS from another process */ static void sig_term(int sig) { usleep(100000); kill(fdtty_pid, SIGKILL); exit(0); } /* should be sent from 'real vpcs' command: disconnect */ static void sig_quit(int sig) { cmd_quit = 1; signal(SIGQUIT, &sig_quit); } /* should be sent from 'real vpcs' command: quit * vpcs has exited. */ static void sig_usr1(int sig) { usleep(100000); kill(fdtty_pid, SIGKILL); exit(0); } /* should be sent from hypervisor command: stop or quit */ static void sig_usr2(int sig) { /* release the resource and save workspace */ kill(fdtty_pid, SIGUSR1); usleep(100000); kill(fdtty_pid, SIGKILL); usleep(100000); exit(0); } /* Ctrl+C was pressed */ static void sig_int(int sig) { ctrl_c = 1; signal(SIGINT, &sig_int); } static int set_telnet_mode(int s) { /* DO echo */ char *neg = "\xFF\xFD\x01" "\xFF\xFB\x01" "\xFF\xFD\x03" "\xFF\xFB\x03"; unsigned char buf[512]; int n; n = write(s, neg, strlen(neg)); n = read(s, buf, sizeof(buf)); return n; } /* end of file */ vpcs-0.8.3/src/daemon.h000066400000000000000000000027451447703427300147230ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _DAEMON_H_ #define _DAEMON_H_ int daemonize(int port, int bg); #endif /* end of file */ vpcs-0.8.3/src/dev.c000066400000000000000000000102701447703427300142210ustar00rootroot00000000000000/* * Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include #include #ifdef Linux #ifdef TAP #include #endif #endif #include "globle.h" #include "dev.h" extern int devtype; #ifdef TAP extern int num_pths; extern char *tapname; #endif int VRead(pcs *pc, void *buf, int len) { struct sockaddr addr; socklen_t size; int n = 0; fd_set readSet; struct timeval timeout = {1, 0}; FD_ZERO(&readSet); FD_SET(pc->fd, &readSet); if (select(pc->fd + 1, &readSet, NULL, NULL, &timeout) <= 0) return 0; switch (devtype) { case DEV_TAP: n = read(pc->fd, buf, len); break; case DEV_UDP: size = sizeof(addr); n = recvfrom(pc->fd, buf, len, 0, (struct sockaddr *)&addr, &size); break; } return n; } int VWrite(pcs *pc, void *buf, int len) { struct sockaddr_in addr; int n = 0; fd_set writeSet; struct timeval timeout = {1, 0}; FD_ZERO(&writeSet); FD_SET(pc->fd, &writeSet); if (select(pc->fd + 1, NULL, &writeSet, NULL, &timeout) <= 0) return 0; switch (devtype) { case DEV_TAP: n = write(pc->fd, buf, len); break; case DEV_UDP: bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(pc->rport); addr.sin_addr.s_addr = pc->rhost; n = sendto(pc->fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)); break; } return n; } int open_dev(int id) { int fd = 0; switch(devtype) { #ifdef TAP case DEV_TAP: fd = open_tap(id); if (fd <= 0) { fd = 0; return 0; } break; #endif case DEV_UDP: fd = open_udp(vpc[id].lport); if (fd <= 0) { fd = 0; return 0; } break; } return fd; } int open_udp(int port) { int s; struct sockaddr_in addr_in; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) return 0; bzero(&addr_in, sizeof(addr_in)); addr_in.sin_family = AF_INET; addr_in.sin_addr.s_addr = htonl(INADDR_ANY); addr_in.sin_port = htons(port); if(bind(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) == -1) { close(s); return 0; } return s; } #ifdef TAP int open_tap(int id) { struct ifreq ifr; int fd; char dev[IFNAMESIZ]; if (num_pths > 1) sprintf(dev, "tap%d", id); else { if (strlen(tapname) >= IFNAMSIZ) return(-1); sprintf(dev, "%s", tapname); } if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { return(-1); } memset(&ifr, 0, sizeof(ifr)); /* * IFF_TAP - TAP device * IFF_NO_PI - Do not provide packet information * TUNSLMODE | TUNSIFHEAD on the freebsd. */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, dev, IFNAMESIZ); if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) { close(fd); return(-1); } return(fd); } #endif /* end of file */ vpcs-0.8.3/src/dev.h000066400000000000000000000031471447703427300142330ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _DEV_H_ #define _DEV_H_ #include "vpcs.h" int open_dev(int id); int open_udp(int port); int open_tap(int id); int VRead(pcs *pc, void *buf, int len); int VWrite(pcs *pc, void *buf, int len); #endif /* end of file */ vpcs-0.8.3/src/dhcp.c000066400000000000000000000437111447703427300143670ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include "packets.h" #include "vpcs.h" #include "dhcp.h" struct packet * dhcp4_discover(pcs *pc, int renew) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; int i, k; struct packet *m; char b[9]; u_char bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; m = new_pkt(DHCP4_PSIZE); if (m == NULL) return NULL; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); dh->op = 1; dh->htype = 1; dh->hlen = 6; dh->hops = 0; dh->xid = pc->ip4.dhcp.xid; dh->secs = 0; dh->flags = 0; dh->ciaddr = 0; dh->yiaddr = 0; dh->siaddr = 0; dh->giaddr = 0; memcpy(dh->chaddr, pc->ip4.mac, 6); i = 0; ((int*)(&dh->options[i]))[0] = htonl(0x63825363); i += sizeof(int); dh->options[i++] = DHO_DHCP_MESSAGE_TYPE; dh->options[i++] = 1; dh->options[i++] = DHCPDISCOVER; dh->options[i++] = DHO_HOST_NAME; k = strlen(pc->xname); dh->options[i++] = k; memcpy((char *)(dh->options + i), pc->xname, k); i += k; dh->options[i++] = DHO_DHCP_CLIENT_IDENTIFIER; dh->options[i++] = 7; /* using hardware address as my identifier */ dh->options[i++] = 1; memcpy(&dh->options[i], pc->ip4.mac, 6); i += 6; if (renew && pc->ip4.dhcp.ip) { dh->options[i++] = DHO_DHCP_REQUESTED_ADDRESS; dh->options[i++] = 4; ((int*)(&dh->options[i]))[0] = pc->ip4.dhcp.ip; i += sizeof(int); } dh->options[i] = DHO_END; ui->ui_sport = htons(68); ui->ui_dport = htons(67); ui->ui_ulen = htons(sizeof(dhcp4_hdr) + sizeof(udphdr)); ui->ui_sum = 0; ip->ver = 4; ip->ihl = sizeof *ip >> 2; ip->tos = 0x10; ip->len = htons(sizeof(udpiphdr) + sizeof(dhcp4_hdr)); ip->id = 0; ip->ttl = 16; ip->proto = IPPROTO_UDP; ip->cksum = 0; ip->sip = 0; ip->dip = 0xffffffff; bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ui->ui_len = ui->ui_ulen; ui->ui_sum = cksum((u_short*)ui, sizeof(udpiphdr) + sizeof(dhcp4_hdr)); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); encap_ehead(m->data, pc->ip4.mac, bcast, ETHERTYPE_IP); m->len = sizeof(ethdr) + sizeof(udpiphdr) + sizeof(dhcp4_hdr); return m; } struct packet * dhcp4_request(pcs *pc) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; int i, k; struct packet *m; char b[9]; m = new_pkt(DHCP4_PSIZE); if (m == NULL) return NULL; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); dh->op = 1; dh->htype = 1; dh->hlen = 6; dh->hops = 0; dh->xid = pc->ip4.dhcp.xid; dh->secs = 0; dh->flags = 0; dh->ciaddr = pc->ip4.dhcp.ip; dh->yiaddr = 0; dh->siaddr = 0; dh->giaddr = 0; memcpy(dh->chaddr, pc->ip4.mac, 6); i = 0; ((int*)(&dh->options[i]))[0] = htonl(0x63825363); i += sizeof(int); dh->options[i++] = DHO_DHCP_MESSAGE_TYPE; dh->options[i++] = 1; dh->options[i++] = DHCPREQUEST; dh->options[i++] = DHO_DHCP_SERVER_IDENTIFIER; dh->options[i++] = 4; ((int*)(&dh->options[i]))[0] = pc->ip4.dhcp.svr; i += sizeof(int); dh->options[i++] = DHO_DHCP_REQUESTED_ADDRESS; dh->options[i++] = 4; ((int*)(&dh->options[i]))[0] = pc->ip4.dhcp.ip; i += sizeof(int); dh->options[i++] = DHO_DHCP_CLIENT_IDENTIFIER; dh->options[i++] = 7; /* using hardware address as my identifier */ dh->options[i++] = 1; memcpy(&dh->options[i], pc->ip4.mac, 6); i += 6; dh->options[i++] = DHO_HOST_NAME; k = strlen(pc->xname); dh->options[i++] = k; memcpy((char *)(dh->options + i), pc->xname, k); i += k; dh->options[i++] = DHO_DHCP_PARAMETER_REQUEST_LIST; dh->options[i++] = 4; dh->options[i++] = DHO_SUBNET_MASK; dh->options[i++] = DHO_ROUTERS; dh->options[i++] = DHO_DNS; dh->options[i++] = DHO_DOMAIN; dh->options[i] = DHO_END; ui->ui_sport = htons(68); ui->ui_dport = htons(67); ui->ui_ulen = htons(sizeof(dhcp4_hdr) + sizeof(udphdr)); ui->ui_sum = 0; ip->ver = 4; ip->ihl = sizeof *ip >> 2; ip->tos = 0x10; ip->len = htons(sizeof(udpiphdr) + sizeof(dhcp4_hdr)); ip->id = 0; ip->ttl = 16; ip->proto = IPPROTO_UDP; ip->cksum = 0; ip->sip = 0; ip->dip = 0xffffffff; bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ui->ui_len = ui->ui_ulen; ui->ui_sum = cksum((u_short*)ui, sizeof(udpiphdr) + sizeof(dhcp4_hdr)); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); encap_ehead(m->data, pc->ip4.mac, pc->ip4.dhcp.smac, ETHERTYPE_IP); m->len = sizeof(ethdr) + sizeof(udpiphdr) + sizeof(dhcp4_hdr); return m; } struct packet * dhcp4_release(pcs *pc) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; int i, k; struct packet *m; char b[9]; m = new_pkt(DHCP4_PSIZE); if (m == NULL) return NULL; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); dh->op = 1; dh->htype = 1; dh->hlen = 6; dh->hops = 0; dh->xid = pc->ip4.dhcp.xid; dh->secs = pc->ip4.dhcp.lease; dh->flags = 0; dh->ciaddr = pc->ip4.dhcp.ip; dh->yiaddr = 0; dh->siaddr = 0; dh->giaddr = 0; memcpy(dh->chaddr, pc->ip4.mac, 6); i = 0; ((int*)(&dh->options[i]))[0] = htonl(0x63825363); i += sizeof(int); dh->options[i++] = DHO_DHCP_MESSAGE_TYPE; dh->options[i++] = 1; dh->options[i++] = DHCPRELEASE; dh->options[i++] = DHO_DHCP_PARAMETER_REQUEST_LIST; dh->options[i++] = 2; dh->options[i++] = DHO_SUBNET_MASK; dh->options[i++] = DHO_ROUTERS; dh->options[i++] = DHO_DHCP_SERVER_IDENTIFIER; dh->options[i++] = 4; ((int*)(&dh->options[i]))[0] = pc->ip4.dhcp.svr; i += sizeof(int); dh->options[i++] = DHO_DHCP_REQUESTED_ADDRESS; dh->options[i++] = 4; ((int*)(&dh->options[i]))[0] = pc->ip4.dhcp.ip; i += sizeof(int); dh->options[i++] = DHO_HOST_NAME; k = strlen(pc->xname); dh->options[i++] = k; memcpy((char *)(dh->options + i), pc->xname, k); i += k; dh->options[i++] = DHO_DHCP_CLIENT_IDENTIFIER; dh->options[i++] = 7; /* using hardware address as my identifier */ dh->options[i++] = 1; memcpy(&dh->options[i], pc->ip4.mac, 6); i += 6; dh->options[i] = DHO_END; ui->ui_sport = htons(68); ui->ui_dport = htons(67); ui->ui_ulen = htons(sizeof(dhcp4_hdr) + sizeof(udphdr)); ui->ui_sum = 0; ip->ver = 4; ip->ihl = sizeof *ip >> 2; ip->tos = 0x10; ip->len = htons(sizeof(udpiphdr) + sizeof(dhcp4_hdr)); ip->id = 0; ip->ttl = 16; ip->proto = IPPROTO_UDP; ip->cksum = 0; ip->sip = pc->ip4.dhcp.ip; ip->dip = pc->ip4.dhcp.svr; bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ui->ui_len = ui->ui_ulen; ui->ui_sum = cksum((u_short*)ui, sizeof(udpiphdr) + sizeof(dhcp4_hdr)); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); encap_ehead(m->data, pc->ip4.mac, pc->ip4.dhcp.smac, ETHERTYPE_IP); m->len = sizeof(ethdr) + sizeof(udpiphdr) + sizeof(dhcp4_hdr); return m; } int isDhcp4_Offer(pcs *pc, struct packet *m) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; u_char *p; u_int magic; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); if (dh->xid != pc->ip4.dhcp.xid || dh->op != 2) return 0; /* offer for me */ p = dh->options; magic = ((long*)(p))[0]; /* invalid magic */ if (magic != htonl(0x63825363)) return 0; pc->ip4.dhcp.svr = ip->sip; pc->ip4.dhcp.ip = dh->yiaddr; memcpy(pc->ip4.dhcp.smac, eh->src, 6); /* options */ p += 4; while (*p != DHO_END && p - dh->options < DHCP_OPTION_LEN) { if (*p == DHO_SUBNET_MASK && *(p + 1) == 4) { pc->ip4.dhcp.netmask = ((int*)(p + 2))[0]; p += 6; continue; } else if (*p == DHO_ROUTERS && *(p + 1) == 4) { pc->ip4.dhcp.gw = ((int*)(p + 2))[0]; p += 6; continue; } else if (*p == DHO_DNS) { if (*(p + 1) == 4) { pc->ip4.dhcp.dns[0] = ((int*)(p + 2))[0]; p += 6; } else if (*(p + 1) >= 8) { pc->ip4.dhcp.dns[0] = ((int*)(p + 2))[0]; pc->ip4.dhcp.dns[1] = ((int*)(p + 2))[1]; p += *(p + 1) + 2; } continue; } else if (*p == DHO_DHCP_SERVER_IDENTIFIER && *(p + 1) == 4) { pc->ip4.dhcp.svr = ((int*)(p + 2))[0]; p += 6; continue; } else { p++; /* skip op code */ p += *(p) + 1; /* add op offset(length) */ } } return 1; } int isDhcp4_packer(pcs *pc, struct packet *m) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; u_char *p; u_int magic; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); if (dh->xid == pc->ip4.dhcp.xid && dh->op == 2) { memset(&(pc->ip4.dhcp), 0, sizeof(pc->ip4.dhcp)); pc->ip4.dhcp.svr = ip->sip; memcpy(pc->ip4.dhcp.smac, eh->src, 6); pc->ip4.ip = dh->yiaddr; pc->ip4.dhcp.ip = pc->ip4.ip; p = dh->options; magic = ((long*)(p))[0]; if (magic == htonl(0x63825363)) { pc->ip4.dhcp.renew = 0; pc->ip4.dhcp.rebind = 0; p += 4; while (*p != DHO_END && p - dh->options < DHCP_OPTION_LEN) { if (*p == DHO_SUBNET_MASK && *(p + 1) == 4) { pc->ip4.dhcp.netmask = ((int*)(p + 2))[0]; pc->ip4.cidr = getCIDR(ntohl(((int*)(p + 2))[0])); p += 6; continue; } else if (*p == DHO_ROUTERS && *(p + 1) == 4) { pc->ip4.gw = ((int*)(p + 2))[0]; pc->ip4.dhcp.gw = pc->ip4.gw; p += 6; continue; } else if (*p == DHO_DHCP_LEASE_TIME && *(p + 1) == 4) { pc->ip4.lease = ntohl(((int*)(p + 2))[0]); pc->ip4.dhcp.lease = pc->ip4.lease; p += 6; continue; } else if (*p == DHO_DHCP_RENEWAL_TIME && *(p + 1) == 4) { pc->ip4.dhcp.renew = ntohl(((int*)(p + 2))[0]); p += 6; continue; } else if (*p == DHO_DHCP_REBIND_TIME && *(p + 1) == 4) { pc->ip4.dhcp.rebind = ntohl(((int*)(p + 2))[0]); p += 6; continue; } else if (*p == DHO_DNS) { if (*(p + 1) == 4) { pc->ip4.dhcp.dns[0] = ((int*)(p + 2))[0]; pc->ip4.dns[0] = pc->ip4.dhcp.dns[0]; p += 6; } else if (*(p + 1) >= 8) { pc->ip4.dhcp.dns[0] = ((int*)(p + 2))[0]; pc->ip4.dhcp.dns[1] = ((int*)(p + 2))[1]; pc->ip4.dns[0] = pc->ip4.dhcp.dns[0]; pc->ip4.dns[1] = pc->ip4.dhcp.dns[1]; p += *(p + 1) + 2; } continue; } else if (*p == DHO_DOMAIN) { memset(pc->ip4.dhcp.domain, 0, sizeof(pc->ip4.dhcp.domain)); memcpy(pc->ip4.dhcp.domain, p + 2, *(p + 1)); strcpy(pc->ip4.domain, pc->ip4.dhcp.domain); p += *(p + 1) + 2; continue; } else if (*p == DHO_DHCP_SERVER_IDENTIFIER && *(p + 1) == 4) { pc->ip4.dhcp.svr = ((int*)(p + 2))[0]; p += 6; continue; } else { p++; /* skip op code */ p += *(p) + 1; /* add op offset(length) */ } } } return 1; } else return 0; } int dmp_dhcp(pcs *pc, const struct packet *m) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; int direct = 0; int i, j, k; struct in_addr in; u_char opcode; char *msg_type[8] = { "Discover", "Offer", "Request", "Decline", "Ack", "Nak", "Release", "Inform"}; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); if (ip->proto != IPPROTO_UDP) return 0; ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); /* incoming */ if (memcmp(eh->dst, pc->ip4.mac, 6) == 0) direct = 1; /* to dhcp server */ if (direct == 0) { if (ui->ui_sport != htons(68) || ui->ui_dport != htons(67)) return 0; } else { if (ui->ui_dport != htons(68) || ui->ui_sport != htons(67)) return 0; } printf("Opcode: %d (%s)\n", dh->op, (dh->op == 1 ? "REQUEST" : "REPLY")); in.s_addr = dh->ciaddr; printf("Client IP Address: %s\n", inet_ntoa(in)); in.s_addr = dh->yiaddr; printf("Your IP Address: %s\n", inet_ntoa(in)); in.s_addr = dh->siaddr; printf("Server IP Address: %s\n", inet_ntoa(in)); in.s_addr = dh->giaddr; printf("Gateway IP Address: %s\n", inet_ntoa(in)); printf("Client MAC Address: "); PRINT_MAC(dh->chaddr); printf("\n"); /* skip magic */ i = sizeof(int); opcode = dh->options[i]; while (opcode != DHO_END && i < DHCP_OPTION_LEN) { switch (opcode) { case DHO_DHCP_MESSAGE_TYPE: printf("Option %d: Message Type = ", DHO_DHCP_MESSAGE_TYPE); k = dh->options[i + 1]; j = dh->options[i + 2]; if (j > 0 && j < 9) printf("%s\n", msg_type[j - 1]); else printf("Unknown\n"); i += k + 2; break; case DHO_HOST_NAME: printf("Option %d: Host Name = ", DHO_HOST_NAME); k = dh->options[i + 1]; for (j = 0; j < k; j++) printf("%c", dh->options[i + 2 + j]); printf("\n"); i += k + 2; break; case DHO_DHCP_CLIENT_IDENTIFIER: printf("Option %d: Client Identifier = ", DHO_DHCP_CLIENT_IDENTIFIER); k = dh->options[i + 1]; if (dh->options[i + 2] == 1) { printf("Hardware Type=Ethernet MAC Address = "); PRINT_MAC(&(dh->options[i + 3])); printf("\n"); } else printf("Unknow type "); i += k + 2; break; case DHO_DHCP_SERVER_IDENTIFIER: in.s_addr = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: DHCP Server = %s\n", DHO_DHCP_SERVER_IDENTIFIER, inet_ntoa(in)); i += 6; break; case DHO_DHCP_REQUESTED_ADDRESS: in.s_addr = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: Requested IP Address = %s\n", DHO_DHCP_REQUESTED_ADDRESS, inet_ntoa(in)); i += 6; break; case DHO_DHCP_LEASE_TIME: j = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: Lease Time = %d\n", DHO_DHCP_LEASE_TIME, ntohl(j)); i += 6; break; case DHO_DHCP_RENEWAL_TIME: j = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: Renewal Time = %d\n", DHO_DHCP_RENEWAL_TIME, ntohl(j)); i += 6; break; case DHO_DHCP_REBIND_TIME: j = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: Rebinding Time = %d\n", DHO_DHCP_REBIND_TIME, ntohl(j)); i += 6; break; case DHO_SUBNET_MASK: printf("Option %d: Subnet Mask = %d.%d.%d.%d\n", DHO_SUBNET_MASK, dh->options[i + 2], dh->options[i + 3], dh->options[i + 4], dh->options[i + 5]); i += 6; break; case DHO_ROUTERS: in.s_addr = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: Router = %s\n", DHO_ROUTERS, inet_ntoa(in)); i += 6; break; case DHO_DNS: k = dh->options[i + 1]; printf("Option %d: DNS Server = ", DHO_DNS); j = 0; while (k >= (j + 1)* 4) { in.s_addr = ((int*)(&dh->options[i + 2 + j * 4]))[0]; printf("%s ", inet_ntoa(in)); j++; } printf("\n"); i += k + 2; break; case DHO_DOMAIN: printf("Option %d: Domain = ", DHO_DOMAIN); k = dh->options[i + 1]; for (j = 0; j < k; j++) printf("%c", dh->options[i + 2 + j]); printf("\n"); i += k + 2; break; case DHO_TFTP_SERVER: in.s_addr = ((int*)(&dh->options[i + 2]))[0]; printf("Option %d: TFTP Server Address = %s\n", DHO_TFTP_SERVER, inet_ntoa(in)); i += 5; break; default: k = dh->options[i + 1]; i += k + 2; break; } opcode = dh->options[i]; } printf("\n"); return 0; } int dhcp_renew(pcs *pc) { struct packet *m; struct packet *p; int i; int ok; pc->ip4.dhcp.xid = rand(); /* request */ i = 0; ok = 0; while (i++ < 3 && !ok) { m = dhcp4_request(pc); if (m == NULL) { sleep(1); continue; } enq(&pc->oq, m); sleep(1); while ((p = deq(&pc->bgiq)) != NULL && !ok) { ok = isDhcp4_packer(pc, p); free(p); } i++; } if (ok) { if (pc->ip4.dhcp.renew == 0) pc->ip4.dhcp.renew = pc->ip4.dhcp.lease / 2; if (pc->ip4.dhcp.rebind == 0) pc->ip4.dhcp.rebind = pc->ip4.dhcp.lease * 7 / 8; return 1; } return 0; } int dhcp_rebind(pcs *pc) { int ts[3] = {1, 3, 9}; struct packet *m; struct packet *p; int i; int ok; pc->ip4.dhcp.xid = rand(); /* request */ i = 0; ok = 0; while (i < 3 && !ok) { m = dhcp4_discover(pc, 0); if (m == NULL) { sleep(1); continue; } enq(&pc->oq, m); sleep(ts[i]); while ((p = deq(&pc->bgiq)) != NULL && !ok) { ok = isDhcp4_Offer(pc, p); free(p); } } if (!ok) return 0; /* request */ i = 0; ok = 0; while (!ok) { m = dhcp4_request(pc); if (m == NULL) { sleep(1); continue; } enq(&pc->oq, m); sleep(1); while ((p = deq(&pc->bgiq)) != NULL && !ok) { ok = isDhcp4_packer(pc, p); free(p); } } if (pc->ip4.dhcp.renew == 0) pc->ip4.dhcp.renew = pc->ip4.dhcp.lease / 2; if (pc->ip4.dhcp.rebind == 0) pc->ip4.dhcp.rebind = pc->ip4.dhcp.lease * 7 / 8; return 1; } int dhcp_enq(pcs *pc, const struct packet *m) { ethdr *eh; iphdr *ip; udpiphdr *ui; dhcp4_hdr *dh; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; dh = (dhcp4_hdr*)(ui + 1); if (pc->bgjobflag && dh->xid == pc->ip4.dhcp.xid) { enq(&pc->bgiq, (struct packet *)m); return 1; } return 0; } /* end of file */ vpcs-0.8.3/src/dhcp.h000066400000000000000000000071531447703427300143740ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _DHCP_H_ #define _DHCP_H_ #define DHCP_SNAME_LEN (64) #define DHCP_FILE_LEN (128) #define DHCP_OPTION_LEN (128) typedef struct dhcp4_packet { char op; char htype; /* ether:1 */ char hlen; /* hardware address length:6 */ char hops; /* number of relay agent, same lan:0 */ u_int xid; /* transaction id */ u_short secs; /* seconds since client start */ u_short flags; /* flags: 0 */ u_int ciaddr; /* client ip */ u_int yiaddr; /* your client ip */ u_int siaddr; /* server ip */ u_int giaddr; /* relay server ip */ u_char chaddr[16]; /* client hardware address */ char sname[DHCP_SNAME_LEN]; /* Server name */ char file[DHCP_FILE_LEN]; /* file name */ u_char options[DHCP_OPTION_LEN]; /* dummny options */ } dhcp4_hdr; #define DHCPDISCOVER 1 #define DHCPOFFER 2 #define DHCPREQUEST 3 #define DHCPDECLINE 4 #define DHCPACK 5 #define DHCPNAK 6 #define DHCPRELEASE 7 #define DHCPINFORM 8 #define DHO_PAD 0 #define DHO_SUBNET_MASK 1 #define DHO_TIME_OFFSET 2 #define DHO_ROUTERS 3 #define DHO_DNS 6 #define DHO_HOST_NAME 12 #define DHO_DOMAIN 15 #define DHO_DHCP_REQUESTED_ADDRESS 50 #define DHO_DHCP_LEASE_TIME 51 #define DHO_DHCP_MESSAGE_TYPE 53 #define DHO_DHCP_SERVER_IDENTIFIER 54 #define DHO_DHCP_PARAMETER_REQUEST_LIST 55 #define DHO_DHCP_MESSAGE 56 #define DHO_DHCP_RENEWAL_TIME 58 #define DHO_DHCP_REBIND_TIME 59 #define DHO_DHCP_CLIENT_IDENTIFIER 61 #define DHO_TFTP_SERVER 150 #define DHO_END 255 #define DHCP4_PSIZE (512) struct packet * dhcp4_discover(pcs *pc, int renew); struct packet * dhcp4_request(pcs *pc); struct packet * dhcp4_renew(pcs *pc); struct packet * dhcp4_release(pcs *pc); int isDhcp4_Offer(pcs *pc, struct packet *m); int isDhcp4_packer(pcs *pc, struct packet *m); int dmp_dhcp(pcs *pc, const struct packet *m); int dhcp_renew(pcs *pc); int dhcp_rebind(pcs *pc); int dhcp_enq(pcs *pc, const struct packet *m); #endif /* end of file */ vpcs-0.8.3/src/dns.c000066400000000000000000000245361447703427300142410ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include "vpcs.h" #include "utils.h" #include "dns.h" #include "inet6.h" #include "packets.h" #include "packets6.h" extern int ctrl_c; static int fmtstring(const char *name, char *buf); static int dnsrequest(u_short id, const char *name, int type, char *data, int *namelen); static int dnsparse(struct packet *m, u_short id, char *data, int dlen, u_char *ip); static int ip2str(u_char *ip, char *str); static void appenddomain(pcs *pc, char *dname, int sdname, const char *name); static struct packet *dns4(pcs *pc, int sw, char *data, int dlen); static struct packet *dns6(pcs *pc, int sw, char *data, int dlen); int hostresolv(pcs *pc, char *name, char *ipstr) { struct packet *m; char data[512]; //char *pdn = NULL; int dlen; struct timeval tv; int ok; int namelen; int i; char dname[64+1]; u_short magicid; int reqcnt = 0; int atype = 1; int cnt4 = 0; int cnt6 = 0; u_char ip[20]; int tryagain = 0; appenddomain(pc, dname, sizeof(dname), name); while (reqcnt++ < 3) { tryagain = 0; magicid = random(); dlen = dnsrequest(magicid, dname, atype, data, &namelen); if (dlen == 0) return 0; //pdn = data + sizeof(dnshdr); for (i = 0; i < 4 && !tryagain; i++) { if (cnt4 < 2) { m = dns4(pc, cnt4, data, dlen); cnt4++; } else if (cnt6 < 2) { m = dns6(pc, cnt6, data, dlen); cnt6++; } if (m == NULL) continue; gettimeofday(&(tv), (void*)0); enq(&pc->oq, m); while (!timeout(tv, 1000) && !ctrl_c) { delay_ms(1); ok = 0; while ((m = deq(&pc->iq)) != NULL && !ok) { ok = dnsparse(m, magicid, dname, namelen, ip); free(m); } if (ok == 2) { tryagain = 1; break; } if (ok == 6) { atype = 28; cnt4 = 0; cnt6 = 0; tryagain = 1; break; } if (ok) { strcpy(name, dname); ip2str(ip, ipstr); return 1; } } } } return 0; } void appenddomain(pcs *pc, char *dname, int sdname, const char *name) { char *dn = NULL; if (strchr(name, '.')) { strcpy(dname, name); return; } if (pc->ip4.domain[0] != '\0') dn = pc->ip4.domain; else if (pc->ip4.dhcp.domain[0] != '\0') dn = pc->ip4.dhcp.domain; else { snprintf(dname, sdname, "%s", name); return; } snprintf(dname, sdname, "%s.%s", name, dn); } struct packet *dns4(pcs *pc, int sw, char *data, int dlen) { u_int gip; //struct in_addr in; sesscb cb; u_char mac[ETH_ALEN]; struct packet *m; if (pc->ip4.dns[sw] == 0) return 0; if (sameNet(pc->ip4.dns[sw], pc->ip4.ip, pc->ip4.cidr)) gip = pc->ip4.dns[sw]; else { if (pc->ip4.gw == 0) return NULL; gip = pc->ip4.gw; } if (!arpResolve(pc, gip, mac)) { //in.s_addr = gip; return NULL; } /* save old control block */ memcpy(&cb, &pc->mscb, sizeof(sesscb)); pc->mscb.data = data; pc->mscb.dsize = dlen; pc->mscb.proto = IPPROTO_UDP; pc->mscb.mtu = pc->mtu; pc->mscb.ipid = time(0) & 0xffff; pc->mscb.ttl = TTL; pc->mscb.sip = pc->ip4.ip; pc->mscb.dip = pc->ip4.dns[sw]; pc->mscb.sport = (random() % (65000 - 1024)) + 1024; pc->mscb.dport = 53; memcpy(pc->mscb.smac, pc->ip4.mac, ETH_ALEN); memcpy(pc->mscb.dmac, mac, ETH_ALEN); m = packet(pc); /* restore control block */ memcpy(&pc->mscb, &cb, sizeof(sesscb)); return m; } struct packet *dns6(pcs *pc, int sw, char *data, int dlen) { sesscb cb; u_char mac[ETH_ALEN]; struct packet *m; char *p; if (pc->ip6.dns[sw].addr32[0] == 0 && pc->ip6.dns[sw].addr32[1] == 0 && pc->ip6.dns[sw].addr32[2] == 0 && pc->ip6.dns[sw].addr32[3] == 0) return 0; p = (char*)nbDiscovery(pc, &pc->mscb.dip6); if (p == NULL) return 0; memcpy(mac, p, 6); /* save old control block */ memcpy(&cb, &pc->mscb, sizeof(sesscb)); pc->mscb.data = data; pc->mscb.dsize = dlen; pc->mscb.proto = IPPROTO_UDP; pc->mscb.mtu = pc->mtu; pc->mscb.ipid = time(0) & 0xffff; pc->mscb.ttl = TTL; memcpy(pc->mscb.dip6.addr8, pc->ip6.dns[sw].addr8, 16); if (pc->mscb.dip6.addr16[0] != IPV6_ADDR_INT16_ULL) memcpy(pc->mscb.sip6.addr8, pc->ip6.ip.addr8, 16); else memcpy(pc->mscb.sip6.addr8, pc->link6.ip.addr8, 16); pc->mscb.sport = (random() % (65000 - 1024)) + 1024; pc->mscb.dport = 53; memcpy(pc->mscb.smac, pc->ip4.mac, ETH_ALEN); memcpy(pc->mscb.dmac, mac, ETH_ALEN); m = packet6(pc); /* restore control block */ memcpy(&pc->mscb, &cb, sizeof(sesscb)); return m; } static int fmtstring(const char *name, char *buf) { char *s, *r; int len = 0; char c; if (name == NULL || name[0] == '.' || strstr(name, "..") || !strchr(name, '.') || strlen(name) > MAX_DNS_NAME) return 0; memset(buf, 0, MAX_DNS_NAME); strcpy(buf + 1, name); s = buf + 1; while (*s != '\0') { if (*s == '.') *s = '\0'; s++; } s = buf; r = buf + 1; while (*r) { c = strlen(r); *s = c; len += c + 1; s = r + c; r = s + 1; } /* prefix and '\0' at end of the string */ return len + 1; } static int dnsrequest(u_short id, const char *name, int type, char *data, int *namelen) { u_char buf[256]; dnshdr dh; int dlen = sizeof(dnshdr); int i; memset(&dh, 0, sizeof(dnshdr)); dh.id = id; dh.flags = 0x0001; /* QR|OC|AA|TC|RD - RA|Z|RCODE */ dh.query = htons(0x0001); /* one query */ memcpy(data, (void *)&dh, sizeof(dnshdr)); /* query name */ memset(buf, 0, sizeof(buf)); i = fmtstring(name, (char *)buf); if (i == 0) return 0; *namelen = i; memcpy(data + dlen, buf, i); dlen += i; /* A record */ data[dlen++] = 0x00; data[dlen++] = type; /* IN class */ data[dlen++] = 0x00; data[dlen++] = 0x01; return dlen; } /* very simple DNS answer parser * only search A record if exist, get IP address * return 1 if host name was resolved. */ static int dnsparse(struct packet *m, u_short magicid, char *data, int dlen, u_char *cip) { ethdr *eh; iphdr *ip4; ip6hdr *ip6; udphdr *uh; u_char *p; dnshdr *dh; u_short *sp; int rlen; int iplen; int i, j; u_char c; int cname = 0; const char *rcode[6] = { "No error", "Format error", "Server failure", "Name error", "Not implement", "Refused"}; eh = (ethdr *)(m->data); if (eh->type == htons(ETHERTYPE_IPV6)) { ip6 = (ip6hdr *)(eh + 1); uh = (udphdr *)(ip6 + 1); iplen = ntohs(ip6->ip6_plen); } else { ip4 = (iphdr *)(eh + 1); uh = (udphdr *)(ip4 + 1); iplen = ntohs(ip4->len); } dh = (dnshdr *)(uh + 1); if (dh->id != magicid) return 0; /* invalid name or answer */ if ((dh->flags & 0x8081) != 0x8081) { c = (dh->flags >> 8) & 0xf; if (c == 0) return 0; printf("DNS server return: "); if (c < 6) printf("%s\n", rcode[c]); else printf("error: %d\n", c); return 0; } if (dh->query == 0) return 0; /* No Error, answer is zero, try AAAA */ if (dh->answer == 0) return 6; p = (u_char *)(dh + 1); /* extract domain name */ c = 0; i = 0; data[0] = '\0'; while (p + c - (u_char *)(eh + 1) < iplen) { i = *(p + c); strncat(data, (char *)(p + c + 1), i); c += i + 1; if (*(p + c) == '\0') break; strcat(data, "."); } /* skip type and class */ p += c + 5; while (p - (u_char *)(eh + 1) < iplen) { /* skip offset pointer, * normal is 0xc00c, 11 00000000001100, * 11-pointer, 0c-offset from dnshdr */ if ((*p & 0xc0) != 0xc0) { p++; continue; } p += 2; sp = (u_short *)p; /* A/AAAA record */ if ((*sp == 0x0100 || *sp == 0x1c00) && *(sp + 1) == 0x0100) { p += 2 + 2 + 4; sp = (u_short *)p; if (*sp == 0x0400 || *sp == 0x1000) { memcpy(cip + 1, p + 2, ntohs(*sp)); cip[0] = ntohs(*sp); return 1; } } else if (*sp == 0x0500) { /* cname */ /* skip type2, class2, ttl4 */ p += 2 + 2 + 4; rlen = ntohs(*((u_short *)p)); p = p + 2; c = *p; i = 0; data[i] = '\0'; while (1) { p++; for (j = 0; j < c; j++) i += sprintf(data + i, "%c", *(p + j)); p += c; c = *p; if (c == 0 || c > 64) break; i += sprintf(data + i, "."); } if (c > 64) { sp = (u_short *)p; i += sprintf(data + i, "."); dmp_dns_rname((char *)(dh) + (ntohs(*sp) & 0x3fff), (char *)(eh + 1) + iplen, data + i); } /* tell caller retry again */ cname = 1; p++; } else { /* skip type2, class2, ttl4, rlen2 */ p += 2 + 2 + 4; sp = (u_short *)p; rlen = ntohs(*sp); p += rlen + 2; /* skip pointer */ p += 2; } } if (cname == 1) return 2; return 0; } int ip2str(u_char *ip, char *str) { struct in6_addr ipaddr; char buf[INET6_ADDRSTRLEN + 1]; if (*ip == 4) sprintf(str, "%d.%d.%d.%d", ip[1], ip[2], ip[3], ip[4]); else if (*ip == 16) { memset(buf, 0, sizeof(buf)); memcpy(ipaddr.s6_addr, ip + 1, 16); vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1); sprintf(str, "%s", buf); } return 0; } int dmp_dns_rname(char *s, char *se, char *name) { int i; u_char c; name[0] = '\0'; c = *s; i = 0; while (s < se) { strncat(name, (char *)(s + i + 1), c); i += c + 1; c = *(s + i); if (*(s + i) == '\0' || c > 64) break; strcat(name, "."); } return i; } /* end of file */ vpcs-0.8.3/src/dns.h000066400000000000000000000035571447703427300142460ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _DNS_H_ #define _DNS_H_ #include #include "vpcs.h" typedef struct { u_short id; u_short flags; u_short query; u_short answer; u_short author; u_short addition; } dnshdr; typedef struct { u_char rd:1; u_char tc:1; u_char aa:1; u_char op:4; u_char qr:1; u_char rc:4; u_char z:3; u_char ra:1; } dnsflags; #define MAX_DNS_NAME 64 int hostresolv(pcs *pc, char *name, char *ipstr); int dmp_dns_rname(char *s, char *se, char *name); #endif /* end of file */ vpcs-0.8.3/src/dump.c000066400000000000000000000366401447703427300144210ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include "ip.h" #include "dump.h" #include "dns.h" static void dmp_ip(void *dat); static void dmp_ip6(void *dat); static void dmp_arp(void *dat); static void dmp_dns(void *dat); static char *dmp_dns_timestr(u_int s); static struct timeval gtv = {0, 0}; int dmp_packet(const struct packet *m, const int flag) { struct timeval tv; uint32_t usec; int i, j, pos0, pos1; char x0[96], x1[17]; u_char *p = (u_char *)m->data; int len = m->len; int left; ethdr *eh = (ethdr *)m->data; int cr = 0; if (flag == 0) return flag; if (gtv.tv_sec == 0) gettimeofday(>v, 0); gettimeofday(&tv, 0); usec = (tv.tv_sec - gtv.tv_sec) * 1000000 + tv.tv_usec - gtv.tv_usec; printf("\n\033[32m%04u.%u\033[0m", usec / 1000000, usec % 1000000); if (flag & DMP_MAC) { printf(" "); printf("\033[33m"); cr = 1; PRINT_MAC(p + 6); printf(" -> "); PRINT_MAC(p); printf("\n"); } len -= 14; p += 14; if (flag & DMP_RAW) { i = 0; if (!cr) { printf("\n"); printf("\033[33m"); cr = 1; } while (i < len) { pos0 = pos1 = 0; left = 40; for (j = i; (j < i + 16 && j < len); j += 2) { pos0 += sprintf(x0 + pos0, "%2.2x", *(p + j)); left -= 2; if (isprint(*(p + j))) pos1 += sprintf(x1 + pos1, "%c", *(p + j)); else pos1 += sprintf(x1 + pos1, "."); pos0 += sprintf(x0 + pos0, "%2.2x ", *(p + j + 1)); left -= 3; if (isprint(*(p + j + 1))) pos1 += sprintf(x1 + pos1, "%c", *(p + j + 1)); else pos1 += sprintf(x1 + pos1, "."); } for (pos1 = 0; pos1 < left; pos1++) pos0 += sprintf(x0 + pos0, " "); printf("%s %s\n", x0, x1); i += (j - i); } printf("\n"); } if (flag & DMP_DETAIL) { if (!cr) { printf("\n"); printf("\033[33m"); cr = 1; } if (eh->type == htons(ETHERTYPE_IP)) dmp_ip(eh + 1); else if (eh->type == htons(ETHERTYPE_IPV6)) dmp_ip6(eh + 1); else if (eh->type == htons(ETHERTYPE_ARP)) dmp_arp(eh + 1); } if (cr) printf("\033[0m"); return 1; } static void dmp_arp(void *dat) { vpcs_arphdr *ah = (vpcs_arphdr *)dat; struct in_addr in; u_char broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u_int *si, *di; printf("ARP, OpCode: %d (%s)", ntohs(ah->op), ((ntohs(ah->op) == ARPOP_REQUEST) ? "Request" : "Reply")); si = (u_int *)ah->sip; di = (u_int *)ah->dip; if (si[0] == di[0] && di[0] != 0) printf(" Gratuitous ARP"); printf("\nEther Address: "); PRINT_MAC(ah->sea); printf(" -> "); if (memcmp(ah->dea, broadcast, ETH_ALEN) == 0) printf("Broadcast"); else PRINT_MAC(ah->dea); printf("\n"); if ((ntohs(ah->op) == ARPOP_REQUEST)) { in.s_addr = di[0]; printf("Who has %s? Tell ", inet_ntoa(in)); in.s_addr = si[0]; printf("%s", inet_ntoa(in)); } else if ((ntohs(ah->op) == ARPOP_REPLY)) { in.s_addr = si[0]; printf("%s is at ", inet_ntoa(in)); PRINT_MAC(ah->sea); } printf("\n"); } static void dmp_ip(void *dat) { iphdr *iph = (iphdr *)dat; icmphdr *icmp = (icmphdr *)(iph + 1); udphdr *uh = (udphdr *)(iph + 1); tcphdr *th = (tcphdr *)(iph + 1); u_char *data; struct in_addr in; printf("IPv%d, id: %x, length: %d, ttl: %d, sum: %4.4x", iph->ver, ntohs(iph->id), ntohs(iph->len), iph->ttl, ntohs(iph->cksum)); if ((ntohs(iph->frag) & IP_DF) == IP_DF) printf(", DF"); if (ntohs(iph->frag) & (IP_MF | IP_OFFMASK)) printf(", MF/%d", (ntohs(iph->frag) << 3) & 0xffff); in.s_addr = iph->sip; printf("\nAddress: %s -> ", inet_ntoa(in)); in.s_addr = iph->dip; printf("%s\n", inet_ntoa(in)); if ((ntohs(iph->frag) << 3) & 0xffff) return; if (iph->proto == IPPROTO_ICMP) { printf("Proto: icmp, "); printf("type: %d, ", icmp->type); printf("code: %d\n", icmp->code); printf("Desc: %s\n", icmpTypeCode2String(iph->ver, icmp->type, icmp->code)); } else if (iph->proto == IPPROTO_UDP) { printf("Proto: udp, len: %d, sum: %4.4x\n", ntohs(uh->len), ntohs(uh->cksum)); printf("Port: %d -> %d\n", ntohs(uh->sport), ntohs(uh->dport)); if (ntohs(uh->sport) == 53 || ntohs(uh->dport) == 53) return dmp_dns(dat); if (ntohs(uh->sport) == ntohs(uh->dport) && ntohs(uh->sport) == 520 && iph->dip == 0x90000e0) { data = (u_char *)(uh + 1); printf("Desc: RIP%d %s message\n", *(data + 1), (*data == 1) ? "request" : "response"); } } else if (iph->proto == IPPROTO_TCP) { printf("Proto: tcp, sum: %4.4x, ack: %8.8x, seq: %8.8x, ", ntohs(th->th_sum), ntohl(th->th_ack), ntohl(th->th_seq)); printf("flags: "); if (th->th_flags & TH_FIN) printf("F"); if (th->th_flags & TH_SYN) printf("S"); if (th->th_flags & TH_RST) printf("R"); if (th->th_flags & TH_PUSH) printf("P"); if (th->th_flags & TH_ACK) printf("A"); if (th->th_flags & TH_URG) printf("U"); if (th->th_flags & TH_ECE) printf("E"); if (th->th_flags & TH_CWR) printf("C"); printf("\n"); printf("Port: %d -> %d\n", ntohs(th->th_sport), ntohs(th->th_dport)); } } static void dmp_ip6(void *dat) { ip6hdr *iph = (ip6hdr *)dat; icmp6hdr *icmp = (icmp6hdr *)(iph + 1); udphdr *uh = (udphdr *)(iph + 1); tcphdr *th = (tcphdr *)(iph + 1); u_char *data; char *p; printf("IPv6, flowid: %x, length: %d, ttl: %d\n", ntohl(iph->ip6_flow & IPV6_FLOWLABEL_MASK), ntohs(iph->ip6_plen), iph->ip6_hlim); p = ip6tostr(iph->src.addr8); printf("Address: %s -> ", p); p = ip6tostr(iph->dst.addr8); printf("%s\n", p); if (iph->ip6_nxt == IPPROTO_ICMPV6) { printf("Proto: icmp, "); printf("type: %d, ", icmp->type); printf("code: %d", icmp->code); if (icmp->type == ICMP6_PACKET_TOO_BIG) printf(", mtu: %d", ntohl(icmp->icmp6_mtu)); printf("\n"); printf("Desc: %s\n", icmpTypeCode2String(6, icmp->type, icmp->code)); } else if (iph->ip6_nxt == IPPROTO_UDP) { printf("Proto: udp, len: %d, sum: %4.4x\n", ntohs(uh->len), ntohs(uh->cksum)); printf("Port: %d -> %d\n", ntohs(uh->sport), ntohs(uh->dport)); if (ntohs(uh->sport) == ntohs(uh->dport) && ntohs(uh->sport) == 521 && iph->dst.addr32[0] == IPV6_ADDR_INT32_MLL && iph->dst.addr32[1] == 0 && iph->dst.addr32[2] == 0 && iph->dst.addr32[3] == 0x09000000) { data = (u_char *)(uh + 1); printf("Desc: RIP%d %s message\n", *(data + 1), (*data == 1) ? "request" : "response"); } } else if (iph->ip6_nxt == IPPROTO_TCP) { printf("Proto: tcp, sum: %4.4x, ack: %8.8x, seq: %8.8x, ", ntohs(th->th_sum), ntohl(th->th_ack), ntohl(th->th_seq)); printf("flags: "); if (th->th_flags & TH_FIN) printf("F"); if (th->th_flags & TH_SYN) printf("S"); if (th->th_flags & TH_RST) printf("R"); if (th->th_flags & TH_PUSH) printf("P"); if (th->th_flags & TH_ACK) printf("A"); if (th->th_flags & TH_URG) printf("U"); if (th->th_flags & TH_ECE) printf("E"); if (th->th_flags & TH_CWR) printf("C"); printf("\n"); printf("Port: %d -> %d\n", ntohs(th->th_sport), ntohs(th->th_dport)); } } void dmp_dns(void *dat) { iphdr *iph = (iphdr *)dat; udphdr *uh = (udphdr *)(iph + 1); int iplen; char *p, *q; dnshdr *dh; u_short *sp; char name[256]; int i, j; int rlen; u_char c; u_short ptr, type, classt; u_int ttl; struct in_addr in; const char *rcode[6] = { "No error", "Format error", "Server failure", "Name error", "Not implement", "Refused"}; const char *typestr[16] = {"A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT"}; const char *classtr[4] = {"IN", "CS", "CH", "HS"}; /* make gcc happy */ union u_dnsflags { u_short flags; dnsflags dflags; } u_dnsflags; dnsflags *dflags; iplen = ntohs(iph->len); dh = (dnshdr *)(uh + 1); printf("DNS: QueryID = %x", dh->id); if (ntohs(uh->dport) == 53) { printf(", QueryFlags = %x\n", dh->flags); p = (char *)(dh + 1); i = j = 0; name[0] = '\0'; while (p + j - (char *)iph < iplen) { i = *(p + j); strncat(name, (char *)(p + j + 1), i); j += i + 1; if (*(p + j) == '\0') break; strcat(name, "."); } printf(" Host: %s", name); p += j + 1; type = *(u_short *)(p); classt = *((u_short *)(p) + 1); if (type == 0x0100) printf(", type = %s", typestr[0]); if (classt == 0x0100) printf(", class = IN"); printf("\n"); } else if (ntohs(uh->sport) == 53){ printf(", RespFlags = %x, ", dh->flags); u_dnsflags.flags = dh->flags; dflags = &u_dnsflags.dflags; if (dflags->rc != 0) { if (dflags->rc) printf("rc: %s", rcode[dflags->rc]); else printf("rc: %d", dflags->rc); } printf("\n"); printf(" Query = %d, Answer = %d, Auth = %d, Add = %d\n", ntohs(dh->query), ntohs(dh->answer), ntohs(dh->author), ntohs(dh->addition)); p = (char *)(dh + 1); j = dmp_dns_rname(p, (char *)iph + iplen, name); printf(" QueryHost: %s", name); p += j + 1; type = *(u_short *)(p); classt = *((u_short *)(p) + 1); if (type == 0x0100) printf(", type = %s", typestr[0]); if (classt == 0x0100) printf(", class = IN"); printf("\n"); p += 4; /* unpack record */ while (p - (char *)iph < iplen) { sp = (u_short *)p; ptr = ntohs(*sp); if ((ptr & 0xc000) == 0xc000) { q = (char *)(dh) + (ptr & 0x3fff); dmp_dns_rname(q, (char *)iph + iplen, name); printf(" RR: name = %s\n", name); } else { printf(" Only support compression scheme\n"); return; } sp ++; p += 2; type = ntohs(*sp); classt = ntohs(*(sp + 1)); ttl = ntohl(*((u_int *)(sp + 4))); if (type < 1 || type > 16) printf(" Invalid type (%d)", type); else printf(" type = %s", typestr[type - 1]); if (classt < 1 || classt > 4) printf(", Invalid class (%d)", classt); else printf(", class = %s", classtr[classt - 1]); printf(", TTL = %d", ttl); p += 2 + 2 + 4; sp = (u_short *)p; rlen = ntohs(*sp); if (type == 1 && rlen == 4) { in.s_addr = ((u_int *)(p + 2))[0]; printf(", addr = %s", inet_ntoa(in)); } else if (type == 2) { /* ns */ i = j = 0; memset(name, 0, sizeof(name)); q = p + 2; c = *(q + j); while (j < rlen) { strncat(name, (char *)(q + j + 1), c); j += i + 1; c = *(q + j); if (*(q + j) == '\0' || c > 64) break; strcat(name, "."); } printf("\n ns = %s", name); } else if (type == 5) { /* cname */ printf(", data length = %d\n", rlen); printf(" Cname: "); /* output cname name */ q = p + 2; c = *q; i = 0; while (1) { q++; for (j = 0; j < c; j++, i++) printf("%c", *(q + j)); q += c; c = *q; if (c == 0 || c > 64) break; printf("."); i++; } if (i + 1 < rlen && c > 64) { sp = (u_short *)q; dmp_dns_rname((char *)(dh) + (ntohs(*sp) & 0x3fff), (char *)iph + iplen, name); printf(".%s", name); } } else if (type == 6) { printf(", data length = %d\n", rlen); printf(" Name server: "); /* output ns server name */ q = p + 2; c = *q; while (1) { q++; for (j = 0; j < c; j++) printf("%c", *(q + j)); q += c; c = *q; if (c > 64) break; printf("."); } dmp_dns_rname((char *)(dh) + (ptr & 0x3fff), (char *)iph + iplen, name); printf(".%s\n", name); sp = (u_short *)q; /* output mail server name */ printf(" Responsible Mailbox: "); q = q + 2; c = *q; while (1) { q++; for (j = 0; j < c; j++) printf("%c", *(q + j)); q += c; c = *q; if (c > 64) break; printf("."); } dmp_dns_rname((char *)(dh) + (ntohs(*sp) & 0x3fff), (char *)iph + iplen, name); printf(".%s\n", name); /*output serial number */ q = q + 2; printf(" Serial number: %x\n", ntohl(((u_int *)q)[0])); printf(" Refresh interval: %s\n", dmp_dns_timestr(((u_int *)q)[1])); printf(" Retry interval: %s\n", dmp_dns_timestr(((u_int *)q)[2])); printf(" Expiration time: %s\n", dmp_dns_timestr(((u_int *)q)[3])); printf(" Minimum TTL: %s", dmp_dns_timestr(((u_int *)q)[4])); } p += 2 + rlen; printf("\n"); } /* while */ } /* if */ } static char * dmp_dns_timestr(u_int s) { static char buf[64]; int off = 0; buf[0] = '\0'; s = ntohl(s); if (s / (3600 * 24)) { off += snprintf(buf + off, sizeof(buf), "%d days", s / (3600 * 24)); s -= (s / (3600 * 24)) * (3600 * 24); } if (s / (3600)) { off += snprintf(buf + off, sizeof(buf), "%d hours", s / (3600)); s -= (s / (3600)) * (3600); } if (s / (60)) { off += snprintf(buf + off, sizeof(buf), "%d minutes", s / (60)); s -= (s / (60)) * (60); } if (s) { off += snprintf(buf + off, sizeof(buf), "%d minutes", s / (60)); } return buf; } FILE * open_dmpfile(const char *fname) { char tfname[1024]; FILE *fp; pcap_hdr_t phdr; time_t t0; struct tm *tm; t0 = time(0); tm = localtime(&t0); snprintf(tfname, sizeof(tfname), "%s_%4d%02d%02d%02d%02d%02d.pcap", fname, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); fp = fopen(tfname, "ab"); if (!fp) return NULL; phdr.magic_number = 0xa1b2c3d4; phdr.version_major = 2; phdr.version_minor = 4; phdr.thiszone = 0; phdr.sigfigs = 0; phdr.snaplen = 0xffff; phdr.network = 1; fwrite(&phdr, sizeof(phdr), 1, fp); fflush(fp); return fp; } void close_dmpfile(FILE *fp) { fclose(fp); } int dmp_packet2file(const struct packet *m, FILE *fp) { pcaprec_hdr_t phdr; struct timeval ts; gettimeofday(&(ts), (void*)0); phdr.ts_sec = ts.tv_sec; phdr.ts_usec = ts.tv_usec; phdr.incl_len = m->len; phdr.orig_len = m->len; fwrite(&phdr, sizeof(phdr), 1, fp); fwrite(m->data, m->len, 1, fp); fflush(fp); return 0; } int dmp_buffer2file(const char *m, int len, FILE *fp) { pcaprec_hdr_t phdr; struct timeval ts; gettimeofday(&(ts), (void*)0); phdr.ts_sec = ts.tv_sec; phdr.ts_usec = ts.tv_usec; phdr.incl_len = len; phdr.orig_len = len; if (!fp) return 0; fwrite(&phdr, sizeof(phdr), 1, fp); fwrite(m, len, 1, fp); fflush(fp); return 0; } vpcs-0.8.3/src/dump.h000066400000000000000000000047051447703427300144230ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _DUMP_H_ #define _DUMP_H_ #include #include "queue.h" typedef struct pcap_hdr_s { u_int magic_number; /* magic number */ u_short version_major; /* major version number */ u_short version_minor; /* minor version number */ u_int thiszone; /* GMT to local correction */ u_int sigfigs; /* accuracy of timestamps */ u_int snaplen; /* max length of captured packets, in octets */ u_int network; /* data link type */ } pcap_hdr_t; typedef struct pcaprec_hdr_s { u_int ts_sec; /* timestamp seconds */ u_int ts_usec; /* timestamp microseconds */ u_int incl_len; /* number of octets of packet saved in file */ u_int orig_len; /* actual length of packet */ } pcaprec_hdr_t; int dmp_packet(const struct packet *m, const int flag); FILE *open_dmpfile(const char *fname); void close_dmpfile(FILE *fp); int dmp_packet2file(const struct packet *m, FILE *fp); int dmp_buffer2file(const char *m, int len, FILE *fp); #endif vpcs-0.8.3/src/frag.c000066400000000000000000000163511447703427300143700ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include "queue.h" #include "frag.h" extern u_int time_tick; static struct fraglink *fraglink_head = NULL; static pthread_mutex_t fraglink_locker; #define LIST_LOCK_INIT pthread_mutex_init(&fraglink_locker, NULL) #define LIST_LOCK pthread_mutex_lock(&fraglink_locker) #define LIST_UNLOCK pthread_mutex_unlock(&fraglink_locker) #define LIST_FOREACH(nq) \ for ((nq) = fraglink_head; (nq) != NULL; (nq) = (nq)->next) #define FREE_NODE(n) do { \ if (n) { \ if ((n) == fraglink_head) \ fraglink_head = (n)->next; \ else \ (n)->prev->next = (n)->next; \ free(n); \ } \ } while (0); #define ADD_NODE(n) do { \ (n)->next = fraglink_head; \ fraglink_head = (n); \ } while (0); static struct packet *defrag(struct packet **m0); struct packet *ipfrag(struct packet *m0, int mtu) { struct packet *m = NULL, *mh = NULL; iphdr *ip = NULL, *ip0 = NULL; int hlen, len, off, elen, flen, last; int nfrags; elen = sizeof(ethdr) + sizeof(iphdr); ip0 = (iphdr *)(m0->data + sizeof(ethdr)); if (ntohs(ip0->len) <= mtu) return m0; hlen = ip0->ihl << 2; len = (mtu - hlen) & ~7; /* payload in fragment */ ip0->len = ntohs(ip0->len); /* too small, let it alone */ if (len < 8) return m0; flen = len; off = hlen + len; mh = m0; last = 0; for (nfrags = 1; off < ip0->len; off += len, nfrags++) { if (off + len >= ip0->len) { last = 1; m = new_pkt(elen + ip0->len - off); len = ip0->len - off; } else m = new_pkt(elen + len); if (m == NULL) goto ipfrag_err; /* ether and ip head */ memcpy(m->data, m0->data, elen); memcpy(m->data + elen, m0->data + sizeof(ethdr) + off, len); ip = (iphdr *)(m->data + sizeof(ethdr)); ip->frag = ((off -hlen) >> 3); if (!last) { ip->frag |= IP_MF; ip->len = htons(len + sizeof(iphdr)); } else ip->len = htons(sizeof(iphdr) + ip0->len - off); ip->frag = htons(ip->frag); ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); m->next = NULL; mh->next = m; mh = m; } m0->len = elen + flen; ip0->len = htons(flen + sizeof(iphdr)); ip0->frag = htons(IP_MF); ip0->cksum = 0; ip0->cksum = cksum((u_short *)ip0, sizeof(iphdr)); return m0; ipfrag_err: for (m = mh->next; m; m = mh) { mh = m->next; del_pkt(m); } return m0; } /* * return NULL, the packet is a piece, expired, or invalid. * return packet, all of pieces have been arrived and reassembled. */ struct packet * ipreass(struct packet *m) { ethdr *eh = (ethdr *)(m->data); iphdr *ip = (iphdr *)(eh + 1); iphdr *ip0; struct fraglink *nq = NULL; struct packet *m0 = NULL, *m2 = NULL; u_short off, off0; int next; ip->frag = ntohs(ip->frag); LIST_LOCK; LIST_FOREACH(nq) { if (time_tick - nq->expired > 30) { free_pkts(nq->m); FREE_NODE(nq); continue; } if (ip->id != nq->id || ip->proto != nq->proto || ip->sip != nq->sip || ip->dip != nq->dip) continue; /* a fragment is existed */ if ((ip->frag & IP_MF) == IP_MF) nq->flags |= FF_HEAD; else if ((ip->frag & (~IP_OFFMASK)) == 0) nq->flags |= FF_TAIL; off = ip->frag << 3; if (off == 0 && (ip->frag & IP_MF)) { if (!ip->len || (ip->len & 0x7) != 0) { del_pkt(m); free_pkts(nq->m); FREE_NODE(nq); goto ret_null; } m->next = nq->m; nq->m = m; } else { /* Find a segment, insertion sort on singly linked list */ m2 = NULL; for (m0 = nq->m; m0; m2 = m0, m0 = m0->next) { ip0 = (iphdr *)(m0->data + sizeof(ethdr)); off0 = ip0->frag << 3; if (off0 > off) break; } if (m2) { m->next = m2->next; m2->next = m; } else { m->next = nq->m; nq->m = m; } } nq->nfrags++; /* too many fragments */ if (nq->nfrags > 16) { free_pkts(nq->m); FREE_NODE(nq); goto ret_null; } /* the head and tail are arrived, scan the chain * Note: overlap is invalid here. */ if (nq->flags == (FF_TAIL | FF_HEAD)) { for (next = 0, m0 = nq->m; m0; m0 = m0->next) { ip0 = (iphdr *)(m0->data + sizeof(ethdr)); off0 = ip0->frag << 3; if (next < off0) goto ret_null; /* the last fragment */ if ((ip0->len & 0x7) != 0) { m = nq->m; FREE_NODE(nq); /* copy to single packet buffer * free the old buffer */ m = defrag(&m); goto ret; } next += ip0->len; } } goto ret_null; } /* new fragment */ nq = (struct fraglink *)malloc(sizeof(struct fraglink)); if (!nq) goto ret; memset(nq, 0, sizeof(struct fraglink)); nq->expired = time_tick; nq->nfrags = 1; nq->proto = ip->proto; nq->id = ip->id; nq->sip = ip->sip; nq->dip = ip->dip; nq->m = m; m->next = NULL; if ((ip->frag & IP_MF) == IP_MF) nq->flags = FF_HEAD; else if ((ip->frag & (~IP_OFFMASK)) == 0) nq->flags = FF_TAIL; ADD_NODE(nq); ret_null: LIST_UNLOCK; return NULL; ret: LIST_UNLOCK; return m; } static struct packet *defrag(struct packet **m0) { struct packet *m, *mh, *m2; iphdr *ip; int len; int elen; int off; mh = *m0; len = 0; while (mh) { ip = (iphdr *)(mh->data + sizeof(ethdr)); len += ntohs(ip->len) - sizeof(iphdr); mh = mh->next; } m = new_pkt(len + sizeof(iphdr) + sizeof(ethdr)); if (m == NULL) return *m0; mh = *m0; memcpy(m->data, mh->data, mh->len); ip = (iphdr *)(m->data + sizeof(ethdr)); ip->len = ntohs(len + sizeof(iphdr)); off = mh->len; elen = sizeof(ethdr) + sizeof(iphdr); m2 = mh; mh = mh->next; del_pkt(m2); while (mh) { len = mh->len - elen; memcpy(m->data + off, mh->data + elen, len); off += len; m2 = mh; mh = mh->next; del_pkt(m2); } ip->frag = 0; ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); return m; } void init_ipfrag(void) { LIST_LOCK_INIT; } /* */ #undef LIST_LOCK_INIT #undef LIST_LOCK #undef LIST_UNLOCK #undef LIST_FOREACH #undef FREE_NODE_SAFE #undef ADD_NODE /* end of file */ vpcs-0.8.3/src/frag.h000066400000000000000000000040451447703427300143720ustar00rootroot00000000000000/* * Copyright (c) 2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _FRAG_H_ #define _FRAG_H_ #include #include #include #include "ip.h" struct fraglink { struct fraglink *prev; struct fraglink *next; u_int expired; u_int flags:4, /* first and last fragments */ nfrags:4; /* count of fragments */ #define FF_HEAD 1 #define FF_TAIL 2 u_char proto; /* protocol of this fragment */ u_short id; /* sequence id for reassembly */ u_int sip; u_int dip; struct packet *m; /* to ip headers of fragments */ }; void init_ipfrag(void); struct packet *ipfrag(struct packet *m0, int mtu); struct packet *ipreass(struct packet *m); #endif vpcs-0.8.3/src/frag6.c000066400000000000000000000204321447703427300144510ustar00rootroot00000000000000/* * Copyright (c) 2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include "queue.h" #include "ip.h" #include "packets6.h" #include "frag6.h" extern u_int time_tick; static struct frag6link *frag6link_head = NULL; static pthread_mutex_t frag6link_locker; #define LIST_LOCK_INIT pthread_mutex_init(&frag6link_locker, NULL) #define LIST_LOCK pthread_mutex_lock(&frag6link_locker) #define LIST_UNLOCK pthread_mutex_unlock(&frag6link_locker) #define LIST_FOREACH(nq) \ for ((nq) = frag6link_head; (nq) != NULL; (nq) = (nq)->next) #define FREE_NODE(n) do { \ if ((n) == frag6link_head) frag6link_head = (n)->next; \ else (n)->prev->next = (n)->next; \ free(n); \ } while (0); #define ADD_NODE(n) do { \ (n)->next = frag6link_head; \ frag6link_head = (n); \ } while (0); static struct packet *defrag6(struct packet **m0); void init_ip6frag(void) { LIST_LOCK_INIT; } struct packet * ipfrag6(struct packet *m0, int mtu) { struct packet *m = NULL, *mh = NULL; ip6hdr *ip = NULL, *ip0 = NULL; struct ip6frag *ip6frag = NULL; int hlen, off, last, plen, ehlen, eilen, dlen, clen; int nfrags; u_int32_t frgid; u_int8_t nxt; ip0 = (ip6hdr *)(m0->data + sizeof(ethdr)); /* |<-- plen ..................................-->| * | ethdr | ip6hdr | data ...............................| * | frag1 | frag2 | ..... ......| fragn | * | ethdr | ip6hdr | ip6frag | frag1(dlen) | * |<-- eilen ...-->| * |<-- ehlen .............-->| * |<-- hlen ......-->| * |<-- mtu .....................-->| * | ethdr | ip6hdr | ip6frag | frag2(dlen) | * ... * | ethdr | ip6hdr | ip6frag | fragn | * */ plen = ntohs(ip0->ip6_plen) + sizeof(ip6hdr); if (plen <= mtu) return m0; eilen = sizeof(ethdr) + sizeof(ip6hdr); hlen = sizeof(ip6hdr) + sizeof(ip6frag); ehlen = sizeof(ethdr) + hlen; dlen = (mtu - hlen) & ~7; off = eilen + dlen; frgid = rand(); nxt = ip0->ip6_nxt; mh = m0; last = 0; for (nfrags = 1, last = 0; off < plen; off += dlen, nfrags++) { if (off + dlen >= plen) { last = 1; clen = plen - dlen * nfrags - sizeof(ip6hdr); } else clen = dlen; m = new_pkt(ehlen + clen); if (m == NULL) goto ipfrag6_err; /* ether, ip head, frag exthead, payload */ memcpy(m->data, m0->data, sizeof(ethdr) + sizeof(ip6hdr)); memcpy(m->data + ehlen, m0->data + off, dlen); ip = (ip6hdr *)(m->data + sizeof(ethdr)); ip->ip6_nxt = IPPROTO_FRAGMENT; ip->ip6_plen = htons(clen + sizeof(ip6frag)); ip6frag = (struct ip6frag *)(ip + 1); ip6frag->nxt = nxt; ip6frag->reserved = 0; ip6frag->offlg = htons((u_short)((off - eilen) & ~7)); ip6frag->ident = frgid; if (!last) ip6frag->offlg |= IP6F_MORE_FRAG; m->next = NULL; mh->next = m; mh = m; } m = new_pkt(ehlen + dlen); if (!m) goto ipfrag6_err; memcpy(m->data, m0->data + sizeof(ethdr) + sizeof(ip6hdr), dlen); dlen = (mtu - hlen) & ~7; ip0->ip6_nxt = 44; ip0->ip6_plen = htons(dlen + sizeof(ip6frag)); ip6frag = (struct ip6frag *)(ip0 + 1); ip6frag->nxt = nxt; ip6frag->reserved = 0; ip6frag->offlg = 0; ip6frag->offlg |= IP6F_MORE_FRAG; ip6frag->ident = frgid; memcpy(m0->data + ehlen, m->data, dlen); m0->len = ehlen + dlen; return m0; ipfrag6_err: for (m = mh->next; m; m = mh) { mh = m->next; del_pkt(m); } return m0; } struct packet * ipreass6(struct packet *m) { ethdr *eh = (ethdr *)(m->data); ip6hdr *ip = (ip6hdr *)(eh + 1); ip6hdr *ip0; struct frag6link *nq; struct ip6frag *fg = NULL, *fg0 = NULL; struct packet *m0 = NULL, *m2 = NULL; u_short off, off0; int hoff; if (ip->ip6_plen == 0) return m; hoff = ip6ehdr(ip, m->len - sizeof(ethdr), IPPROTO_FRAGMENT); if (hoff == 0) return m; fg = (struct ip6frag *)((char *)ip + hoff); off = ntohs((fg->offlg & IP6F_OFF_MASK)); LIST_LOCK; LIST_FOREACH(nq) { if (time_tick - nq->expired > 30) { free_pkts(nq->m); FREE_NODE(nq); continue; } if (fg->ident != nq->id || fg->nxt != nq->proto || !IP6EQ(&ip->src, &nq->sip) || !IP6EQ(&ip->dst, &nq->dip)) { continue; } if ((fg->offlg & IP6F_MORE_FRAG) && (fg->offlg & IP6F_OFF_MASK) == 0) { nq->flags |= FF_HEAD; }else if ((fg->offlg & IP6F_MORE_FRAG) == 0) nq->flags |= FF_TAIL; /* find a position and insert */ m2 = NULL; for (m0 = nq->m; m0; m2 = m0, m0 = m0->next) { ip0 = (ip6hdr *)(m0->data + sizeof(ethdr)); hoff = ip6ehdr(ip0, m->len - sizeof(ethdr), IPPROTO_FRAGMENT); if (hoff == 0) goto ret; fg0 = (struct ip6frag *)((char *)ip0 + hoff); off0 = ntohs((fg0->offlg & IP6F_OFF_MASK)); if (off0 > off) break; } if (m2) { m->next = m2->next; m2->next = m; } else { m->next = nq->m; nq->m = m; } nq->nfrags++; /* too many fragments */ if (nq->nfrags > 16) { free_pkts(nq->m); FREE_NODE(nq); goto ret_null; } /* the head and tail are arrived, scan the chain * Note: overlap is invalid here. */ if (nq->flags == (FF_TAIL | FF_HEAD)) { m = nq->m; FREE_NODE(nq); m = defrag6(&m); goto ret; } else goto ret_null; } /* new fragment */ nq = (struct frag6link *)malloc(sizeof(struct frag6link)); if (!nq) goto ret; memset(nq, 0, sizeof(struct frag6link)); nq->expired = time_tick; nq->nfrags = 1; nq->proto = fg->nxt; nq->id = fg->ident; memcpy(nq->sip.addr8, ip->src.addr8, sizeof(ip->src.addr8)); memcpy(nq->dip.addr8, ip->dst.addr8, sizeof(ip->dst.addr8)); nq->m = m; m->next = NULL; if ((fg->offlg & IP6F_MORE_FRAG) && (fg->offlg & IP6F_OFF_MASK) == 0) nq->flags = FF_HEAD; else if ((fg->offlg & IP6F_MORE_FRAG) == 0) nq->flags = FF_TAIL; ADD_NODE(nq); ret_null: LIST_UNLOCK; return NULL; ret: LIST_UNLOCK; return m; } struct packet *defrag6(struct packet **m0) { struct packet *m, *mh, *m2; struct ip6frag *fg = NULL; ip6hdr *ip; int len; int hoff, doff, off; u_int8_t nxt; /* calculate the payload size */ mh = *m0; ip = (ip6hdr *)(mh->data + sizeof(ethdr)); hoff = ip6ehdr(ip, mh->len - sizeof(ethdr), IPPROTO_FRAGMENT); doff = hoff + sizeof(struct ip6frag); fg = (struct ip6frag *)((char *)ip + hoff); nxt = fg->nxt; len = 0; while (mh) { ip = (ip6hdr *)(mh->data + sizeof(ethdr)); len = len + ntohs(ip->ip6_plen) + sizeof(ip6hdr) - doff; mh = mh->next; } m = new_pkt(len + hoff + sizeof(ethdr)); if (m == NULL) return *m0; /* copy the first header */ mh = *m0; memcpy(m->data, mh->data, hoff + sizeof(ethdr)); ip = (ip6hdr *)(m->data + sizeof(ethdr)); ip->ip6_nxt = nxt; ip->ip6_plen = htons(len + hoff - sizeof(ip6hdr)); off = hoff + sizeof(ethdr); /* copy the payload */ while (mh) { ip = (ip6hdr *)(mh->data + sizeof(ethdr)); len = ntohs(ip->ip6_plen) + sizeof(ip6hdr) - doff; memcpy(m->data + off, mh->data + sizeof(ethdr) + doff, len); off += len; m2 = mh; mh = mh->next; del_pkt(m2); } return m; } /* */ #undef LIST_LOCK_INIT #undef LIST_LOCK #undef LIST_UNLOCK #undef LIST_FOREACH #undef FREE_NODE #undef ADD_NODE /* end of file */ vpcs-0.8.3/src/frag6.h000066400000000000000000000040001447703427300144470ustar00rootroot00000000000000/* * Copyright (c) 2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _FRAG6_H_ #define _FRAG6_H_ #include #include #include #include "ip.h" struct frag6link { struct frag6link *prev; struct frag6link *next; struct packet *m; /* to ip headers of fragments */ u_int expired; u_int flags:4, /* first and last fragments */ nfrags:4; /* count of fragments */ #define FF_HEAD 1 #define FF_TAIL 2 u_char proto; /* protocol of this fragment */ u_int32_t id; /* sequence id for reassembly */ ip6 sip; ip6 dip; }; void init_ip6frag(void); struct packet *ipfrag6(struct packet *m0, int mtu); struct packet *ipreass6(struct packet *m); #endif vpcs-0.8.3/src/getopt.c000066400000000000000000000144131447703427300147500ustar00rootroot00000000000000/***************************************************************************** * getopt.c - competent and free getopt library. * $Header: /home/ubuntu/cvs/cvsroot/vpcs/getopt.c,v 1.2 2007-06-13 14:11:14 admin Exp $ * * Copyright (c)2002-2003 Mark K. Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * * Neither the original author of this software 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 COPYRIGHT HOLDERS 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 * COPYRIGHT OWNER 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. */ #include #include #include #include "getopt.h" //static const char* ID = "$Id$"; char* optarg = NULL; int optind = 0; int opterr = 1; int optopt = '?'; static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ static int prev_argc = 0; /* tell if getopt params change */ static int argv_index = 0; /* Option we're checking */ static int argv_index2 = 0; /* Option argument we're checking */ static int opt_offset = 0; /* Index into compounded "-option" */ static int dashdash = 0; /* True if "--" option reached */ static int nonopt = 0; /* How many nonopts we've found */ static void increment_index() { /* Move onto the next option */ if(argv_index < argv_index2) { while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' && argv_index < argv_index2+1); } else argv_index++; opt_offset = 1; } /* * Permutes argv[] so that the argument currently being processed is moved * to the end. */ static int permute_argv_once() { /* Movability check */ if(argv_index + nonopt >= prev_argc) return 1; /* Move the current option to the end, bring the others to front */ else { char* tmp = prev_argv[argv_index]; /* Move the data */ memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], sizeof(char**) * (prev_argc - argv_index - 1)); prev_argv[prev_argc - 1] = tmp; nonopt++; return 0; } } int getopt(int argc, char** argv, char* optstr) { int c = 0; /* If we have new argv, reinitialize */ if(prev_argv != argv || prev_argc != argc) { /* Initialize variables */ prev_argv = argv; prev_argc = argc; argv_index = 1; argv_index2 = 1; opt_offset = 1; dashdash = 0; nonopt = 0; } /* Jump point in case we want to ignore the current argv_index */ getopt_top: /* Misc. initializations */ optarg = NULL; /* Dash-dash check */ if(argv[argv_index] && !strcmp(argv[argv_index], "--")) { dashdash = 1; increment_index(); } /* If we're at the end of argv, that's it. */ if(argv[argv_index] == NULL) { c = -1; } /* Are we looking at a string? Single dash is also a string */ else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) { /* If we want a string... */ if(optstr[0] == '-') { c = 1; optarg = argv[argv_index]; increment_index(); } /* If we really don't want it (we're in POSIX mode), we're done */ else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) { c = -1; /* Everything else is a non-opt argument */ nonopt = argc - argv_index; } /* If we mildly don't want it, then move it back */ else { if(!permute_argv_once()) goto getopt_top; else c = -1; } } /* Otherwise we're looking at an option */ else { char* opt_ptr = NULL; /* Grab the option */ c = argv[argv_index][opt_offset++]; /* Is the option in the optstr? */ if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); else opt_ptr = strchr(optstr, c); /* Invalid argument */ if(!opt_ptr) { if(opterr) { fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); } optopt = c; c = '?'; /* Move onto the next option */ increment_index(); } /* Option takes argument */ else if(opt_ptr[1] == ':') { /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ if(argv[argv_index][opt_offset] != '\0') { optarg = &argv[argv_index][opt_offset]; increment_index(); } /* ie, -o ARGUMENT (only if it's a required argument) */ else if(opt_ptr[2] != ':') { /* One of those "you're not expected to understand this" moment */ if(argv_index2 < argv_index) argv_index2 = argv_index; while(argv[++argv_index2] && argv[argv_index2][0] == '-'); optarg = argv[argv_index2]; /* Don't cross into the non-option argument list */ if(argv_index2 + nonopt >= prev_argc) optarg = NULL; /* Move onto the next option */ increment_index(); } else { /* Move onto the next option */ increment_index(); } /* In case we got no argument for an option with required argument */ if(optarg == NULL && opt_ptr[2] != ':') { optopt = c; c = '?'; if(opterr) { fprintf(stderr,"%s: option requires an argument -- %c\n", argv[0], optopt); } } } /* Option does not take argument */ else { /* Next argv_index */ if(argv[argv_index][opt_offset] == '\0') { increment_index(); } } } /* Calculate optind */ if(c == -1) { optind = argc - nonopt; } else { optind = argv_index; } return c; } /* vim:ts=3 */ vpcs-0.8.3/src/globle.h000066400000000000000000000032701447703427300147160ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _GLOBLE_H_ #define _GLOBLE_H_ #ifndef DEV_TAP #define DEV_TAP 1 #endif #ifndef DEV_UDP #define DEV_UDP 2 #endif #define DEBUG 1 #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif #define MAX_NUM_PTHS 9 #ifndef IFNAMESIZ #define IFNAMESIZ 12 #endif #endif /* end of file */ vpcs-0.8.3/src/help.c000066400000000000000000000465511447703427300144060ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include "help.h" #include "utils.h" extern int num_pths; int help_clear(int argc, char **argv) { esc_prn("\n{Hclear} {Hip}|{Hipv6}|{Harp}|{Hneighbor}|{Hhist}\n" " Clear ip/ipv6 address, arp/neighbor table, command history.\n"); return 1; } int help_relay(int argc, char **argv) { char *s[2] = { "[{Uip1}:]{Uport1} [{Uip2}:]{Uport2}", "{Uip1} and {Uip2}"}; esc_prn("\n{Hrelay} {UARG}\n" " The relay command allows the VPCS to become a virtual patch panel where\n" " connections can be dynamically changed using the {Hrelay} command.\n" " There are three steps required to use VPCS as a virtual patch panel.\n" " 1. A relay {Hhub port} must be defined using the {Hrelay port} {Uport} command.\n" " 2. Remote NIO_UDP connections (cloud connections in GNS3) use this {Hhub}\n" " {Hport} as the remote port, ensuring each NIO_UDP connection has a unique \n" " {Hlocal} port (The local {Hport} numbers will be used to 'patch' the\n" " connection). VPC instances can be directed to use this hub port as\n" " their remote port using the command {Hset rport} {Uport}.\n" " 3. The 'patching' is completed using the command:\n" " {Hrelay add} [{Uip1}:]{Uport1} [{Uip2}:]{Uport2}, where {Uport1} and {Uport2} are the\n" " {Hlocal} port numbers used in step 2.\n" " ARG:\n" " {Hadd} %s Relay the packets between %s\n" " {Hdel} %s Delete the relay rule\n" " {Hdel} {Uid} Delete the relay rule\n" " {Hdump} [{Hon}|{Hoff}] Dump relay packets to file\n" " {Hport} {Uport} Set relay hub port\n" " {Hshow} Show the relay rules\n" " Note: %s are 127.0.0.1 by default\n", s[0], s[1], s[0], s[1]); return 1; } int help_ip(int argc, char **argv) { if (!strncmp(argv[0], "dhcp", strlen(argv[0])) || (argc == 3 && !strncmp(argv[1], "dhcp", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2]))))) { esc_prn("\n{Hip dhcp} [{UOPTION}]\n" " Attempt to obtain IPv4 address, mask, gateway and DNS via DHCP\n" " OPTION:\n" " {H-d} Show DHCP packet decode\n" " {H-r} Renew DHCP lease\n" " {H-x} Release DHCP lease\n"); return 1; } if (argc == 3 && (!strncmp(argv[1], "dns", strlen(argv[1])) || !strncmp(argv[1], "dns6", strlen(argv[1]))) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("\n{Hip [dns | dns6]} {Uip}\n" " Set DNS server {Uip}, delete if {Uip} is '0'.\n"); return 1; } if (argc == 3 && !strncmp(argv[1], "domain", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("\n\{Hip domain} {Uname}\n" " Sets local domain name. \n" " If there's no '.' in the host name: the name is assumed within the local\n" " domain, it is a short name relative to the local domain. The resolver\n" " will append the local domain name to the hostname to resolve it.\n"); return 1; } esc_prn("\n{Hip} {UARG} ... [{UOPTION}]\n" " Configure the current VPC's IP settings\n" " ARG ...:\n" " {Uaddress} [{Umask}] [{Ugateway}]\n" " {Uaddress} [{Ugateway}] [{Umask}]\n" " Set the VPC's ip, default gateway ip and network mask\n" " Default IPv4 mask is /24, IPv6 is /64. Example:\n" " {Hip 10.1.1.70/26 10.1.1.65} set the VPC's ip to 10.1.1.70,\n" " the gateway to 10.1.1.65, the netmask to 255.255.255.192.\n" " In tap mode, the ip of the tapx is the maximum host ID\n" " of the subnet. In the example above the tapx ip would be \n" " 10.1.1.126\n" " {Umask} may be written as /26, 26 or 255.255.255.192\n" " {Hauto} Attempt to obtain IPv6 address, mask and gateway using SLAAC\n" " {Hdhcp} [{UOPTION}] Attempt to obtain IPv4 address, mask, gateway, DNS via DHCP\n" " {H-d} Show DHCP packet decode\n" " {H-r} Renew DHCP lease\n" " {H-x} Release DHCP lease\n" " {Hdns} {Uip} Set DNS server {Uip}, delete if {Uip} is '0'\n" " {Hdns6} {Uipv6} Set DNS server {Uipv6}, delete if {Uipv6} is '0'\n" " {Hdomain} {UNAME} Set local domain name to {UNAME}\n"); return 1; } int help_load(int argc, char **argv) { esc_prn("\n{Hload} [{UFILENAME}[.vpc]]\n" " Load the configuration/script from the file {UFILENAME}. If {UFILENAME} ends with\n" " '.vpc', then the '.vpc' can be omitted. If {UFILENAME} is omitted then \n" " {Ustartup.vpc} will be loaded if it exists. When the file is loaded, each\n" " line of the file is executed as a VPCS command. If the state of the echo flag\n" " is on, the command will be echoed to the console before execution, except: \n" " * If the command is prefixed with a '@' symbol (eg {H@set echo color red});\n" " * If the command is an echo command;\n" " * If the command is a sleep command \n" " Note: The command {Hsleep 0} will be echoed if the echo flag is on\n" " See {Hset echo} and {Hshow echo}\n\n" " Note: Press Ctrl+C to interrupt the running script.\n"); return 1; } int help_ping(int argc, char **argv) { esc_prn("\n{Hping} {UHOST} [{UOPTION} ...]\n" " Ping the network {UHOST}. {UHOST} can be an ip address or name\n" " Options:\n" " {H-1} ICMP mode, default\n" " {H-2} UDP mode\n" " {H-3} TCP mode\n" " {H-c} {Ucount} Packet count, default 5\n" " {H-D} Set the Don't Fragment bit\n" " {H-f} {UFLAG} Tcp header FLAG |{HC}|{HE}|{HU}|{HA}|{HP}|{HR}|{HS}|{HF}|\n" " bits |7 6 5 4 3 2 1 0|\n" " {H-i} {Ums} Wait {Ums} milliseconds between sending each packet\n" " {H-l} {Usize} Data size\n" " {H-P} {Uprotocol} Use IP {Uprotocol} in ping packets\n" " {H1} - ICMP (default), {H17} - UDP, {H6} - TCP\n" " {H-p} {Uport} Destination port\n" " {H-s} {Uport} Source port\n" " {H-T} {Uttl} Set {Uttl}, default 64\n" " {H-t} Send packets until interrupted by Ctrl+C\n" " {H-w} {Ums} Wait {Ums} milliseconds to receive the response\n\n" " Notes: 1. Using names requires DNS to be set.\n" " 2. Use Ctrl+C to stop the command.\n"); return 1; } int help_trace(int argc, char **argv) { esc_prn("\n{Htrace} {UHOST} [{UOPTION} ...]\n" " Print the path packets take to the network {UHOST}. {UHOST} can be an ip address or\n" " name.\n" " Options:\n" " {H-P} {Uprotocol} Use IP {Uprotocol} in trace packets\n" " {H1} - icmp, {H17} - udp (default), {H6} - tcp\n" " {H-m} {Uttl} Maximum {Uttl}, default 8\n\n" " Notes: 1. Using names requires DNS to be set.\n" " 2. Use Ctrl+C to stop the command.\n"); return 1; } int help_rlogin(int argc, char **argv) { esc_prn("\n{Hrlogin} [{Uip}] {Uport}\n" " Telnet to {Uport} at {Uip} (default 127.0.0.1) relative to host PC. \n" " To attach to the console of a virtual router running on port 2000 of this\n" " host PC, use {Hrlogin 2000}\n" " To telnet to the port 2004 of a remote host 10.1.1.1, use\n" " {Hrlogin 10.1.1.1 2004}\n"); return 1; } int help_save(int argc, char **argv) { esc_prn("\n{Hsave} [{UFILENAME}[.vpc]]\n" " Save the configuration to the file {UFILENAME.vpc}. If there is no '.' in\n" " {UFILENAME} then a '.vpc' extension is added. If {UFILENAME} is omitted then the\n" " configuration will be saved to {Ustartup.vpc}\n"); return 1; } int help_write(int argc, char **argv) { esc_prn("\n{Hwrite} [{UFILENAME}[.vpc]]\n" " Save the configuration to the file {UFILENAME.vpc}. If there is no '.' in\n" " {UFILENAME} then a '.vpc' extension is added. If {UFILENAME} is omitted then the\n" " configuration will be saved to {Ustartup.vpc}\n"); return 1; } int help_set(int argc, char **argv) { if (argc == 3 && !strncmp(argv[1], "dump", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("\n{Hset dump} {Hall}|{Hdetail}|{Hfile}|{Hoff}|{Hmac}|{Hraw}\n" " Set the packet dump flags for this VPC\n" " {Hall} All the packets including incoming\n" " must use {Udetail}|{Umac}|{Uraw} as well as 'all'\n" " {Hdetail} Print protocol\n" " {Hfile} Dump packets to file 'vpcs[id]_yyyymmddHHMMSS.pcap'\n" " {Hmac} Print harware MAC address\n" " {Hoff} Clear all the flags\n" " {Hraw} Print the first 40 bytes\n"); return 1; } if (argc == 3 && !strncmp(argv[1], "echo", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("\n{Hset echo} {Hon}|{Hoff}|[{Hcolor} {Hclear}|{UFGCOLOR} [{UBGCOLOR}]]\n" " Sets the state of the echo flag used when executing script files,\n" " or sets the color of text to {UFGCOLOR} with optional {UBGCOLOR}\n" " Color list: black, red, green, yellow, blue, magenta, cyan, white\n" " See {Hload ?}.\n"); return 1; } if (argc == 3 && !strncmp(argv[1], "mtu", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("\n{Hset mtu} {Uvalue}\n" " Set the maximum transmission unit of the interface, at least 576.\n"); return 1; } esc_prn("\n{Hset} {UARG} ...\n" " Set hostname, connection port, ipfrag state, dump options and echo options\n" " ARG:\n" " {Hdump} {UFLAG} [[{UFLAG}]...] Set the packet dump flags for this VPC. \n" " FLAG:\n" " {Hall} All the packets including incoming.\n" " must use [detail|mac|raw] as well as 'all'\n" " {Hdetail} Print protocol\n" " {Hfile} Dump packets to file 'vpcs[id]_yyyymmddHHMMSS.pcap'\n" " {Hoff} Clear all the flags\n" " {Hmac} Print hardware MAC address\n" " {Hraw} Print the first 40 bytes\n" " {Hecho} {Hon}|{Hoff}|{Ucolor} ... Set echoing options. See {Hset echo ?}\n" " {Hlport} {Uport} Local port\n" " {Hmtu} {Uvalue} Set the maximum transmission unit of the interface\n" " {Hpcname} {UNAME} Set the hostname of the current VPC to {UNAME}\n" " {Hrport} {Uport} Remote peer port\n" " {Hrhost} {Uip} Remote peer host IPv4 address\n"); return 1; } int help_show(int argc, char **argv) { char *harp[2] = { "\n{Hshow arp} [{Udigit}|{Hall}]\n" " Show arp table for VPC {Udigit} (default this VPC) or all VPCs\n", "\n{Hshow arp}\n" " Show arp table\n"}; char *hdump[2] = { "\n{Hshow dump} [{Udigit}|{Hall}]\n" " Show dump flags for VPC {Udigit} (default this VPC) or all VPCs\n", "\n{Hshow dump}\n" " Show dump flags\n"}; char *hip[2] = { "\n{Hshow ip} [{Udigit}|{Hall}]\n" " Show IPv4 details for VPC {Udigit} (default this VPC) or all VPCs, including\n" " VPC Name, IP address, mask, gateway, DNS, MAC, lport, rhost:rport and MTU.\n", "\n{Hshow ip} [{Hall}]\n" " Show IPv4 details for including:\n" " VPC Name, IP address, mask, gateway, DNS, MAC, lport, rhost:rport and MTU.\n" " (reduced view in tablular format if 'all' option used)\n"}; char *hip6[2] = { "\n{Hshow ipv6} [{Udigit}|{Hall}]\n" " Show IPv6 details for VPC {Udigit} (default this VPC) or all VPCs, including\n" " VPC Name, IPv6 addresses/mask, router link-layer, MAC, lport, rhost:rport and\n" " MTU\n", "\n{Hshow ipv6} [{Hall}]\n" " Show IPv6 details, including:\n" " VPC Name, IPv6 addresses/mask, router link-layer, MAC, lport, rhost:rport and\n" " MTU (reduced view in tablular format if 'all' option used)\n"}; char *hmtu[2] = { "\n{Hshow mtu6} [{Udigit}|{Hall}]\n" " Show IPv6 mtu table for VPC {Udigit} (default this VPC) or all VPCs\n", "\n{Hshow mtu6}\n" " Show IPv6 mtu table\n"}; char *hh[3] = { "\n{Hshow} [{UARG}]\n" " Show information for ARG\n" " ARG:\n", " {Harp} [{Udigit}|{Hall}] Show arp table for VPC {Udigit} or all VPCs\n" " {Hdump} [{Udigit}|{Hall}] Show dump flags for VPC {Udigit} or all VPCs\n" " {Hecho} Show the status of the echo flag. See {Hset echo ?}\n" " {Hhistory} List the command history\n" " {Hip} [{Udigit}|{Hall}] Show IPv4 details for VPC {Udigit} or all VPCs\n" " shows VPC Name, IP address, mask, gateway, DNS, MAC, \n" " lport, rhost:rport and MTU\n" " {Hipv6} [{Udigit}|{Hall}] Show IPv6 details for VPC {Udigit} or all VPCs\n" " shows VPC Name, IPv6 addresses/mask, gateway, MAC,\n" " lport, rhost:rport and MTU\n" " {Hmtu6} [{Udigit}|{Hall}] Show IPv6 mtu table for VPC {Udigit} or all VPCs\n" " {Hversion} Show the version information\n\n" " Notes: \n" " 1. If no parameter is given, the key information of all VPCs will be displayed\n" " 2. If no parameter is given for {Harp}/{Hdump}/{Hip}/{Hipv6} information for the\n" " current VPC will be displayed.\n", " {Harp} Show arp table\n" " {Hdump} Show dump flags \n" " {Hecho} Show the status of the echo flag. See {Hset echo ?}\n" " {Hhistory} List the command history\n" " {Hip} [{Hall}] Show IPv4 details\n" " Shows VPC Name, IP address, mask, gateway, DNS, MAC, \n" " lport, rhost:rport and MTU\n" " {Hipv6} [{Hall}] Show IPv6 details\n" " Shows VPC Name, IPv6 addresses/mask, gateway, MAC,\n" " lport, rhost:rport and MTU\n" " {Hversion} Show the version information\n\n" " Notes: \n" " 1. If no parameter is given, the key information of the current VPC will be\n" " displayed\n" " 2. If 'all' parameter is given for {Hip}/{Hipv6} a reduced view in tablular\n" " format will be displayed.\n"}; if (argc == 3 && !strncmp(argv[1], "arp", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("%s", num_pths > 1 ? harp[0] : harp[1]); return 1; } if (argc == 3 && !strncmp(argv[1], "dump", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("%s", num_pths > 1 ? hdump[0] : hdump[1]); return 1; } if (argc == 3 && !strcmp(argv[1], "ip") && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("%s", num_pths > 1 ? hip[0] : hip[1]); return 1; } if (argc == 3 && !strcmp(argv[1], "ipv6") && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("%s", num_pths > 1 ? hip6[0] : hip6[1]); return 1; } if (argc == 3 && !strncmp(argv[1], "mtu6", strlen(argv[1])) && (!strcmp(argv[2], "?") || !strncmp(argv[2], "help", strlen(argv[2])))) { esc_prn("%s", num_pths > 1 ? hmtu[0] : hmtu[1]); return 1; } if (argc > 1 && (!strcmp(argv[argc - 1], "?") || !strncmp(argv[argc - 1], "help", strlen(argv[argc - 1])))) { esc_prn("%s", hh[0]); esc_prn("%s", num_pths > 1 ? hh[1] : hh[2]); return 1; } return 0; } int help_sleep(int argc, char **argv) { esc_prn("\n{Hsleep} [{Useconds}] [{Utext}]\n" " Print {Utext} and pause execution of script for {Utime} seconds.\n" " If {Useconds} is zero or missing, pause until a key is pressed. \n" " Default text when no parameters given: 'Press any key to continue'\n" " See {Hload} [{Ufilename}]\n"); return 1; } int help_help(int argc, char **argv) { esc_prn("\n{H%s}, Print help. Use {UCOMMAND} {H?} or " "{HCOMMAND} {UARG} {H?} for more help\n", argv[0]); return 1; } int run_help(int argc, char **argv) { esc_prn("\n" "{H?} Print help\n"); if (num_pths > 1) { esc_prn("{Udigit} Switch to the VPC{Udigit}. " "{Udigit} range 1 to %d\n", num_pths); } esc_prn("{Harp} %s Shortcut for: {Hshow arp}. " "Show arp table\n", (num_pths > 1) ? "[{Udigit}|{Hall}]" : " "); esc_prn("{Hclear} {UARG} Clear IPv4/IPv6, arp/neighbor cache, command history\n" "{Hdhcp} [{UOPTION}] Shortcut for: {Hip dhcp}. Get IPv4 address via DHCP\n" "{Hdisconnect} Exit the telnet session (daemon mode)\r\n" "{Hecho} {UTEXT} Display {UTEXT} in output. See also {Hset echo ?}\n" "{Hhelp} Print help\n" "{Hhistory} Shortcut for: {Hshow history}. List the command history\n" "{Hip} {UARG} ... [{UOPTION}] Configure the current VPC's IP settings. See {Hip ?}\n" "{Hload} [{UFILENAME}] Load the configuration/script from the file {UFILENAME}\n" "{Hping} {UHOST} [{UOPTION} ...] Ping {UHOST} with ICMP (default) or TCP/UDP. See {Hping ?}\n" "{Hquit} Quit program\n" "{Hrelay} {UARG} ... Configure packet relay between UDP ports. See {Hrelay ?}\n" "{Hrlogin} [{Uip}] {Uport} Telnet to {Uport} on host at {Uip} (relative to host PC)\n" "{Hsave} [{UFILENAME}] Save the configuration to the file {UFILENAME}\n" "{Hset} {UARG} ... Set VPC name and other options. Try {Hset ?}\n" "{Hshow} [{UARG} ...] Print the information of VPCs (default). See {Hshow ?}\n" "{Hsleep} [{Useconds}] [TEXT] Print TEXT and pause running script for {Useconds}\n" "{Htrace} {UHOST} [{UOPTION} ...] Print the path packets take to network {UHOST}\n" "{Hversion} Shortcut for: {Hshow version}\n\n" "To get command syntax help, please enter '{H?}' as an argument of the command.\n"); return 1; } /* end of file */ vpcs-0.8.3/src/help.h000066400000000000000000000043431447703427300144040ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _HELP_H_ #define _HELP_H_ int run_help(int argc, char **argv); int help_clear(int argc, char **argv); int help_echo(int argc, char **argv); int help_help(int argc, char **argv); int help_hist(int argc, char **argv); int help_ip(int argc, char **argv); int help_load(int argc, char **argv); int help_neighbor(int argc, char **argv); int help_ping(int argc, char **argv); int help_trace(int argc, char **argv); int help_relay(int argc, char **argv); int help_rlogin(int argc, char **argv); int help_save(int argc, char **argv); int help_set(int argc, char **argv); int help_show(int argc, char **argv); int help_shut(int argc, char **argv); int help_sleep(int argc, char **argv); int help_version(int argc, char **argv); int help_write(int argc, char **argv); #define EHL(x) "\033[1m"x"\033[0m" #define EUL(x) "\033[4m"x"\033[0m" #endif /* end of file */ vpcs-0.8.3/src/hv.c000066400000000000000000000417621447703427300140720ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Darwin #include #elif Linux || GNUkFreeBSD #include #elif FreeBSD #include #elif OpenBSD #include #include #endif #ifdef cygwin #include #endif #include #include "hv.h" #include "utils.h" #include "readline.h" #include "remote.h" static void set_telnet_mode(int s); static void loop(void); static void* pty_master(void *arg); static void* pty_slave(void *arg); static void clean(void); static int hypervisor(int port); static char *getpath(const char *name); extern int vpcs(int argc, char **argv); extern int help_rlogin(int argc, char **argv); static int run_vpcs(int ac, char **av); static int run_list(int ac, char **av); static int run_quit(int ac, char **av); static int run_disconnect(int ac, char **av); static int run_stop(int ac, char **av); static int run_help(int ac, char **av); static int run_rlogin(int ac, char **av); extern void usage(void); static struct list vpcs_list[MAX_DAEMONS]; static int ptyfdm, ptyfds; static FILE *fptys; static int sock = -1; static int sock_cli = -1; static int cmd_quit = 0; //static volatile int cmd_wait = 0; static pthread_t pid_master, pid_salve; static int hvport = 2000; static struct rls *rls = NULL; static char prgname[PATH_MAX]; static cmdStub cmd_entry[] = { {"?", run_help}, {"disconnect", run_disconnect}, {"help", run_help}, {"list", run_list}, {"quit", run_quit}, {"rlogin", run_rlogin}, {"telnet", run_rlogin}, {"stop", run_stop}, {"vpcs", run_vpcs}, {NULL, NULL}}; int main(int argc, char **argv, char** envp) { if (argc == 3 && !strcmp(argv[1], "-H")) { hvport = atoi(argv[2]); if (hvport < 1024 || hvport > 65000) { printf("Invalid port\n"); exit(1); } /* keep program name for vpcs */ #ifdef cygwin /* using windows native API to get 'real' path */ if (GetModuleFileName(NULL, prgname, PATH_MAX) == 0) { #else if (!getpath(argv[0])) { #endif printf("Can not get file path\n"); return 1; } return hypervisor(hvport); } /* go to vpcs */ return vpcs(argc, argv); } int hypervisor(int port) { struct sockaddr_in serv; int on = 1; setsid(); #if 1 if (daemon(1, 1)) { perror("Daemonize fail"); goto ret; } #endif memset(vpcs_list, 0, MAX_DAEMONS * sizeof(struct list)); if (openpty(&ptyfdm, &ptyfds, NULL, NULL, NULL)) { perror("Create pseudo-terminal"); goto ret; } signal(SIGCHLD, SIG_IGN); signal(SIGPIPE, SIG_IGN); fptys = fdopen(ptyfds, "w"); rls = readline_init(50, 128); rls->fdin = ptyfds; rls->fdout = ptyfds; if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) >= 0) { (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); //fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); bzero((char *) &serv, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = htonl(INADDR_ANY); serv.sin_port = htons(port); if (bind(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) { perror("Daemon bind port"); goto ret; } if (listen(sock, 5) < 0) { perror("Daemon listen"); goto ret; } loop(); close(sock); } ret: if (rls) readline_free(rls); return 1; } static void* pty_master(void *arg) { int i; u_char buf[128]; while (!cmd_quit) { memset(buf, 0, sizeof(buf)); i = read(ptyfdm, buf, sizeof(buf)); if (i > 0 && write(sock_cli, buf, i)) ; } return NULL; } static void* pty_slave(void *arg) { char *cmd; char *av[20]; int ac = 0; cmdStub *ep = NULL; int matched = 0; while (!cmd_quit) { cmd = readline("HV > " , rls); fprintf(fptys, "\r\n"); fflush(fptys); usleep(1); if (!cmd) continue; ttrim(cmd); ac = mkargv(cmd, (char **)av, 20); if (ac == 0) continue; for (ep = cmd_entry, matched = 0; ep->name != NULL; ep++) { if(!strncmp(av[0], ep->name, strlen(av[0]))) { matched = 1; break; } } if (matched) { ep->f(ac, av); } else ERR(fptys, "Invalid or incomplete command\r\n"); } return NULL; } static void loop(void) { struct sockaddr_in cli; int slen; u_char buf[256], *p; int i; fd_set set; struct timeval tv; slen = sizeof(cli); while (cmd_quit != 2) { cmd_quit = 0; sock_cli = accept(sock, (struct sockaddr *) &cli, (socklen_t *)&slen); if (sock_cli < 0) continue; set_telnet_mode(sock_cli); pthread_create(&pid_master, NULL, pty_master, NULL); pthread_create(&pid_salve, NULL, pty_slave, NULL); fcntl(0, F_SETFL, fcntl(sock_cli, F_GETFL) | O_NONBLOCK); while (!cmd_quit) { FD_ZERO(&set); FD_SET(sock_cli, &set); /* wait 1s */ tv.tv_sec = 1; tv.tv_usec = 0; i = select(sock_cli + 1, &set, NULL, NULL, &tv); /* error */ if (i < 0) break; /* time out */ if (i == 0) continue; if (FD_ISSET(sock_cli, &set)) { memset(buf, 0, sizeof(buf)); i = read(sock_cli, buf, sizeof(buf)); if (i < 0) break; if (i == 0) continue; p = buf; /* skip telnet IAC... */ if (*p == 0xff) while (*p && !isprint(*p)) p++; if (*p == '\0') continue; i = i - (p - buf); while (i > 0 && *(p + i - 1) == '\0') i--; if (i <= 0) continue; if (*p == CTRLD) { p = buf; strcpy((char *)buf, "disconnect\n"); i = strlen((char *)buf); i = write(ptyfdm, p, i); usleep(100); strcpy((char *)buf, "\n"); i = strlen((char *)buf); } /* ignore pty error */ if (write(ptyfdm, p, i)) ; } } pthread_cancel(pid_master); pthread_cancel(pid_salve); close(sock_cli); } } static void clean(void) { close(ptyfdm); close(ptyfds); close(sock_cli); close(sock); } static int run_vpcs(int ac, char **av) { int i, j, c; struct list *pv; pid_t pid; char *agv[20]; int agc = 0; char buf[1024]; int fd1; if (ac == 2 && !strcmp(av[1], "?")) { /* redirect STDOUT to socket */ fd1 = dup(STDOUT_FILENO); dup2(sock_cli, STDOUT_FILENO); usage(); fflush(stdout); dup2(fd1, STDOUT_FILENO); return 0; } /* find free slot */ for (i = 0; i < MAX_DAEMONS && vpcs_list[i].pid != 0; i++); if (i == MAX_DAEMONS) return 0; pv = &vpcs_list[i]; memset(pv, 0, sizeof(struct list)); /* reinitialized, maybe call getopt twice */ optind = 1; #if ((!defined(GNUkFreeBSD) && (defined(FreeBSD) || defined(OpenBSD))) || defined(Darwin)) optreset = 1; #endif while ((c = getopt(ac, av, "p:m:s:c:")) != -1) { switch (c) { case 'p': pv->vport = atoi(optarg); if (pv->vport == 0) { ERR(fptys, "Invalid daemon port\r\n"); return 1; } break; case 'm': pv->vmac = atoi(optarg); if (pv->vmac == 0) { ERR(fptys, "Invalid ether address\r\n"); return 1; } break; case 's': pv->vsport = atoi(optarg); if (pv->vsport == 0) { ERR(fptys, "Invalid local port\r\n"); return 1; } break; case 'c': pv->vcport = atoi(optarg); if (pv->vcport == 0) { ERR(fptys, "Invalid remote port\r\n"); return 1; } break; } } /* set the new daemon port */ if (pv->vport == 0) { j = 0; for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (vpcs_list[i].vport > j) j = vpcs_list[i].vport; } if (j == 0) pv->vport = hvport + 1; else pv->vport = j + 1; } else { for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (pv->vport != vpcs_list[i].vport) continue; ERR(fptys, "Port %d already in use\r\n", pv->vport); return 1; } } /* set the new mac */ if (pv->vmac == 0) { j = 0; c = 0; for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (vpcs_list[i].vmac > j) j = vpcs_list[i].vmac; c = 1; } if (j == 0) { /* there's vpcs which ether address start from 0 */ if (c == 1) pv->vmac = STEP; else pv->vmac = 0; } else pv->vmac = j + STEP; } else { for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (((pv->vmac >= vpcs_list[i].vmac) && ((pv->vmac - vpcs_list[i].vmac) < STEP)) || ((pv->vmac < vpcs_list[i].vmac) && ((vpcs_list[i].vmac - pv->vmac) < STEP))) { ERR(fptys, "Ether address overlapped\r\n"); return 1; } } } /* set the new local port */ if (pv->vsport == 0) { j = 0; for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (vpcs_list[i].vsport > j) j = vpcs_list[i].vsport; } if (j == 0) pv->vsport = DEFAULT_SPORT; else pv->vsport = j + STEP; } else { for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (((pv->vsport >= vpcs_list[i].vsport) && ((pv->vsport - vpcs_list[i].vsport) < STEP)) || ((pv->vsport < vpcs_list[i].vsport) && ((vpcs_list[i].vsport - pv->vsport) < STEP))) { ERR(fptys, "Local udp port overlapped\r\n"); return 1; } } } /* set the new remote port */ if (pv->vcport == 0) { j = 0; for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (vpcs_list[i].vcport > j) j = vpcs_list[i].vcport; } if (j == 0) pv->vcport = DEFAULT_CPORT; else pv->vcport = j + STEP; } else { for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; if (((pv->vcport >= vpcs_list[i].vcport) && ((pv->vcport - vpcs_list[i].vcport) < STEP)) || ((pv->vcport < vpcs_list[i].vcport) && ((vpcs_list[i].vcport - pv->vcport) < STEP))) { ERR(fptys,"Remote udp port overlapped\r\n"); return 1; } } } /* the arguments for vpcs */ i = 0; if (pv->vport) i += snprintf(buf + i, sizeof(buf) - i, "-p %d ", pv->vport); if (pv->vsport) i += snprintf(buf + i, sizeof(buf) - i, "-s %d ", pv->vsport); if (pv->vcport) i += snprintf(buf + i, sizeof(buf) - i, "-c %d ", pv->vcport); if (pv->vmac) i += snprintf(buf + i, sizeof(buf) - i, "-m %d ", pv->vmac); j = 1; while (j < ac) { if (!strcmp(av[j], "-p") || !strcmp(av[j], "-s") || !strcmp(av[j], "-c") || !strcmp(av[j], "-m")) { j += 2; continue; } i += snprintf(buf + i, sizeof(buf) - i, "%s ", av[j]); j++; } pv->cmdline = strdup(buf); agv[0] = "vpcs"; agv[1] = "-F"; agc = mkargv(buf, (char **)(agv + 2), 20); agc++; agc++; agv[agc] = NULL; pid = fork(); switch (pid) { case -1: return 0; case 0: /* 'real' vpcs */ clean(); if (execvp(prgname, agv) == -1) { syslog(LOG_ERR, "Execute vpcs failed: %s\n", strerror(errno)); } /* never here */ exit(0); break; default: pv->pid = pid; SUCC(fptys, "VPCS started with %s\r\n", pv->cmdline); break; } return 0; } static int run_list(int ac, char **av) { int i, k; fprintf(fptys, "ID\tPID\tParameters\r\n"); for (i = 0, k = 1; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; /* remove the invalid instance */ if (kill(vpcs_list[i].pid, 0)) { vpcs_list[i].pid = 0; continue; } fprintf(fptys, "%-2d\t%-5d\t%s\r\n", k, vpcs_list[i].pid, vpcs_list[i].cmdline); k++; } SUCC(fptys, "OK\r\n"); return 0; } static int run_disconnect(int ac, char **av) { cmd_quit = 1; return 0; } static int run_quit(int ac, char **av) { int i; char ans[8]; char *warning_quit = "Warning: there are active VPCS sessions.\r\n" "Are you sure you want to quit and terminate these sessions(y/N)? "; if (ac == 1) { for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid != 0) break; } /* There are active VPCS sessions */ if (i < MAX_DAEMONS) { i = write(sock_cli, warning_quit, strlen(warning_quit)); memset(ans, 0, sizeof(ans)); i = read(sock_cli, ans, sizeof(ans)); if (i <= 0) return 0; i = write(sock_cli, ans, strlen(ans)); i = write(sock_cli, "\r\n", 2); if (strcmp(ans, "y") && strcmp(ans, "Y")) return 0; } } else if (ac == 2 && strcmp(av[1], "-f")) return 1; else if (ac > 2) { ERR(fptys, "Invalid command\r\n"); return 1; } for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; kill(vpcs_list[i].pid, SIGUSR2); vpcs_list[i].pid = 0; if (vpcs_list[i].cmdline) free(vpcs_list[i].cmdline); } cmd_quit = 2; return 0; } static int run_rlogin(int argc, char **argv) { if (!strcmp(argv[argc - 1], "?")) return help_rlogin(argc, argv); if (argc == 2) { if (!digitstring(argv[1])) { printf("Invalid port\n"); return help_rlogin(argc, argv); } return open_remote(ptyfds, "127.0.0.1", atoi(argv[1])); } else if (argc == 3) { if (!digitstring(argv[2])) { printf("Invalid port\n"); return help_rlogin(argc, argv); } return open_remote(ptyfds, argv[1], atoi(argv[2])); } return help_rlogin(argc, argv); } static int run_stop(int ac, char **av) { int i, j, k, found = 0; if (ac == 1) { ERR(fptys, "Invalid or incomplete command\r\n"); return 1; } j = atoi(av[1]); i = 0; k = 0; for (i = 0; i < MAX_DAEMONS; i++) { if (vpcs_list[i].pid == 0) continue; k++; if (k != j) continue; SUCC(fptys, "VPCS PID %d is terminated\r\n", vpcs_list[i].pid); kill(vpcs_list[i].pid, SIGUSR2); vpcs_list[i].pid = 0; if (vpcs_list[i].cmdline) free(vpcs_list[i].cmdline); found = 1; break; } if (!found) ERR(fptys, "VPCS id %s does not exist\r\n", av[1]); return 0; } static int is_there(char *candidate) { struct stat fin; /* XXX work around access(2) false positives for superuser */ if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 && S_ISREG(fin.st_mode) && (getuid() != 0 || (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { return (1); } return (0); } static char * getpath(const char *name) { char *pathenv = NULL, *env; const char *d; int found; char rpath[PATH_MAX]; if (strchr(name, '/') != NULL) { strcpy(rpath, name); if (is_there(rpath)) { found = 1; goto ret; } else return NULL; } if (getenv("PATH") == NULL) return NULL; pathenv = strdup(getenv("PATH")); if (pathenv == NULL) return NULL; found = 0; env = pathenv; while ((d = strsep(&env, ":")) != NULL) { if (*d == '\0') d = "."; if (snprintf(rpath, sizeof(rpath), "%s/%s", d, name) >= (int)sizeof(rpath)) continue; if (is_there(rpath)) { found = 1; break; } } free(pathenv); ret: if (found) { return realpath(rpath, prgname); } else return NULL; } static int run_help(int ac, char **av) { esc_fprn(fptys, "{Hhelp} | {H?} Print help\r\n" "{Hdisconnect} Exit the telnet session\r\n" "{Hlist} List vpcs process\r\n" "{Hquit} [{H-f}] Stop vpcs processes and hypervisor\r\n" " {H-f} force quit without prompting\r\n" "{Hrlogin} [{Uip}] {Uport} Same as telnet\r\n" "{Hstop} {Uid} Stop vpcs process\r\n" "{Htelnet} [{Uip}] {Uport} Telnet to {Uport} at {Uip} (def 127.0.0.1)\r\n" "{Hvpcs} [{Uparameters}] Start vpcs with {Uparameters} of vpcs\r\n" ); return 0; } void set_telnet_mode(int s) { /* DO echo */ char *neg = "\xFF\xFD\x01" "\xFF\xFB\x01" "\xFF\xFD\x03" "\xFF\xFB\x03"; if (write(s, neg, strlen(neg))) ; } /* end of file */ vpcs-0.8.3/src/hv.h000066400000000000000000000040761447703427300140740ustar00rootroot00000000000000/* * Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _HV_H_ #define _HV_H_ #include #include #include #define delay_ms(x) usleep((x) * 1000) #define ERR(out, ...) do { \ fprintf(out, "200-"); \ fprintf(out, __VA_ARGS__); \ fflush(out); \ } while (0); #define SUCC(out, ...) do { \ fprintf(out, "100-"); \ fprintf(out, __VA_ARGS__); \ fflush(out); \ } while (0); #define DEFAULT_PORT (21000) #define DEFAULT_SPORT (20000) #define DEFAULT_CPORT (30000) #define STEP (10) #define MAX_DAEMONS (10) struct list { pid_t pid; int vport; int vmac; int vsport; int vcport; char *cmdline; }; typedef struct stub { char *name; int (*f)(int argc, char **argv); } cmdStub; #endif /* end of file */ vpcs-0.8.3/src/inet6.c000066400000000000000000000165051447703427300144770ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ /* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "inet6.h" static const char * inet_ntop4w(const u_char *src, char *dst, socklen_t size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; int l; l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); if (l <= 0 || (socklen_t) l >= size) { errno = ENOSPC; return (NULL); } strncpy(dst, tmp, size); return (dst); } static const char * vinet_ntop6w(const u_char *src, char *dst, socklen_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; struct { int base, len; } best, cur; u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; int i; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < NS_IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; best.len = 0; cur.base = -1; cur.len = 0; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 7 && words[7] != 0x0001) || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4w(src+12, tp, sizeof tmp - (tp - tmp))) return (NULL); tp += strlen(tp); break; } tp += sprintf(tp, "%x", words[i]); } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((socklen_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } strcpy(dst, tmp); return (dst); } static int vinet_pton6w(const char *src, u_char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, seen_xdigits; u_int val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; seen_xdigits = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (++seen_xdigits > 4) return (0); continue; } if (ch == ':') { curtok = src; if (!seen_xdigits) { if (colonp) return (0); colonp = tp; continue; } else if (*src == '\0') { return (0); } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; seen_xdigits = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton(AF_INET, curtok, tp) > 0) { tp += NS_INADDRSZ; seen_xdigits = 0; break; /*%< '\\0' was seen by inet_pton4(). */ } return (0); } if (seen_xdigits) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; if (tp == endp) return (0); for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } const char * vinet_ntop6(int af, const void * __restrict src, char * __restrict dst, socklen_t size) { switch (af) { case AF_INET6: return (vinet_ntop6w(src, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } int vinet_pton6(int af, const char * __restrict src, void * __restrict dst) { switch (af) { case AF_INET6: return (vinet_pton6w(src, dst)); default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* end of file */ vpcs-0.8.3/src/inet6.h000066400000000000000000000034131447703427300144760ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _INET6_H_ #define _INET6_H_ #include #ifndef NS_IN6ADDRSZ #define NS_IN6ADDRSZ 16 #endif #ifndef NS_INT16SZ #define NS_INT16SZ 2 #endif #ifndef NS_INADDRSZ #define NS_INADDRSZ 4 #endif int vinet_pton6(int af, const char * __restrict src, void * __restrict dst); const char *vinet_ntop6(int af, const void *src, char *dst, socklen_t cnt); #endif /* end of file */ vpcs-0.8.3/src/ip.c000066400000000000000000000166151447703427300140640ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include "ip.h" #include "queue.h" #include "inet6.h" u_long ip_masks[33] = { 0x0, 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF }; void swap_ehead(char *mbuf) { u_char mac[6]; ethdr *eh; eh = (ethdr *)mbuf; memcpy(mac, eh->dst, ETH_ALEN); memcpy(eh->dst, eh->src, ETH_ALEN); memcpy(eh->src, mac, ETH_ALEN); } void encap_ehead(char *mbuf, const u_char *sea, const u_char *dea, const u_short type) { ethdr *eh; eh = (ethdr *)mbuf; memcpy(eh->dst, dea, ETH_ALEN); memcpy(eh->src, sea, ETH_ALEN); eh->type = htons(type); } u_short cksum(register unsigned short *buffer, register int size) { register unsigned long cksum = 0; while (size > 1) { cksum += *buffer++; size -= sizeof(unsigned short); } if (size) cksum += *(unsigned char *) buffer; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (unsigned short) (~cksum); } u_short cksum_fixup(u_short cksum, u_short old, u_short new, u_short udp) { u_long l = 0; if (udp && !cksum) return (0x0000); l = cksum + old - new; l = (l >> 16) + (l & 0xffff); l = l & 0xffff; if (udp && !l) return (0xFFFF); return (l); } u_short cksum6(ip6hdr *ip, u_char nxt, int len) { int sum = 0; u_short *w; union { u_short phs[4]; struct { u_int ph_len; u_char ph_zero[3]; u_char ph_nxt; } ph; } uph; memset(&uph, 0, 8); uph.ph.ph_len = htonl(len); uph.ph.ph_nxt = nxt; sum += uph.phs[0]; sum += uph.phs[1]; sum += uph.phs[2]; sum += uph.phs[3]; w = (u_short *)&(ip->src); sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; w = (u_short *)&(ip->dst); sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; w = (u_short *)(ip + 1); while (len > 1) { sum += *w++; len -= sizeof(u_short); } if (len) sum += *(unsigned char *) w; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return (u_short) (~sum); } int sameNet(u_long ip1, u_long ip2, int cidr) { return ((ip_masks[cidr] & ntohl(ip1)) == (ip_masks[cidr] & ntohl(ip2))); } int sameNet6(char *s, char *d, int cidr) { int b; int i; b = cidr / 8; i = 0; while (i < b) { if (s[i] != d[i]) return 0; i++; } b = 8 - cidr % 8; if (i < 16 && ((s[i] >> b) & 0xff) != ((d[i] >> b) & 0xff)) return 0; return 1; } int getCIDR(u_long mask) { int i; for (i = 0; i < 33; i++) { if (ip_masks[i] == mask) return i; } // should not be here return 0; } void swap_ip6head(struct packet *m) { ip6 ip0; ip6hdr *ip; ip = (ip6hdr *)(m->data + sizeof(ethdr)); memcpy(ip0.addr8, ip->dst.addr8, 16); memcpy(ip->dst.addr8, ip->src.addr8, 16); memcpy(ip->src.addr8, ip0.addr8, 16); } int etherIsZero(u_char *mac) { u_char zero[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; return (!memcmp((const char *)mac, (const char *)zero, ETH_ALEN)); } int etherIsMulticast(u_char *mac) { u_char broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; return (!memcmp((const char *)mac, (const char *)broadcast, ETH_ALEN)); } const char *icmpTypeCode2String(int ipv, u_int8_t type, u_int8_t code) { const char *DestUnreach[] = { "Destination network unreachable", "Destination host unreachable", "Destination protocol unreachable", "Destination port unreachable", "Fragmentation required, and DF flag set", "Source route failed", "Destination network unknown", "Destination host unknown", "Source host isolated", "Network administratively prohibited", "Host administratively prohibited", "Network unreachable for TOS", "Host unreachable for TOS", "Communication administratively prohibited"}; const char *Redirect[] = { "Redirect Datagram for the Network", "Redirect Datagram for the Host", "Redirect Datagram for the TOS & network", "Redirect Datagram for the TOS & host"}; const char *TimeExceed[] = { "TTL expired in transit", "Fragment reassembly time exceeded"}; const char *Dest6Unreach[] = { "No route to destination", "Communication with destination administratively prohibited", "Beyond scope of source address", "Address unreachable", "Port unreachable", "Source address failed ingress/egress policy", "Reject route to destination"}; const char *Time6Exceed[] = { "Hop limit exceeded in transit", "Fragment reassembly time exceeded"}; const char *ND_messesg[] = { /* start from 133 to 137 */ "ICMPv6 router solicitation", "ICMPv6 router advertisement", "ICMPv6 neighbor solicitation", "ICMPv6 neighbor advertisement", "ICMPv6 redirect"}; const char *empty = ""; if (ipv == 4) { switch (type) { case 0: return "Echo reply"; case 8: return "Echo"; case 3: if (code <= 13) return DestUnreach[code]; break; case 5: if (code <= 3) return Redirect[code]; break; case 11: if (code <= 1) return TimeExceed[code]; break; default: break; } } else if (ipv == 6) { switch (type) { case 1: if (code <= 6) return Dest6Unreach[code]; break; case 2: return "ICMPv6 packet too big"; case 3: if (code <= 1) return Time6Exceed[code]; break; case 128: return "ICMPv6 echo request"; case 129: return "ICMPv6 echo reply"; case 133: case 134: case 135: case 136: case 137: return ND_messesg[type - 133]; default: break; } } return empty; } char *ip6tostr(const u_char *ip6) { struct in6_addr ipaddr; static char buf[INET6_ADDRSTRLEN + 1]; memset(buf, 0, INET6_ADDRSTRLEN + 1); memcpy(ipaddr.s6_addr, ip6, 16); vinet_ntop6(AF_INET6, &ipaddr, buf, INET6_ADDRSTRLEN + 1); return buf; } /* end of file */ vpcs-0.8.3/src/ip.h000066400000000000000000000321441447703427300140640ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _IP_H_ #define _IP_H_ #include #include #include #include #include #define MTU 1500 #define IPV6_MMTU 1280 #define ETH_ALEN 6 #define ETHERTYPE_IP 0x0800 /* IP */ #define ETHERTYPE_ARP 0x0806 /* Address resolution */ struct ethdr { u_char dst[ETH_ALEN]; /* destination eth addr */ u_char src[ETH_ALEN]; /* source ether addr */ u_short type; /* packet type ID field */ }; typedef struct ethdr ethdr; #define ARPHRD_ETHER 1 /* ethernet hardware format */ #define ARPOP_REQUEST 1 /* request to resolve address */ #define ARPOP_REPLY 2 /* response to previous request */ struct vpcs_arphdr { u_short hrd; /* format of hardware address */ u_short pro; /* format of protocol address */ u_char hln; /* length of hardware address */ u_char pln; /* length of protocol address */ u_short op; /* one of: */ u_char sea[ETH_ALEN]; u_char sip[4]; u_char dea[ETH_ALEN]; u_char dip[4]; }; typedef struct vpcs_arphdr vpcs_arphdr; struct iphdr { u_int ihl:4, /* ip header length, should be 20 bytes */ ver:4; /* version */ u_char tos; /* type of service */ u_short len; /* ip packet length */ u_short id; /* identification */ u_short frag; /* fragment offset field */ #define IP_DF 0x4000 #define IP_MF 0x2000 #define IP_OFFMASK 0x1fff u_char ttl; /* time to live */ #define TTL 64 u_char proto; /* protocol */ u_short cksum; /* checksum */ u_int sip; u_int dip; /* source and dest address */ }; typedef struct iphdr iphdr; #ifndef IPPROTO_ICMP #define IPPROTO_ICMP 1 #endif #ifndef ICMP_ECHO #define ICMP_ECHO 8 #endif #ifndef ICMP_ECHOREPLY #define ICMP_ECHOREPLY 0 #endif #ifndef ICMP_TIMXCEED #define ICMP_TIMXCEED 11 #endif #ifndef ICMP_UNREACH #define ICMP_UNREACH 3 #endif #ifndef ICMP_UNREACH_PORT #define ICMP_UNREACH_PORT 3 #endif #ifndef ICMP_UNREACH_NEEDFRAG #define ICMP_UNREACH_NEEDFRAG 4 #endif #ifndef ICMP_REDIRECT #define ICMP_REDIRECT 5 #define ICMP_REDIRECT_NET 0 #endif struct icmphdr { u_char type; /* echo or echo reply */ u_char code; /* type sub code */ u_short cksum; u_short id; u_short seq; }; typedef struct icmphdr icmphdr; struct icmprdr { u_char type; /* echo or echo reply */ u_char code; /* type sub code */ u_short cksum; u_int ip; u_char data[0]; }; typedef struct icmprdr icmprdr; struct icmpthdr { icmphdr b; u_int timestamp; }; typedef struct icmpthdr icmpthdr; #ifndef IPPROTO_UDP #define IPPROTO_UDP 17 #endif #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 #endif struct ipovly { u_char ih_x1[9]; /* (unused) */ u_char ih_pr; /* protocol */ u_short ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ }; typedef struct { u_short sport; u_short dport; u_short len; u_short cksum; } udphdr; struct udpiphdr { struct ipovly ui_i; /* overlaid ip structure */ udphdr ui_u; /* udp header */ }; #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.sport #define ui_dport ui_u.dport #define ui_ulen ui_u.len #define ui_sum ui_u.cksum typedef struct udpiphdr udpiphdr; struct tcphdr { u_short th_sport; /* source port */ u_short th_dport; /* destination port */ u_int th_seq; /* sequence number */ u_int th_ack; /* acknowledgement number */ #if BYTE_ORDER == LITTLE_ENDIAN u_int th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int th_off:4, /* data offset */ th_x2:4; /* (unused) */ #endif u_char 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 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECE|TH_CWR) #define PRINT_TH_FLAGS "\20\1FIN\2SYN\3RST\4PUSH\5ACK\6URG\7ECE\10CWR" u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */ }; typedef struct tcphdr tcphdr; struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ struct tcphdr ti_t; /* tcp header */ }; typedef struct tcpiphdr tcpiphdr; #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 #define TCPOPT_MAXSEG 2 #define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 #define TCPOLEN_WINDOW 3 #define TCPOPT_TIMESTAMP 8 #define TCPOLEN_TIMESTAMP 10 #define PKT_MAXSIZE 1520 #define ARP_PSIZE 64 #define ICMP_PSIZE 128 #define UDP_PSIZE 128 /* define ipv6 */ #define ETHER_MAP_IPV6_MULTICAST(ip6addr, enaddr) \ { \ (enaddr)[0] = 0x33; \ (enaddr)[1] = 0x33; \ (enaddr)[2] = ((u_char *)ip6addr)[12]; \ (enaddr)[3] = ((u_char *)ip6addr)[13]; \ (enaddr)[4] = ((u_char *)ip6addr)[14]; \ (enaddr)[5] = ((u_char *)ip6addr)[15]; \ } #define ETHERTYPE_IPV6 0x86DD /* IP */ typedef struct { union { u_char _a8[16]; u_short _a16[8]; u_int _a32[4]; } uaddr; } ip6; #define addr8 uaddr._a8 #define addr16 uaddr._a16 #define addr32 uaddr._a32 #define IN6_IS_MULTICAST(a) ((a)->addr8[0] == 0xff) typedef struct { union { struct ip6_hdrctl { u_int ip6_un1_flow; /* 20 bits of flow-ID */ u_short ip6_un1_plen; /* payload length */ u_char ip6_un1_nxt; /* next header */ u_char ip6_un1_hlim; /* hop limit */ } ip6_un1; u_char ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; ip6 src; /* source address */ ip6 dst; /* destination address */ } ip6hdr; #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim #define IPV6_VERSION 0x60 #define IPV6_VERSION_MASK 0xf0 #define IPV6_FLOWLABEL_MASK 0xffff0f00 #define IPV6_ADDR_INT32_ONE 0x01000000 #define IPV6_ADDR_INT32_TWO 0x02000000 #define IPV6_ADDR_INT32_MNL 0x000001ff #define IPV6_ADDR_INT32_MLL 0x000002ff #define IPV6_ADDR_INT32_SMP 0xffff0000 #define IPV6_ADDR_INT16_ULL 0x80fe #define IPV6_ADDR_INT16_USL 0xc0fe #define IPV6_ADDR_INT16_MLL 0x02ff #define IP6EQ(s, d) (!memcmp((s)->addr8, (d)->addr8, 16)) #define IP6ZERO(s) (((s)->addr32[0] == 0) && \ ((s)->addr32[1] == 0) && \ ((s)->addr32[0] == 0) && \ ((s)->addr32[0] == 0)) typedef struct { u_int8_t nxt; u_int8_t len; } ip6eh; struct ip6frag { u_int8_t nxt; /* next header */ u_int8_t reserved; /* reserved field */ u_int16_t offlg; /* 13 bits offset */ u_int32_t ident; /* identification */ }; #define IPV6_SFRAG_OFFSET(p, o) (p)->offlg = htons((ntohs((p)->offlg) & ~0x1fff) + ((o) & 0x1fff)) #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ #ifndef IPPROTO_FRAGMENT #define IPPROTO_FRAGMENT 44 #endif #ifndef IPPROTO_AH #define IPPROTO_AH 51 /* only for check ehdr, its length is */ #endif #ifndef IPV6_MMTU #define IPV6_MMTU 1280 #endif typedef struct { u_int8_t type; /* type field */ u_int8_t code; /* code field */ u_int16_t cksum; /* checksum field */ union { u_int32_t icmp6_un_data32[1]; /* type-specific field */ u_int16_t icmp6_un_data16[2]; /* type-specific field */ u_int8_t icmp6_un_data8[4]; /* type-specific field */ } icmp6_dataun; } icmp6hdr; #define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data16 icmp6_dataun.icmp6_un_data16 #define icmp6_data8 icmp6_dataun.icmp6_un_data8 #define icmp6_pptr icmp6_data32[0] /* parameter prob */ #define icmp6_mtu icmp6_data32[0] /* packet too big */ #define icmp6_id icmp6_data16[0] /* echo request/reply */ #define icmp6_seq icmp6_data16[1] /* echo request/reply */ #ifndef IPPROTO_ICMP #define IPPROTO_ICMP 1 #endif #ifndef ICMP_ECHO #define ICMP_ECHO 8 #endif #ifndef ICMP_ECHOREPLY #define ICMP_ECHOREPLY 0 #endif #ifndef ICMP_TIMXCEED #define ICMP_TIMXCEED 11 #endif #ifndef ICMP_UNREACH #define ICMP_UNREACH 3 #endif #ifndef ICMP_UNREACH_PORT #define ICMP_UNREACH_PORT 3 #endif #ifndef IPPROTO_ICMPV6 #define IPPROTO_ICMPV6 58 #endif #ifndef ICMP6_ECHO_REQUEST #define ICMP6_ECHO_REQUEST 128 /* echo service */ #endif #ifndef ICMP6_ECHO_REPLY #define ICMP6_ECHO_REPLY 129 /* echo reply */ #endif #ifndef ICMP6_DST_UNREACH #define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */ #endif #ifndef ICMP6_PACKET_TOO_BIG #define ICMP6_PACKET_TOO_BIG 2 /* packet too big */ #endif #ifndef ICMP6_TIME_EXCEEDED #define ICMP6_TIME_EXCEEDED 3 /* time exceeded, code: */ #endif #ifndef ICMP6_DST_UNREACH_NOPORT #define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */ #endif typedef struct tcpcb6 { u_int timeout; ip6 sip; ip6 dip; u_int sport; u_int dport; u_int ack; u_int seq; u_short winsize; u_char flags; /* my flags */ u_char rflags; /* remote tcp flags */ } tcpcb6; #ifndef ND_ROUTER_SOLICIT #define ND_ROUTER_SOLICIT 133 /* router solicitation */ #define ND_ROUTER_ADVERT 134 /* router advertisement */ #define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */ #define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisement */ #define ND_REDIRECT 137 /* redirect */ #endif typedef struct { icmp6hdr hdr; ip6 target; } ndhdr; typedef struct { u_char type; u_char len; u_char mac[6]; } ndopt; #define nd_na_flags hdr.icmp6_data32[0] #define ND_NA_FLAG_OVERRIDE 0x20 typedef struct { icmp6hdr hdr; u_int reachable; u_int retransmit; } ndrahdr; #define nd_ra_curhoplimit hdr.icmp6_data8[0] #define nd_ra_router_lifetime hdr.icmp6_data16[1] #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 #define ND_RA_FLAG_HA 0x20 #define DMP_MAC 1 #define DMP_RAW 2 #define DMP_DETAIL 4 #define DMP_ALL 0x80 #define DMP_FILE 0x1000 struct packet; /* defined in queue.h */ typedef struct sesscb { int sock; u_int timeout; u_int sn; u_int waittime; u_char smac[6]; u_char dmac[6]; u_int sip; u_int dip; u_int rdip; ip6 sip6; ip6 dip6; ip6 rdip6; u_int sport; u_int dport; u_int ipid; int proto; int dsize; int rdsize; u_int ack; u_int seq; u_int rack; u_int rseq; u_short winsize; u_char flags; /* my flags */ u_char rflags; /* remote tcp flags */ u_char ttl; u_char rttl; u_short rmss; /* TCP MSS */ int aproto; u_char icmptype; u_char icmpcode; int mtu; u_char frag; char *data; } sesscb; void encap_ehead(char *mbuf, const u_char *sea, const u_char *dea, const u_short type); void swap_ehead(char *mbuf); u_short cksum(register unsigned short *buffer, register int size); u_short cksum_fixup(u_short cksum, u_short old, u_short new, u_short udp); u_short cksum6(ip6hdr *ip, u_char nxt, int len); int etherIsZero(u_char *mac); int etherIsMulticast(u_char *mac); int sameNet(u_long ip1, u_long ip2, int cidr); int sameNet6(char *s, char *d, int cidr); void swap_ip6head(struct packet *m); int getCIDR(u_long mask); const char *icmpTypeCode2String(int ipv, u_int8_t type, u_int8_t code); char *ip6tostr(const u_char *ip6); #define PRINT_MAC(x) \ printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5]); #endif /* end of file */ vpcs-0.8.3/src/keydef.h000066400000000000000000000017661447703427300147310ustar00rootroot00000000000000#ifndef _KEYDEF_H_ #define _KEYDEF_H_ #define CTRLA 1 #define CTRLB 2 #define CTRLC 3 #define CTRLD 4 #define CTRLE 5 #define CTRLF 6 #define CTRLG 7 #define CTRLH 8 #define CTRLI 9 #define CTRLJ 10 #define CTRLK 11 #define CTRLL 12 #define CTRLM 13 #define CTRLN 14 #define CTRLO 15 #define CTRLP 16 #define CTRLQ 17 #define CTRLR 18 #define CTRLS 19 #define CTRLT 20 #define CTRLU 21 #define CTRLV 22 #define CTRLW 23 #define CTRLX 24 #define CTRLY 25 #define CTRLZ 26 #define CTRL3 27 #define CTRL4 28 #define CTRL5 29 #define CTRL6 30 #define CTRL7 31 #define BACKSP0 8 /* backspace */ #define BACKSP1 127 /* backspace */ #define LF 10 #define CR 13 /* escape seqence */ #define ESC 27 /* 27 area */ #define ESC_ALT 0x1b /* 91 area */ #define ESC_PAD 0x5b #define KEY_HOME 0x7e31 #define KEY_INSERT 0x7e32 #define KEY_DELETE 0x7e33 #define KEY_END 0x7e34 #define KEY_UP 0x0041 #define KEY_DOWN 0x0042 #define KEY_RIGHT 0x0043 #define KEY_LEFT 0x0044 #endif vpcs-0.8.3/src/mk.sh000077500000000000000000000024501447703427300142460ustar00rootroot00000000000000#!/bin/sh os=`uname` if [ $# -eq 0 ]; then arch=`uname -p` fi CCOPT="-O2" if [ $# -eq 1 ]; then case $1 in clean) MKOPT=clean arch=`uname -p` ;; debug) CCOPT="-g" MKOPT=debug arch=`uname -p` ;; *) arch=$1 esac fi if [ $# -eq 2 ]; then case $1 in clean) MKOPT=clean arch=$2 ;; debug) CCOPT="-g" MKOPT=debug arch=$2 ;; esac case $2 in clean) MKOPT=clean arch=$1 ;; debug) CCOPT="-g" MKOPT=debug arch=$1 ;; esac fi if [ "x$arch" = "x" ]; then echo $0" [i386 | amd64 | 32 | 64] [clean | debug]" exit 1 fi if [ $arch = "i386" -o $arch = "32" ]; then CCOPT=$CCOPT" -m32" fi if [ $arch = "amd64" -o $arch = "x86_64" -o $arch = "64" ]; then CCOPT=$CCOPT" -m64" fi if [ $os = "Darwin" ]; then CCOPT=$CCOPT"" fi export CCOPT case ${os} in FreeBSD) make -f Makefile.fbsd ${MKOPT} ;; OpenBSD) make -f Makefile.obsd ${MKOPT} ;; Linux) make -f Makefile.linux ${MKOPT} ;; CYGWIN*) make -f Makefile.cygwin ${MKOPT} ;; Darwin) make -f Makefile.osx ${MKOPT} ;; *) echo "Not support: ${os}" ;; esac vpcs-0.8.3/src/packets.c000066400000000000000000000431471447703427300151060ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include /* isprint */ #include /* usleep */ #include #include #include "packets.h" #include "vpcs.h" #include "utils.h" #define IPFRG_MAXHASH (1 << 10) #define IPFRG_HASHMASK (IPFRG_MAXHASH - 1) #define IPFRG_HASH(x,y) \ (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPFRG_HASHMASK) u_char broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static struct packet *arp(pcs *pc, u_int dip); static struct packet *udpReply(struct packet *m0); static struct packet *icmpReply(struct packet *m0, char icmptype, char icmpcode); static void save_eaddr(pcs *pc, u_int addr, u_char *mac); extern int upv6(pcs *pc, struct packet **m); extern void send6(pcs *pc, struct packet *m); extern int tcp(pcs *pc, struct packet *m); /* static void free_ipfrag(struct ipfrag_head *head, struct ipfrag *fp); static void free_packet(struct packet *m); static struct ipfrag *new_ipfrag(struct packet *m, iphdr *ip); static struct packet *defrag_pkt(struct packet **); */ // 1 : ok // 0 : error static int fix_dmac(pcs *pc, struct packet *m); extern u_int time_tick; /* * ipv4 stack * * code: PKT_UP, send to up layer * PKT_ENQ, in out queue * PKT_DROP, drop the packet */ int upv4(pcs *pc, struct packet **m0) { struct packet *m = *m0; ethdr *eh = (ethdr *)(m->data); u_int *si, *di; if (eh->type == htons(ETHERTYPE_IPV6)) return upv6(pc, m0); /* not ipv4 or arp */ if ((eh->type != htons(ETHERTYPE_IP)) && (eh->type != htons(ETHERTYPE_ARP))) return PKT_DROP; if (etherIsMulticast(eh->src)) return PKT_DROP; if ( (memcmp(eh->dst, pc->ip4.mac, ETH_ALEN) == 0 || memcmp(eh->dst, broadcast, ETH_ALEN) == 0) && ((u_short*)m->data)[6] == htons(ETHERTYPE_IP)) { struct packet *p; iphdr *ip = (iphdr *)(eh + 1); if (ntohs(ip->len) > pc->mtu) { p = icmpReply(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG); if (p) { fix_dmac(pc, p); if (pc->ip4.flags & IPF_FRAG) { p = ipfrag(p, pc->mtu); } enq(&pc->oq, p); } return PKT_ENQ; } if (ntohs(ip->frag) & (IP_MF | IP_OFFMASK)) { m = ipreass(m); if (m == NULL) return PKT_ENQ; else *m0 = m; ip = (iphdr *)(m->data + sizeof(ethdr)); } /* ping me, reply */ if (ip->proto == IPPROTO_ICMP) { icmphdr *icmp = (icmphdr *)(ip + 1); if (ip->dip != pc->ip4.ip) return PKT_DROP; /* other type will be sent to application */ if (icmp->type != ICMP_ECHO) return PKT_UP; p = icmpReply(m, ICMP_ECHOREPLY, 0); if (p != NULL) { enq(&pc->bgoq, p); } return PKT_ENQ; } else if (ip->proto == IPPROTO_UDP) { udpiphdr *ui; char *data = NULL; ui = (udpiphdr *)ip; if (IN_MULTICAST(ntohl(ip->dip))) return PKT_DROP; /* dhcp packet */ if (ui->ui_sport == htons(67) && ui->ui_dport == htons(68)) return PKT_UP; if (ip->dip != pc->ip4.ip) return PKT_DROP; /* dns response */ if (ui->ui_sport == htons(53)) return PKT_UP; data = ((char*)(ui + 1)); /* udp echo reply */ if (memcmp(data, eh->dst, ETH_ALEN) == 0) return PKT_UP; else { if (ip->ttl == 1) p = icmpReply(m, ICMP_UNREACH, ICMP_UNREACH_PORT); else p = udpReply(m); if (p != NULL) { enq(&pc->bgoq, p); } } /* anyway tell caller to drop this packet */ return PKT_DROP; } else if (ip->proto == IPPROTO_TCP) { if (ip->dip != pc->ip4.ip) return PKT_DROP; return tcp(pc, m); } } else if (eh->type == htons(ETHERTYPE_ARP)) { vpcs_arphdr *ah = (vpcs_arphdr *)(eh + 1); si = (u_int *)ah->sip; di = (u_int *)ah->dip; /* arp reply */ if (ah->op == htons(ARPOP_REQUEST) && di[0] == pc->ip4.ip) { save_eaddr(pc, si[0], ah->sea); ah->op = htons(ARPOP_REPLY); memcpy(ah->dea, ah->sea, ETH_ALEN); memcpy(ah->sea, pc->ip4.mac, ETH_ALEN); di[0] = si[0]; si[0] = pc->ip4.ip; encap_ehead(m->data, pc->ip4.mac, eh->src, ETHERTYPE_ARP); enq(&pc->oq, m); return PKT_ENQ; } else if (ah->op == htons(ARPOP_REPLY) && sameNet(di[0], pc->ip4.ip, pc->ip4.cidr)) { save_eaddr(pc, si[0], ah->sea); } return PKT_DROP; } else if (strncmp((const char *)eh->dst, (const char *)pc->ip4.mac, ETH_ALEN) != 0) return PKT_DROP; return PKT_UP; } void send4(pcs *pc, struct packet *m) { ethdr *eh = (ethdr *)(m->data); if (eh->type == htons(ETHERTYPE_IPV6)) { send6(pc, m); return; } if (eh->type != htons(ETHERTYPE_IP)) { del_pkt(m); return; } if( ! fix_dmac(pc, m) ){ del_pkt(m); return; } if (pc->ip4.flags & IPF_FRAG) { m = ipfrag(m, pc->mtu); } enq(&pc->oq, m); } int response(struct packet *m, sesscb *sesscb) { ethdr *eh; iphdr *ip; int n; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); /* tracerouter response */ if (ip->proto == IPPROTO_ICMP) { icmphdr *icmp = (icmphdr *)(ip + 1); /* redirect for network */ if (icmp->type == ICMP_REDIRECT) { if (icmp->code == ICMP_REDIRECT_NET) { icmprdr *rdr = (icmprdr *)icmp; sesscb->icmptype = icmp->type; sesscb->icmpcode = icmp->code; /* should check sum */ sesscb->rdip = rdr->ip; /* should check data */ return IPPROTO_ICMP; } } if (icmp->type == ICMP_UNREACH || icmp->type == ICMP_TIMXCEED) { sesscb->icmptype = icmp->type; sesscb->icmpcode = icmp->code; sesscb->rttl = ip->ttl; sesscb->rdip = ip->sip; return IPPROTO_ICMP; } } if (ip->sip != sesscb->dip) return 0; sesscb->rdsize = ntohs(ip->len); if (ip->proto == IPPROTO_ICMP && sesscb->proto == IPPROTO_ICMP) { icmphdr *icmp = (icmphdr *)(ip + 1); sesscb->icmptype = icmp->type; sesscb->icmpcode = icmp->code; sesscb->rttl = ip->ttl; sesscb->rdip = ip->sip; if (ntohs(icmp->seq) == sesscb->sn) return IPPROTO_ICMP; return 0; } if (ip->proto == IPPROTO_UDP && sesscb->proto == IPPROTO_UDP) { udpiphdr *ui = (udpiphdr *)ip; char *data = ((char*)(ui + 1)); if (memcmp(data, eh->dst, 6) == 0) { sesscb->rttl = ip->ttl; return IPPROTO_UDP; } return 0; } if (ip->proto == IPPROTO_TCP && sesscb->proto == IPPROTO_TCP) { tcpiphdr *ti = (tcpiphdr *)ip; char *data = ((char*)(ti + 1)); sesscb->rseq = ntohl(ti->ti_seq); sesscb->rack = ntohl(ti->ti_ack); sesscb->rflags = ti->ti_flags; sesscb->rttl = ip->ttl; sesscb->data = NULL; n = sesscb->rdsize - (ip->ihl << 2) - (ti->ti_off << 2); /* try to get MSS from options */ if (sesscb->flags == TH_SYN && sesscb->rflags == (TH_SYN | TH_ACK) && n > 0) { int i = 0; while ( i < sesscb->rdsize && data[i] == 0x1 ) i++; for (;i < n;) { if (data[i] == TCPOPT_MAXSEG && data[i + 1] == TCPOLEN_MAXSEG) { sesscb->rmss = (data[i + 2] << 8) + data[i + 3]; break; } i += data[i + 1]; } } else { sesscb->data = ((char*)(ip + 1)) + (ti->ti_off << 2); } return IPPROTO_TCP; } return 0; } int arpResolve(pcs *pc, u_int ip, u_char *dmac) { int i, c; struct packet *m; int waittime = 1000; struct timeval tv; c = 0; for (i = 0; i < POOL_SIZE; i++) { if (pc->ipmac4[i].ip == ip && (time_tick - pc->ipmac4[i].timeout) <= 120 && !etherIsZero(pc->ipmac4[i].mac)) { memcpy(dmac, pc->ipmac4[i].mac, ETH_ALEN); return 1; } } while (c++ < 3){ m = arp(pc, ip); if (m == NULL) { printf("out of memory\n"); return 0; } enq(&pc->oq, m); gettimeofday(&(tv), (void*)0); while (!timeout(tv, waittime)) { delay_ms(1); for (i = 0; i < POOL_SIZE; i++) { if (pc->ipmac4[i].ip == ip && (time_tick - pc->ipmac4[i].timeout) <= 120 && !etherIsZero(pc->ipmac4[i].mac)) { memcpy(dmac, pc->ipmac4[i].mac, ETH_ALEN); return 1; } } } } return 0; } struct packet *packet(pcs *pc) { sesscb *sesscb = &pc->mscb; ethdr *eh; iphdr *ip; int i; struct packet *m; int dlen = 0; /* the size of payload */ int hdr_len = 0; char b[9]; dlen = sesscb->dsize; switch (sesscb->proto) { case IPPROTO_ICMP: hdr_len = sizeof(iphdr) + sizeof(icmphdr); break; case IPPROTO_UDP: hdr_len = sizeof(iphdr) + sizeof(udphdr); break; case IPPROTO_TCP: if (sesscb->flags != (TH_ACK | TH_PUSH)) dlen = 0; if (sesscb->flags == TH_SYN) { /* mss(2 + 2), nop(1 + 1), timestamp ( 2 + 8), * nop(1), winscale (2 + 1)*/ dlen = 4 + 2 + 2 + 8 + 1 + 3; } else { dlen = dlen + 2 + 2 + 8; } if (sesscb->rmss != 0 && dlen > sesscb->rmss) dlen = sesscb->rmss - sizeof(ethdr) - sizeof(iphdr) - sizeof(tcphdr); hdr_len = sizeof(iphdr) + sizeof(tcphdr); break; } m = new_pkt(sizeof(ethdr) + hdr_len + dlen); if (m == NULL) return NULL; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ip->ver = 4; ip->ihl = sizeof *ip >> 2; ip->len = htons(hdr_len + dlen); ip->id = htons(sesscb->ipid++); if (!sesscb->frag) ip->frag = htons(IP_DF); ip->ttl = sesscb->ttl; ip->proto = sesscb->proto; ip->sip = sesscb->sip; ip->dip = sesscb->dip; if (sesscb->proto == IPPROTO_ICMP) { icmphdr *icmp = (icmphdr *)(ip + 1); char *data = ((char*)(icmp + 1)); icmp->seq = htons(sesscb->sn); icmp->cksum = 0; icmp->type = ICMP_ECHO; icmp->code = 0; icmp->id = time(0) & 0xffff; for (i = 0; i < dlen; i++) data[i] = (i + sizeof(icmphdr)) & 0xff; icmp->cksum = cksum((unsigned short *) (icmp), hdr_len + dlen - sizeof(iphdr)); } else if (sesscb->proto == IPPROTO_UDP) { udpiphdr *ui = (udpiphdr *)ip; char *data = ((char*)(ui + 1)); ui->ui_sport = htons(sesscb->sport); ui->ui_dport = htons(sesscb->dport); ui->ui_ulen = htons(hdr_len + dlen - sizeof(iphdr)); ui->ui_sum = 0; /* this's my footprint */ if (sesscb->data != NULL) { memcpy(data, sesscb->data, dlen); } else { memcpy(data, sesscb->smac, 6); for (i = 6; i < dlen; i++) data[i] = (i + sizeof(udphdr)) & 0xff; } bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ui->ui_len = ui->ui_ulen; ui->ui_sum = cksum((u_short*)ui, hdr_len + dlen); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); } else if (sesscb->proto == IPPROTO_TCP) { tcpiphdr *ti = (tcpiphdr *)ip; char *data = ((char*)(ti + 1)); u_int t = htonl(time(0)); int optlen = 0; ti->ti_sport = htons(sesscb->sport); ti->ti_dport = htons(sesscb->dport); ti->ti_len = htons(hdr_len + dlen - sizeof(iphdr)); ti->ti_ack = htonl(sesscb->ack); ti->ti_seq = htonl(sesscb->seq); ti->ti_win = htons(sesscb->winsize); ti->ti_sum = 0; ti->ti_flags = sesscb->flags; if (sesscb->flags == TH_SYN) { /* mss 1460 */ *data++ = TCPOPT_MAXSEG; *data++ = TCPOLEN_MAXSEG; *data++ = 0x5; *data++ = 0xb4; /* align */ *data++ = 0x1; *data++ = 0x1; /* timestamp */ *data++ = TCPOPT_TIMESTAMP; *data++ = TCPOLEN_TIMESTAMP; memcpy(data, (char *)&t, 4); data += 8; /* align */ *data++ = 0x1; *data++ = TCPOPT_WINDOW; *data++ = TCPOLEN_WINDOW; *data++ = 1; } else { /* align */ *data++ = 0x1; *data++ = 0x1; /* timestamp */ *data++ = TCPOPT_TIMESTAMP; *data++ = TCPOLEN_TIMESTAMP; memcpy(data, (char *)&t, 4); data += 8; } optlen = data - (char*)(ti + 1); ti->ti_off = (sizeof(tcphdr) + optlen) >> 2; /* * TELNET protcol * IAC: 0xff * option code * WILL: 0xfb * WON't: 0xfc * DO: 0xfd * DON'T: 0xfe * command * ECHO: 0x01 * SUPPRESS-GO-AHEAD: 0x03 * TERMINAL-TYPE: 0x18 * NAWS: 0x1f */ /* fill the data */ for (i = optlen; i < dlen; i++) { if ((i % 2) == 0) *data++ = 0xd; else *data++ = 0xa; } bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ti->ti_sum = cksum((u_short*)ti, hdr_len + dlen); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); } encap_ehead(m->data, sesscb->smac, sesscb->dmac, ETHERTYPE_IP); /* maybe fragmentation failed, let's do cksum first */ ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); /* Even when DF bit is set we'll fragment according to our MTU size */ m = ipfrag(m, sesscb->mtu); return m; } struct packet *arp(pcs *pc, u_int dip) { ethdr *eh; vpcs_arphdr *ah; struct packet *m; u_int *si, *di; m = new_pkt(ARP_PSIZE); if (m == NULL) return NULL; eh = (ethdr *)(m->data); ah = (vpcs_arphdr *)(eh + 1); ah->hrd = htons(ARPHRD_ETHER); ah->pro = htons(ETHERTYPE_IP); ah->hln = 6; ah->pln = 4; ah->op = htons(ARPOP_REQUEST); si = (u_int *)ah->sip; di = (u_int *)ah->dip; si[0] = pc->ip4.ip; di[0] = dip; memcpy(ah->dea, broadcast, ETH_ALEN); memcpy(ah->sea, pc->ip4.mac, ETH_ALEN); encap_ehead(m->data, pc->ip4.mac, broadcast, ETHERTYPE_ARP); return m; } struct packet *udpReply(struct packet *m0) { ethdr *eh; iphdr *ip; udpiphdr *ui; struct packet *m; m = new_pkt(m0->len); if (m == NULL) return NULL; copy_pkt(m, m0); eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ui = (udpiphdr *)ip; ip->dip ^= ip->sip; ip->sip ^= ip->dip; ip->dip ^= ip->sip; ui->ui_sport ^= ui->ui_dport; ui->ui_dport ^= ui->ui_sport; ui->ui_sport ^= ui->ui_dport; ip->cksum = cksum_fixup(ip->cksum, ip->ttl, TTL, 0); ip->ttl = TTL; swap_ehead(m->data); return m; } struct packet *icmpReply(struct packet *m0, char icmptype, char icmpcode) { struct packet *m = NULL; ethdr *eh = NULL; iphdr *ip = NULL; icmphdr *icmp = NULL; if (icmptype == ICMP_ECHOREPLY) { m = m0; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); icmp = (icmphdr *)(ip + 1); u_short old_sum; u_char old_ttl; old_ttl = ip->ttl; old_sum = icmp->cksum; icmp->type = ICMP_ECHOREPLY; icmp->cksum = cksum_fixup(icmp->cksum, ICMP_ECHO, ICMP_ECHOREPLY, 0); ip->dip ^= ip->sip; ip->sip ^= ip->dip; ip->dip ^= ip->sip; ip->ttl = TTL; ip->cksum = cksum_fixup(cksum_fixup(cksum_fixup(ip->cksum, old_ttl, ip->ttl, 0), ICMP_ECHO, ICMP_ECHOREPLY, 0), old_sum, icmp->cksum, 0); swap_ehead(m->data); return m; } if (icmptype == ICMP_UNREACH) { int len, len0; eh = (ethdr *)(m0->data); ip = (iphdr *)(eh + 1); len0 = ntohs(ip->len); if (len0 > 44) len0 = 44; len = sizeof(ethdr) + sizeof(iphdr) + sizeof(icmphdr) + len0; m = new_pkt(len); if (m == NULL) return NULL; /* get original etherhdr and iphdr */ memcpy(m->data, m0->data, sizeof(ethdr) + sizeof(iphdr)); eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); icmp = (icmphdr *)(ip + 1); /* copy the origial part */ memcpy((char*)(icmp + 1), (char *)(m0->data + sizeof(ethdr)), len0); ip->len = htons(len - sizeof(ethdr)); ip->id = time(0) & 0xffff; ip->frag = htons(0x4000); ip->ttl = TTL; ip->proto = IPPROTO_ICMP; ip->cksum = 0; ip->dip ^= ip->sip; ip->sip ^= ip->dip; ip->dip ^= ip->sip; icmp->seq = htons(1); icmp->cksum = 0; icmp->type = icmptype; icmp->code = icmpcode; icmp->id = time(0) & 0xffff; icmp->cksum = cksum((unsigned short *) (icmp), sizeof(icmphdr) + len0); ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); swap_ehead(m->data); return m; } return NULL; } static void save_eaddr(pcs *pc, u_int addr, u_char *mac) { int i; if (!sameNet(addr, pc->ip4.ip, pc->ip4.cidr)) return; i = 0; while (i < POOL_SIZE) { if (time_tick - pc->ipmac4[i].timeout <= 120 && pc->ipmac4[i].ip == addr) { pc->ipmac4[i].timeout = time_tick; break; } if (pc->ipmac4[i].timeout == 0 || time_tick - pc->ipmac4[i].timeout > 120) { pc->ipmac4[i].ip = addr; memcpy(pc->ipmac4[i].mac, mac, ETH_ALEN); pc->ipmac4[i].timeout = time_tick; break; } i++; } } // return 1 : ok // return 0 : error int fix_dmac(pcs *pc, struct packet *m) { ethdr *eh = NULL; iphdr *ip = NULL; u_char mac[6]; eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); if (sameNet(ip->dip, pc->ip4.ip, pc->ip4.cidr)) return 1; if( pc->ip4.gw == 0 ) // gw == 0.0.0.0 return 0; if (arpResolve(pc, pc->ip4.gw, mac)) { memcpy(eh->dst, mac, sizeof(mac)); return 1; } return 0; } #if 0 static void xxpreh(char *e, int c) { int i; for (i = 0; i < c; i++) { printf("%2.2x ", *(e + i)); if (i % 16 == 0) printf("\n"); } return; } #endif /* end of file */ vpcs-0.8.3/src/packets.h000066400000000000000000000034311447703427300151030ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _PACKETS_H_ #define _PACKETS_H_ #include "vpcs.h" #include "ip.h" #include "frag.h" #define PAYLOAD56 56 struct packet *packet(pcs *pc); int upv4(pcs *pc, struct packet **pkt); int response(struct packet *pkt, sesscb *sesscb); int arpResolve(pcs *pc, u_int ip, u_char *dmac); int host2ip(pcs *pc, const char *name, u_int *ip); void send4(pcs *pc, struct packet *pkt); #endif /* end of file */ vpcs-0.8.3/src/packets6.c000066400000000000000000000612041447703427300151660ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vpcs.h" #include "packets6.h" #include "utils.h" #include "ip.h" #include "frag6.h" static struct packet *icmp6Reply(pcs *, struct packet *, char type, char code); static struct packet *udp6Reply(struct packet *m0); static void fix_dmac6(pcs *pc, struct packet *m); static struct packet* nb_sol(pcs *pc, ip6 *dst); static void save_mtu6(pcs *pc, struct packet *m); static int sub_nbsol(pcs *pc, struct packet *m); static int sub_nbadv(pcs *pc, struct packet *m); static int sub_udp(pcs *pc, struct packet *m); static int save_nb_adv(pcs *pc, struct packet *m); /* static void xxpreh(char *e, int c); */ extern int tcp6(pcs *pc, struct packet *m); extern u_int time_tick; /* * ipv6 stack * * code: PKT_UP, send to up layer * PKT_ENQ, in out queue * PKT_DROP, drop the packet */ int upv6(pcs *pc, struct packet **m0) { struct packet *m = *m0; ethdr *eh; ip6hdr *ip; icmp6hdr *icmp; struct packet *p = NULL; eh = (ethdr *)(m->data); if (etherIsMulticast(eh->src)) return PKT_DROP; if (eh->type != htons(ETHERTYPE_IPV6)) return PKT_DROP; ip = (ip6hdr *)(eh + 1); if ((ip->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) return PKT_DROP; /* too big, send ICMP with the code ICMP6_PACKET_TOO_BIG */ if (ntohs(ip->ip6_plen) + sizeof(ip6hdr) > pc->mtu) { p = icmp6Reply(pc, m, ICMP6_PACKET_TOO_BIG, 0); if (p) { fix_dmac6(pc, p); enq(&pc->oq, p); } return PKT_ENQ; } /* fragment */ if (ip6ehdr(ip, m->len - sizeof(ethdr), IPPROTO_FRAGMENT) > 0) { m = ipreass6(m); if (m == NULL) return PKT_ENQ; else *m0 = m; ip = (ip6hdr *)(m->data + sizeof(ethdr)); } if (ip->ip6_nxt == IPPROTO_ICMPV6) { icmp = (icmp6hdr *)(ip + 1); /* neighbor solicitation */ if (icmp->type == ND_NEIGHBOR_SOLICIT) return sub_nbsol(pc, m); if (icmp->type == ICMP6_ECHO_REQUEST) { swap_ip6head(m); icmp = (icmp6hdr *)(ip + 1); icmp->type = ICMP6_ECHO_REPLY; icmp->cksum = cksum_fixup(icmp->cksum, ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY, 0); swap_ehead(m->data); /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); return PKT_ENQ; } if (icmp->type == ND_ROUTER_ADVERT) { return sub_nbadv(pc, m); } /* neighbor advertisement */ if (icmp->type == ND_NEIGHBOR_ADVERT) { save_nb_adv(pc, m); return PKT_DROP; } if (icmp->type == ICMP6_PACKET_TOO_BIG) save_mtu6(pc, m); switch (icmp->type) { case ICMP6_ECHO_REPLY: case ICMP6_TIME_EXCEEDED: case ICMP6_DST_UNREACH: case ICMP6_PACKET_TOO_BIG: return PKT_UP; default: break; } } switch (ip->ip6_nxt) { case IPPROTO_UDP: return sub_udp(pc, m); case IPPROTO_TCP: return tcp6(pc, m); default: return PKT_DROP; } return PKT_UP; } int sub_udp(pcs *pc, struct packet *m) { ethdr *eh; ip6hdr *ip; udphdr *ui; struct packet *p; eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); ui = (udphdr *)(ip + 1); if (IN6_IS_MULTICAST(&(ip->dst))) return PKT_DROP; /* udp echo reply */ char *data = ((char*)(ui + 1)); if (memcmp(data, eh->dst, 6) == 0) return PKT_UP; p = (ip->ip6_hlim != 1) ? udp6Reply(m) : icmp6Reply(pc, m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) enq(&pc->bgoq, p); /* anyway tell caller to drop this packet */ return PKT_DROP; } int sub_nbsol(pcs *pc, struct packet *m) { ethdr *eh; ip6hdr *ip; ndhdr *nshdr; ndopt *nsopt; ip6 *tip6 = NULL; eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); nshdr = (ndhdr *)(ip + 1); nsopt = (ndopt *)(nshdr + 1); if (eh->dst[0] != 0x33 || eh->dst[1] != 0x33 || eh->dst[2] != 0xff || ip->ip6_hlim != 255 || ip->dst.addr16[0] != IPV6_ADDR_INT16_MLL || ip->dst.addr32[1] != 0 || ip->dst.addr32[2] != IPV6_ADDR_INT32_ONE || ip->dst.addr8[12] != 0xff) { return PKT_DROP; } if (eh->dst[3] != pc->ip6.ip.addr8[13] || eh->dst[4] != pc->ip6.ip.addr8[14] || eh->dst[5] != pc->ip6.ip.addr8[15] || ip->dst.addr32[3] != (pc->ip6.ip.addr32[3] | 0xff)) { if (eh->dst[3] != pc->link6.ip.addr8[13] || eh->dst[4] != pc->link6.ip.addr8[14] || eh->dst[5] != pc->link6.ip.addr8[15] || ip->dst.addr32[3] != (pc->link6.ip.addr32[3] | 0xff)) { return PKT_DROP; } else tip6 = &pc->link6.ip; } else tip6 = &pc->ip6.ip; /* send advertisement */ memcpy(ip->dst.addr8, ip->src.addr8, 16); memcpy(ip->src.addr8, tip6->addr8, 16); nshdr->hdr.type = ND_NEIGHBOR_ADVERT; nshdr->hdr.code = 0; nshdr->nd_na_flags = ND_RA_FLAG_OTHER | ND_RA_FLAG_HA; nsopt->type = 2; memcpy(nsopt->mac, pc->ip4.mac, ETH_ALEN); nshdr->hdr.cksum = 0; nshdr->hdr.cksum = cksum6(ip, IPPROTO_ICMPV6, ntohs(ip->ip6_plen)); memcpy(eh->dst, eh->src, ETH_ALEN); memcpy(eh->src, pc->ip4.mac, ETH_ALEN); enq(&pc->oq, m); return PKT_ENQ; } int sub_nbadv(pcs *pc, struct packet *m) { ethdr *eh; ip6hdr *ip; icmp6hdr *icmp; int setMtu = 0, setMac = 0; u_int32_t mtu = 0; char *p = NULL, *mac = NULL; ndrahdr *ndr = NULL; eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); icmp = (icmp6hdr *)(ip + 1); ndr = (ndrahdr *)(ip + 1); /* icmp6_data8[0] * |7654 3210| * ||| * ||Override flag, update link address if 1 * |Solicited flag, response to NS if 1 * Router flag if 1 */ if (ip->src.addr8[0] != 0xfe || ip->src.addr8[1] != 0x80 || icmp->icmp6_data8[0] != ND_RA_FLAG_OTHER) { return PKT_DROP; } /* * TLD (Type, Length, Data) * Type, Length: 8 bits * 1 = Source link-layer * Length = 1, Data: Ethernet 48 bit MAC * 2 = Target link-layer * Length = 1, Data: Ethernet 48 bit MAC * 3 = Prefix Informationr * Length = 4, * Data: Prefix Length 8 bit * 1-bit on-link flag * 1-bit autonomous address-configuration flag, this * prefix can be used for stateless autoconfiguration. * 6-bits reserved * 32-bits the prefix valid lifetime in seconds * 32-bits stateless address remain preferred lifetime * 32-bits reserved * 128-bits Prefix of the ip address * 4 = Redirected Header * Length: multiple of 8 octets in range 1 to 161 * Data: 48-bits Set to zero and ignored by receiver. * variable octet IP Header + Data, not exceed 1280 octets. * 5 = MTU * Length = 1 * Data: 16-bits reserved * 32-bits mtu */ for (p = (char *)(ndr + 1); p < ((char*)icmp + ntohs(ip->ip6_plen)); p += *(p + 1) * 8) { /* link-layer address */ if (*p == 1 && *(p + 1) == 1) mac = p + 2; /* mtu */ else if (*p == 5 && *(p + 1) == 1) mtu = ntohl(*(u_int32_t *)(p + 4)); /* prefix */ else if (*p == 3 && *(p + 1) == 4) { if (pc->ip6.cidr == 0) { memcpy(pc->ip6.ip.addr8, p + 16, 16); pc->ip6.cidr = *(p + 2); pc->ip6.ip.addr8[15] = pc->ip4.mac[5]; pc->ip6.ip.addr8[14] = pc->ip4.mac[4]; pc->ip6.ip.addr8[13] = pc->ip4.mac[3]; pc->ip6.ip.addr8[12] = 0xfe; pc->ip6.ip.addr8[11] = 0xff; pc->ip6.ip.addr8[10] = pc->ip4.mac[2]; pc->ip6.ip.addr8[9] = pc->ip4.mac[1]; pc->ip6.ip.addr8[8] = (pc->ip4.mac[0] &0x20) ? pc->ip4.mac[0] & 0xef : (pc->ip4.mac[0] | 0x20); pc->ip6.type = IP6TYPE_EUI64; setMtu = 1; } if (sameNet6((char *)pc->ip6.ip.addr8, p + 16, pc->ip6.cidr)) setMac = 1; } } if (setMtu != 0 && mtu != 0) pc->mtu = mtu; if (setMac != 0 && mac != NULL) memcpy(pc->ip6.gmac, mac, 6); return PKT_DROP; } void send6(pcs *pc, struct packet *m) { ethdr *eh = (ethdr *)(m->data); ip6hdr *ip; if (eh->type != htons(ETHERTYPE_IPV6)) { del_pkt(m); return; } fix_dmac6(pc, m); ip = (ip6hdr *)(eh + 1); m = ipfrag6(m, findmtu6(pc, &ip->dst)); enq(&pc->oq, m); } int response6(struct packet *m, sesscb *sesscb) { ethdr *eh; ip6hdr *ip; eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); if (ip->ip6_nxt == IPPROTO_ICMPV6) { icmp6hdr *icmp = (icmp6hdr *)(ip + 1); if (icmp->type == ICMP6_DST_UNREACH || icmp->type == ICMP6_TIME_EXCEEDED || icmp->type == ICMP6_DST_UNREACH_NOPORT || icmp->type == ICMP6_PACKET_TOO_BIG) { if (icmp->type == ICMP6_PACKET_TOO_BIG) sesscb->mtu = ntohl(icmp->icmp6_mtu); sesscb->icmptype = icmp->type; sesscb->icmpcode = icmp->code; sesscb->rttl = ip->ip6_hlim; memcpy(sesscb->rdip6.addr8, ip->src.addr8, 16); return IPPROTO_ICMPV6; } } if (!IP6EQ(&(sesscb->dip6), &(ip->src))) return 0; if (ip->ip6_nxt == IPPROTO_ICMPV6 && sesscb->proto == IPPROTO_ICMPV6) { icmp6hdr *icmp = (icmp6hdr *)(ip + 1); sesscb->icmptype = icmp->type; sesscb->icmpcode = icmp->code; sesscb->rttl = ip->ip6_hlim; memcpy(sesscb->rdip6.addr8, ip->src.addr8, 16); if (ntohs(icmp->icmp6_seq) == sesscb->sn) { return IPPROTO_ICMPV6; } return 0; } if (ip->ip6_nxt == IPPROTO_UDP) { udphdr *ui = (udphdr *)(ip + 1); char *data = ((char*)(ui + 1)); if (memcmp(data, eh->dst, 6) == 0) { sesscb->rttl = ip->ip6_hlim; return IPPROTO_UDP; } return 0; } if (ip->ip6_nxt == IPPROTO_TCP) { struct tcphdr *th = (struct tcphdr *)(ip + 1); char *data = ((char*)(th + 1)); sesscb->rseq = ntohl(th->th_seq); sesscb->rack = ntohl(th->th_ack); sesscb->rflags = th->th_flags; sesscb->rttl = ip->ip6_hlim; sesscb->rdsize = ntohs(ip->ip6_plen) - sizeof(iphdr) - (th->th_off << 2); sesscb->data = NULL; /* try to get MSS from options */ if (sesscb->flags == TH_SYN && sesscb->rdsize > 0 && sesscb->rflags == (TH_SYN | TH_ACK)) { int i = 0; while ( i < sesscb->rdsize && data[i] == 0x1 ) i++; for (;i < sesscb->rdsize;) { if (data[i] == TCPOPT_MAXSEG && data[i + 1] == TCPOLEN_MAXSEG) { sesscb->rmss = (data[i + 2] << 8) + data[i + 3]; break; } i += data[i + 1]; } } else { sesscb->data = ((char*)(ip + 1)) + (th->th_off << 2); } return IPPROTO_TCP; } return 0; } struct packet *packet6(pcs *pc) //sesscb *sesscb) { sesscb *sesscb = &pc->mscb; int dlen = 0, len = 0, i; struct packet *m = NULL; ethdr *eh; ip6hdr *ip; if (sesscb->dsize < 60000) dlen = sesscb->dsize; len = sizeof(ethdr) + sizeof(ip6hdr); switch (sesscb->proto) { case IPPROTO_ICMPV6: len += sizeof(icmp6hdr) + dlen; break; case IPPROTO_UDP: if (dlen < 6) dlen = 6; len += sizeof(udphdr) + dlen; break; case IPPROTO_TCP: if (sesscb->flags != (TH_ACK | TH_PUSH)) dlen = 0; if (sesscb->flags == TH_SYN) { /* mss(2 + 2), nop(1 + 1), timestamp ( 2 + 8), * nop(1), winscale (2 + 1)*/ dlen = 4 + 2 + 2 + 8 + 1 + 3; } else { dlen = dlen + 2 + 2 + 8; } if (sesscb->rmss != 0 && dlen > sesscb->rmss) dlen = sesscb->rmss - sizeof(ethdr) - sizeof(iphdr) - sizeof(tcphdr); len += sizeof(tcphdr) + dlen; break; } m = new_pkt(len); if (m == NULL) return NULL; eh = (ethdr *)(m->data); memcpy(eh->src, sesscb->smac, 6); memcpy(eh->dst, sesscb->dmac, 6); eh->type = htons(ETHERTYPE_IPV6); ip = (ip6hdr *)(eh + 1); ip->ip6_flow = 0; ip->ip6_vfc &= ~IPV6_VERSION_MASK; ip->ip6_vfc |= IPV6_VERSION; ip->ip6_nxt = sesscb->proto; ip->ip6_hlim = sesscb->ttl; ip->ip6_plen = htons((u_short)(len - sizeof(ethdr) - sizeof(ip6hdr))); memcpy(ip->src.addr8, sesscb->sip6.addr8, 16); memcpy(ip->dst.addr8, sesscb->dip6.addr8, 16); if (sesscb->proto == IPPROTO_ICMPV6) { icmp6hdr *icmp = (icmp6hdr *)(ip + 1); icmp->type = ICMP6_ECHO_REQUEST; icmp->icmp6_id = sesscb->ipid; icmp->icmp6_seq = htons(sesscb->sn); /* append payload data */ for (i = 0; i < dlen; i++) m->data[sizeof(ethdr) + sizeof(ip6hdr) + sizeof(icmp6hdr) + i] = i % 0xff; icmp->cksum = 0; icmp->cksum = cksum6(ip, IPPROTO_ICMPV6, len - sizeof(ethdr) - sizeof(ip6hdr)); } else if (sesscb->proto == IPPROTO_UDP) { udphdr *ui = (udphdr *)(ip + 1); char *data = ((char*)(ui + 1)); ui->sport = htons(sesscb->sport); ui->dport = htons(sesscb->dport); ui->len = htons(len - sizeof(ethdr) - sizeof(ip6hdr)); memcpy(data, sesscb->smac, 6); for (i = 6; i < dlen; i++) data[i] = i + sizeof(udphdr); ui->cksum = 0; ui->cksum = cksum6(ip, IPPROTO_UDP, len - sizeof(ethdr) - sizeof(ip6hdr)); } else if (sesscb->proto == IPPROTO_TCP) { struct tcphdr *th = (struct tcphdr *)(ip + 1); char *data = ((char*)(th + 1)); u_int t = htonl(time(0)); int optlen = 0; th->th_sport = htons(sesscb->sport); th->th_dport = htons(sesscb->dport); th->th_ack = htonl(sesscb->ack); th->th_seq = htonl(sesscb->seq); th->th_win = htons(sesscb->winsize); th->th_flags = sesscb->flags; if (sesscb->flags == TH_SYN) { /* mss 1460 */ *data++ = TCPOPT_MAXSEG; *data++ = TCPOLEN_MAXSEG; *data++ = 0x5; *data++ = 0xb4; /* align */ *data++ = 0x1; *data++ = 0x1; /* timestamp */ *data++ = TCPOPT_TIMESTAMP; *data++ = TCPOLEN_TIMESTAMP; memcpy(data, (char *)&t, 4); data += 8; /* align */ *data++ = 0x1; *data++ = TCPOPT_WINDOW; *data++ = TCPOLEN_WINDOW; *data++ = 1; } else { /* align */ *data++ = 0x1; *data++ = 0x1; /* timestamp */ *data++ = TCPOPT_TIMESTAMP; *data++ = TCPOLEN_TIMESTAMP; memcpy(data, (char *)&t, 4); data += 8; } optlen = data - (char*)(th + 1); th->th_off = (sizeof(tcphdr) + optlen) >> 2; /* fill the data */ for (i = optlen; i < dlen; i++) { if ((i % 2) == 0) *data++ = 0xd; else *data++ = 0xa; } th->th_sum = 0; th->th_sum = cksum6(ip, IPPROTO_TCP, len - sizeof(ethdr) - sizeof(ip6hdr)); } if ((sesscb->frag & IPF_FRAG) == IPF_FRAG) m = ipfrag6(m, findmtu6(pc, &(sesscb->dip6))); return m; } /*----------------------------------------------------------------------- * * internal functions * *-----------------------------------------------------------------------*/ struct packet *icmp6Reply(pcs *pc, struct packet *m0, char icmptype, char icmpcode) { ethdr *eh, *eh0; ip6hdr *ip, *ip0; icmp6hdr *icmp; struct packet *m; int hlen; int plen; plen = m0->len - sizeof(ethdr); if (sizeof(ip6hdr) + sizeof(icmp6hdr) + plen > IPV6_MMTU) plen = IPV6_MMTU - sizeof(ip6hdr) - sizeof(icmp6hdr); hlen = sizeof(ethdr) + sizeof(ip6hdr) + sizeof(icmp6hdr) + plen; m = new_pkt(hlen); if (m == NULL) return NULL; hlen = hlen - sizeof(ethdr) - sizeof(ip6hdr); eh = (ethdr *)(m->data); eh0 = (ethdr *)(m0->data); memcpy(eh->src, eh0->dst, ETH_ALEN); memcpy(eh->dst, eh0->src, ETH_ALEN); eh->type = eh0->type; ip = (ip6hdr *)(eh + 1); ip0 = (ip6hdr *)(eh0 + 1); ip->ip6_flow = 0; ip->ip6_vfc &= ~IPV6_VERSION_MASK; ip->ip6_vfc |= IPV6_VERSION; ip->ip6_nxt = IPPROTO_ICMPV6; ip->ip6_hlim = TTL; ip->ip6_plen = htons(sizeof(icmp6hdr) + (u_short)plen); memcpy(ip->src.addr8, ip0->dst.addr8, 16); memcpy(ip->dst.addr8, ip0->src.addr8, 16); icmp = (icmp6hdr *)(ip + 1); icmp->type = icmptype; //ICMP6_DST_UNREACH; icmp->code = icmpcode; //ICMP6_DST_UNREACH_NOPORT; switch (icmptype) { case ICMP6_PACKET_TOO_BIG: icmp->icmp6_mtu = htonl(pc->mtu); break; default: icmp->icmp6_id = time(0) & 0xffff; icmp->icmp6_seq = htons(1); break; } memcpy((char *)(icmp + 1), m0->data + sizeof(ethdr), plen); icmp->cksum = 0; icmp->cksum = cksum6(ip, IPPROTO_ICMPV6, hlen); return m; } struct packet *udp6Reply(struct packet *m0) { ethdr *eh; ip6hdr *ip; udphdr *ui; struct packet *m; m = new_pkt(m0->len); if (m == NULL) return NULL; copy_pkt(m, m0); eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); ui = (udphdr *)(ip + 1); swap_ehead(m->data); swap_ip6head(m); ip->ip6_hlim = TTL; ui->sport ^= ui->dport; ui->dport ^= ui->sport; ui->sport ^= ui->dport; ui->cksum = 0; ui->cksum = cksum6(ip, IPPROTO_UDP, ntohs(ui->len)); return m; } /* * find neighbor * * return the mac * NULL, not found * */ u_char *nbDiscovery(pcs *pc, ip6 *dst) { int i; static u_char mac[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; int waittime = 1000; struct timeval tv; /* linklocal address */ if (dst->addr16[0] == IPV6_ADDR_INT16_ULL) { mac[0] = (dst->addr8[8] ^ 0x2); mac[1] = dst->addr8[9]; mac[2] = dst->addr8[10]; mac[3] = dst->addr8[13]; mac[4] = dst->addr8[14]; mac[5] = dst->addr8[15]; return mac; } /* find router */ if (!sameNet6((char *)pc->ip6.ip.addr8, (char *)dst->addr8, pc->ip6.cidr) && dst->addr16[0] != IPV6_ADDR_INT16_ULL) { gettimeofday(&(tv), (void*)0); while (!timeout(tv, waittime)) { struct packet *m; if (memcmp(pc->ip6.gmac, (const char *)mac, ETH_ALEN) != 0) return (pc->ip6.gmac); m = nbr_sol(pc); if (m == NULL) { printf("out of memory\n"); return NULL; } enq(&pc->oq, m); delay_ms(10); } return NULL; } else { /* search neightbor cache */ for (i = 0; i < POOL_SIZE; i++) { if (sameNet6((char *)pc->ipmac6[i].ip.addr8, (char *)dst->addr8, 128)) return (pc->ipmac6[i].mac); } } /* find neighbor */ i = 0; while ( i++ < 3 ){ struct packet *m; m = nb_sol(pc, dst); if (m == NULL) { printf("out of memory\n"); return NULL; } enq(&pc->oq, m); gettimeofday(&(tv), (void*)0); while (!timeout(tv, waittime)) { delay_ms(1); for (i = 0; i < POOL_SIZE; i++) { if (sameNet6((char *)pc->ipmac6[i].ip.addr8, (char *)dst->addr8, 128)) return (pc->ipmac6[i].mac); } } } return NULL; } /* * generate neighbor router solicitation packet */ struct packet* nbr_sol(pcs *pc) { ethdr *eh; ip6hdr *ip; icmp6hdr *icmp; struct packet *m; int len; len = sizeof(ethdr) + sizeof(ip6hdr) + sizeof(icmp6hdr); m = new_pkt(len); if (m == NULL) return NULL; len = sizeof(icmp6hdr); eh = (ethdr *)(m->data); memcpy(eh->src, pc->ip4.mac, ETH_ALEN); eh->type = htons(ETHERTYPE_IPV6); ip = (ip6hdr *)(eh + 1); ip->ip6_flow = 0; ip->ip6_vfc &= ~IPV6_VERSION_MASK; ip->ip6_vfc |= IPV6_VERSION; ip->ip6_nxt = IPPROTO_ICMPV6; ip->ip6_hlim = 255; memcpy(ip->src.addr8, pc->ip6.ip.addr8, 16); /* format destination ip */ ip->dst.addr16[0] = IPV6_ADDR_INT16_MLL; ip->dst.addr16[1] = 0; ip->dst.addr32[1] = 0; ip->dst.addr32[2] = 0; ip->dst.addr32[3] = IPV6_ADDR_INT32_TWO; /* rewrite eh->dst */ eh->dst[0] = 0x33; eh->dst[1] = 0x33; eh->dst[5] = 2; icmp = (icmp6hdr *)(ip + 1); icmp->type = ND_ROUTER_SOLICIT; icmp->code = 0; len = sizeof(icmp6hdr); ip->ip6_plen = htons((u_short)len); icmp->cksum = 0; icmp->cksum = cksum6(ip, IPPROTO_ICMPV6, len); return m; } /* generate neighbor solicitation packet */ struct packet* nb_sol(pcs *pc, ip6 *dst) { ethdr *eh; ip6hdr *ip; ndhdr *nshdr; ndopt *nsopt; struct packet *m; int len; len = sizeof(ethdr) + sizeof(ip6hdr) + sizeof(ndhdr) + sizeof(ndopt); m = new_pkt(len); if (m == NULL) return NULL; len = sizeof(ndhdr) + sizeof(ndopt); eh = (ethdr *)(m->data); memcpy(eh->src, pc->ip4.mac, ETH_ALEN); eh->type = htons(ETHERTYPE_IPV6); ip = (ip6hdr *)(eh + 1); ip->ip6_flow = 0; ip->ip6_vfc &= ~IPV6_VERSION_MASK; ip->ip6_vfc |= IPV6_VERSION; ip->ip6_nxt = IPPROTO_ICMPV6; ip->ip6_hlim = 255; if (dst->addr16[0] == IPV6_ADDR_INT16_ULL) memcpy(ip->src.addr8, pc->link6.ip.addr8, 16); else memcpy(ip->src.addr8, pc->ip6.ip.addr8, 16); /* format destination ip */ ip->dst.addr16[0] = IPV6_ADDR_INT16_MLL; ip->dst.addr16[1] = 0; ip->dst.addr32[1] = 0; ip->dst.addr32[2] = IPV6_ADDR_INT32_ONE; ip->dst.addr32[3] = dst->addr32[3]; ip->dst.addr8[12] = 0xff; /* rewrite eh->dst */ eh->dst[0] = 0x33; eh->dst[1] = 0x33; eh->dst[2] = ip->dst.addr8[12]; eh->dst[3] = ip->dst.addr8[13]; eh->dst[4] = ip->dst.addr8[14]; eh->dst[5] = ip->dst.addr8[15]; nshdr = (ndhdr *)(ip + 1); nshdr->hdr.type = ND_NEIGHBOR_SOLICIT; nshdr->hdr.code = 0; nshdr->nd_na_flags = 0; memcpy(nshdr->target.addr8, dst->addr8, 16); /* append neighbor solicitation option */ nsopt = (ndopt*)(nshdr + 1); nsopt->type = 1; nsopt->len = 1; memcpy(nsopt->mac, pc->ip4.mac, ETH_ALEN); len = sizeof(ndhdr) + sizeof(ndopt); ip->ip6_plen = htons((u_short)len); nshdr->hdr.cksum = 0; nshdr->hdr.cksum = cksum6(ip, IPPROTO_ICMPV6, len); return m; } int save_nb_adv(pcs *pc, struct packet *m) { ethdr *eh; ip6hdr *ip; ndhdr *nshdr; ndopt *nsopt; int i; eh = (ethdr *)(m->data); if (eh->type != htons(ETHERTYPE_IPV6)) return -1; if (memcmp(eh->dst, pc->ip4.mac, ETH_ALEN)) return -1; ip = (ip6hdr *)(eh + 1); if ((!IP6EQ(&(pc->ip6.ip), &(ip->dst)) && !IP6EQ(&(pc->link6.ip), &(ip->dst))) || IP6EQ(&ip->dst, &ip->src)) return -1; nshdr = (ndhdr *)(ip + 1); nsopt = (ndopt *)(nshdr + 1); if (nshdr->hdr.type != ND_NEIGHBOR_ADVERT) return -1; /* shoule check sum field * ... */ /* not Target Link-Layer Address */ if (nsopt->type != 2) return -1; i = 0; while (i < POOL_SIZE) { if (IP6EQ(&pc->ipmac6[i].ip, &ip->src) && (time_tick - pc->ipmac6[i].timeout <= 120)) break; if (pc->ipmac6[i].timeout == 0 || (time_tick - pc->ipmac6[i].timeout > 120)) { memcpy(pc->ipmac6[i].mac, nsopt->mac, ETH_ALEN); memcpy(pc->ipmac6[i].ip.addr8, ip->src.addr8, sizeof(ip->src.addr8)); pc->ipmac6[i].timeout = time_tick; pc->ipmac6[i].cidr = 128; break; } i++; } if (i == POOL_SIZE) { i = 0; memcpy(pc->ipmac6[i].mac, nsopt->mac, ETH_ALEN); memcpy(pc->ipmac6[i].ip.addr8, ip->src.addr8, 16); pc->ipmac6[i].timeout = time_tick; } return i; } void fix_dmac6(pcs *pc, struct packet *m) { u_char *p; ethdr *eh; ip6hdr *ip; eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); p = nbDiscovery(pc, &ip->dst); if (p) memcpy(eh->dst, p, 6); } int ip6ehdr(ip6hdr *ip, int plen, int hdrtype) { int nxt, off; ip6eh *eh; nxt = ip->ip6_nxt; off = sizeof(ip6hdr); while (off < plen) { if (nxt == hdrtype) return off; eh = (ip6eh *)(((char *)ip) + off); switch (nxt) { case IPPROTO_AH: off = (eh->len) << 2; break; default: off += (eh->len + 1) << 3; break; } nxt = eh->nxt; } return 0; } void save_mtu6(pcs *pc, struct packet *m) { icmp6hdr *icmp; ip6hdr *ip = NULL, *ip0 = NULL; int i, n; ip = (ip6hdr *)(m->data + sizeof(ethdr)); if ((ip->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) return; n = ip6ehdr(ip, m->len - sizeof(ethdr), IPPROTO_ICMPV6); if (n == 0) return; icmp = (icmp6hdr *)((char *)ip + n); if (icmp->type != ICMP6_PACKET_TOO_BIG) return; ip0 = (ip6hdr *)(m->data + sizeof(ethdr) + sizeof(ip6hdr) + sizeof(icmp6hdr)); for (i = 0, n = -1; i < POOL_SIZE; i++) { if (IP6EQ(&ip0->dst, &pc->ip6mtu[i].ip)) { pc->ip6mtu[i].mtu = ntohl(icmp->icmp6_mtu); pc->ip6mtu[i].timeout = time_tick; return; } if ((n < 0) && (time_tick - pc->ip6mtu[i].timeout > POOL_TIMEOUT)) n = i; } if (n >= 0) { pc->ip6mtu[n].mtu = ntohl(icmp->icmp6_mtu); pc->ip6mtu[n].timeout = time_tick; memcpy(pc->ip6mtu[n].ip.addr8, ip0->dst.addr8, 16); } } int findmtu6(pcs *pc, ip6 *src) { int i; for (i = 0; i < POOL_SIZE; i++) { if (time_tick - pc->ip6mtu[i].timeout > POOL_TIMEOUT) continue; if (IP6EQ(src, &pc->ip6mtu[i].ip)) return pc->ip6mtu[i].mtu; } return pc->mtu; } /* end of file */ vpcs-0.8.3/src/packets6.h000066400000000000000000000053331447703427300151740ustar00rootroot00000000000000/* * Copyright (c) 2007-2016, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _PACKETS6_H_ #define _PACKETS6_H_ #include #include #include #include "vpcs.h" #include "ip.h" #define ETHER_MAP_IPV6_MULTICAST(ip6addr, enaddr) \ /* struct in6_addr *ip6addr; */ \ /* u_char enaddr[ETHER_ADDR_LEN]; */ \ { \ (enaddr)[0] = 0x33; \ (enaddr)[1] = 0x33; \ (enaddr)[2] = ((u_char *)ip6addr)[12]; \ (enaddr)[3] = ((u_char *)ip6addr)[13]; \ (enaddr)[4] = ((u_char *)ip6addr)[14]; \ (enaddr)[5] = ((u_char *)ip6addr)[15]; \ } int upv6(pcs *pc, struct packet **m); struct packet *packet6(pcs *pc); //, sesscb *sesscb); int response6(struct packet *pkt, sesscb *sesscb); struct packet *tcp6Reply(struct packet *m0, sesscb *cb); int tr6Reply(struct packet *m, ip6 *mip, ip6 *dip); u_char *nbDiscovery(pcs *pc, ip6 *dst); struct packet* nbr_sol(pcs *pc); void send6(pcs *pc, struct packet *m); int findmtu6(pcs *pc, ip6 *src); int ip6ehdr(ip6hdr *ip, int plen, int hdrtype); #endif /* end of file */ vpcs-0.8.3/src/queue.c000066400000000000000000000060071447703427300145720ustar00rootroot00000000000000/* * Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include "queue.h" void free_pkts(struct packet *m) { struct packet *m0; while (m) { m0 = m->next; del_pkt(m); m = m0; } } void del_pkt(struct packet *m) { free(m); } struct packet *new_pkt(int len) { struct packet *m = NULL; m = (struct packet *)malloc(len + sizeof(struct packet)); if (m != NULL) { memset(m, 0, len + sizeof(struct packet)); m->len = len; return m; } else return NULL; } struct packet *deq_impl(struct pq *pq, int cond) { struct packet *m = NULL; lock_q(pq); if (cond && (pq->q == NULL)) pthread_cond_wait(&(pq->cond), &(pq->locker)); if (pq->q != NULL) { m = pq->q; pq->q = pq->q->next; pq->size --; m->next = NULL; } ulock_q(pq); return m; } struct packet *deq(struct pq *pq) { return deq_impl(pq, 0); } struct packet *waitdeq(struct pq *pq) { return deq_impl(pq, 1); } struct packet *enq(struct pq *pq, struct packet *m) { struct packet *q = NULL; if (pq->size == PKTQ_SIZE) { printf("queue is full \n"); return NULL; } lock_q(pq); gettimeofday(&(m->ts), (void*)0); if (pq->q == NULL) pq->q = m; else { q = pq->q; while (q->next != NULL) q = q->next; q->next = m; } while (m) { pq->size ++; m = m->next; } pthread_cond_signal(&(pq->cond)); ulock_q(pq); return q; } void init_queue(struct pq *pq) { pthread_mutex_init(&(pq->locker), NULL); pthread_cond_init(&(pq->cond), NULL); pq->ip = 0; pq->size = 0; } void lock_q(struct pq *pq) { pthread_mutex_lock(&(pq->locker)); } void ulock_q(struct pq *pq) { pthread_mutex_unlock(&(pq->locker)); } /* end of file */ vpcs-0.8.3/src/queue.h000066400000000000000000000045001447703427300145730ustar00rootroot00000000000000/* * Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _PKTQ_H_ #define _PKTQ_H_ #include #include #include #define PKTQ_SIZE (101) #define PKT_DROP 0 /* drop it */ #define PKT_ENQ 1 /* enqueued */ #define PKT_UP 2 /* application */ struct packet { struct packet *next; int len; struct timeval ts; char data[0]; }; struct pq { int type; /* for debug */ int ip; /* pointer of the queue */ int size; /* size of queue */ pthread_mutex_t locker; pthread_cond_t cond; struct packet *q; }; #define copy_pkt(dst, src) { \ dst->len = src->len; \ memcpy(dst->data, src->data, src->len); \ dst->ts = src->ts; \ } void init_queue(struct pq*); struct packet *enq(struct pq*, struct packet *pkt); struct packet *deq(struct pq*); struct packet *waitdeq(struct pq *pq); void lock_q(struct pq*); void ulock_q(struct pq*); struct packet *new_pkt(int len); void del_pkt(struct packet *m); void free_pkts(struct packet *m); #endif /* end of file */ vpcs-0.8.3/src/readline.c000066400000000000000000000306031447703427300152300ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #if Linux || Darwin #include #endif #include "readline.h" static int _readline(struct rls *rls); static int findhistory(struct rls *rls, int start); static void trimspace(char *buf); static void vprint(int fd, char *s, int len); void kbhit(int fd) { struct termios termios; char kb[32]; int rc; set_terminal(fd, &termios); do { rc = read(fd, kb, sizeof(kb)); if (rc > 0) break; usleep(100); } while (1); reset_terminal(fd, &termios); } char *readline(const char *prompt, struct rls *rls) { if (prompt == NULL || rls == NULL) return NULL; if (write(rls->fdout, prompt, strlen(prompt))) ; rls->prompt = (char *)prompt; if (_readline(rls) == 0) return NULL; return rls->kbuffer; } int readline_tab(char** (*cb)(const char *string, const char *part), struct rls *rls) { if (cb != NULL) rls->tab_callback = cb; return 0; } int loadhistory(const char *filename, struct rls *rls) { FILE *fp = fopen(filename, "r"); int len; int i; if (fp == NULL) return errno; i = 0; while (fgets(rls->kbuffer, rls->maxbuflen, fp)) { len = strlen(rls->kbuffer); if (len == 0) continue; if (rls->kbuffer[len - 1] == '\n') rls->kbuffer[len - 1] = '\0'; if (i == rls->maxhistnum) { memmove(rls->history[0], rls->history[1], rls->maxbuflen * (rls->maxhistnum - 1)); i--; } strcpy(rls->history[i++], rls->kbuffer); } rls->hist_total = i; fclose(fp); return 0; } int savehistory(const char *filename, struct rls *rls) { FILE *fp = fopen(filename, "w"); int i; if (fp == NULL) return errno; for (i = 0; i < rls->hist_total; i++) fprintf(fp, "%s\n", rls->history[i]); fclose(fp); return 0; } struct rls * readline_init(int histnum, int buflen) { struct rls *rls = NULL; int i; char *p = NULL; if (histnum < 1 || buflen < 1) return NULL; rls = malloc(sizeof(struct rls)); while (rls != NULL) { memset(rls, 0, sizeof(struct rls)); p = malloc((histnum + 2) * buflen); if (p == NULL) break; memset(p, 0, (histnum + 2) * buflen); rls->kbuffer = p; rls->history = malloc(histnum * sizeof(char *)); if (rls->history == NULL) break; for (i = 0; i <= histnum; i++) rls->history[i] = p + buflen * i; rls->kbuffer = p + buflen * (histnum + 1); rls->maxbuflen = buflen; rls->maxhistnum = histnum; rls->fdin = 0; rls->fdout = 1; return rls; } if (p != NULL) free(p); if (rls != NULL) free(rls); return NULL; } void readline_free(struct rls *rls) { if (rls->history != NULL) { free(rls->history[0]); free(rls->history); } free(rls); } int _readline(struct rls *rls) { int histmode; struct termios termios; int i, j; int fkey; char *kb; int ihist; int rc; char **tab; char *p; int off = 0; if (isatty(rls->fdin)) set_terminal(rls->fdin, &termios); memset(rls->kbuffer, 0, rls->maxbuflen); rls->pos = 0; histmode = 0; ihist = 0; kb = rls->kb; rc = 0; do { if (off >= rc) { memset(kb, 0, sizeof(rls->kb)); rc = read(rls->fdin, kb, sizeof(rls->kb)); if (rc <= 0) continue; off = 0; } else { memmove(kb, kb + off, rc - off); rc -= off; } #if 0 printf("\n%2.2x - %2.2x - %2.2x - %2.2x - %2.2x - %2.2x - %2.2x - %2.2x\n", kb[0], kb[1], kb[2], kb[3], kb[4], kb[5], kb[6], kb[6]); fflush(stdout); #endif if (kb[0] == ESC && kb[1] == ESC_PAD) { fkey = kb[2] | (kb[3] << 8); if (kb[2] == KEY_UP) { off = 3; if (histmode == 0) { histmode = 1; ihist = rls->hist_total; rls->kbuffer[rls->pos] = '\0'; strcpy(rls->history[rls->maxhistnum], rls->kbuffer); } if (ihist == 0) continue; i = findhistory(rls, 0 - ihist); if (i == -1) continue; ihist = i; i = strlen(rls->kbuffer); while (rls->pos++ < i) vprint(rls->fdout, " ", 1); while (i-- > 0) vprint(rls->fdout, "\b \b", 3); memset(rls->kbuffer, 0, rls->maxbuflen); strcpy(rls->kbuffer, rls->history[ihist]); rls->pos = strlen(rls->kbuffer); vprint(rls->fdout, rls->kbuffer, rls->pos); continue; } if (kb[2] == KEY_DOWN){ off = 3; if (histmode == 0) continue; if ((ihist + 1) >= rls->hist_total) { i = strlen(rls->kbuffer); while (rls->pos++ < i) vprint(rls->fdout, " ", 1); while (i-- > 0) vprint(rls->fdout, "\b \b", 3); memset(rls->kbuffer, 0, rls->maxbuflen); rls->pos = 0; histmode = 0; continue; } i = findhistory(rls, ihist); if (i == -1) continue; ihist = i; i = strlen(rls->kbuffer); while (rls->pos++ < i) vprint(rls->fdout, " ", 1); while (i-- > 0) vprint(rls->fdout, "\b \b", 3); memset(rls->kbuffer, 0, rls->maxbuflen); strcpy(rls->kbuffer, rls->history[ihist]); rls->pos = strlen(rls->kbuffer); vprint(rls->fdout, rls->kbuffer, rls->pos); continue; } if (kb[2] == KEY_RIGHT) { off = 3; if (rls->pos < strlen(rls->kbuffer)) vprint(rls->fdout, &(rls->kbuffer[rls->pos++]), 1); continue; } if (kb[2] == KEY_LEFT) { off = 3; if (rls->pos > 0) { vprint(rls->fdout, "\b", 1); rls->pos --; } continue; } if (fkey == KEY_HOME) { off = 4; while (rls->pos > 0) { vprint(rls->fdout, "\b", 1); rls->pos --; } continue; } if (fkey == KEY_END) { off = 4; while (rls->pos < strlen(rls->kbuffer)) { vprint(rls->fdout, &(rls->kbuffer[rls->pos++]), 1); } continue; } } histmode = 0; /* 'enter' */ if (kb[0] == LF || kb[0] == CR) { off = 1; trimspace(rls->kbuffer); rls->pos = strlen(rls->kbuffer); if (rls->pos == 0) break; if (rls->hist_total == rls->maxhistnum) { memmove(rls->history[0], rls->history[1], rls->maxbuflen * (rls->maxhistnum - 1)); rls->hist_total--; } strcpy(rls->history[rls->hist_total++], rls->kbuffer); break; } if (kb[0] == CTRLC) { off = 1; rls->pos = 0; rls->kbuffer[0] = '\0'; break; } if (kb[0] == '\t') { off = 1; if (rls->tab_callback == NULL) continue; p= NULL; if (rls->pos != 0) { p = rls->kbuffer + rls->pos; while (p > rls->kbuffer) { if (*(p - 1) == ' ') break; p--; } } tab = rls->tab_callback(rls->kbuffer, p); if (tab == NULL) continue; /* only one */ if (*tab != NULL && *(tab + 1) == NULL) { for (i = 0; i < strlen(p); i++) vprint(rls->fdout, "\b \b", 3); i = strlen(*tab); vprint(rls->fdout, *tab, i); if (p - rls->kbuffer + i < rls->maxbuflen) { strcpy(p, *tab); rls->pos = strlen(rls->kbuffer); } free(*tab); free(tab); continue; } /* more than one */ vprint(rls->fdout, "\n", 1); i = 0; while (*(tab + i)) { vprint(rls->fdout, *(tab + i), strlen(*(tab + i))); vprint(rls->fdout, " ", 1); free(*(tab + i)); i++; } vprint(rls->fdout, "\n", 1); free(tab); vprint(rls->fdout, rls->prompt, strlen(rls->prompt)); vprint(rls->fdout, rls->kbuffer, rls->pos); continue; } /* backspace */ if ((kb[0] == BACKSP0)|| (kb[0] == BACKSP1)) { off = 1; if (rls->pos > 0) { i = strlen(rls->kbuffer); j = rls->pos; while (j < i) { rls->kbuffer[j - 1] = rls->kbuffer[j]; j++; } rls->kbuffer[j - 1] = '\0'; rls->pos--; vprint(rls->fdout, "\b", 1); vprint(rls->fdout, &rls->kbuffer[rls->pos], strlen(&rls->kbuffer[rls->pos])); vprint(rls->fdout, " \b", 2); j = strlen(rls->kbuffer) - rls->pos; for (i = 0; i < j; i++) vprint(rls->fdout, "\b", 1); } continue; } /* normal key */ off = 1; i = kb[0]; if (!isprint(i)) continue; if (rls->pos < strlen(rls->kbuffer) - 1) { j = strlen(rls->kbuffer); /* avoid overflow */ if (j < rls->maxbuflen - 1) { p = rls->kbuffer; while (j > rls->pos) { *(p + j) = *(p + j - 1); j--; } rls->kbuffer[rls->pos] = kb[0]; vprint(rls->fdout, &rls->kbuffer[rls->pos], strlen(&rls->kbuffer[rls->pos])); j = strlen(rls->kbuffer) - rls->pos - 1; for (i = 0; i < j; i++) vprint(rls->fdout, "\b", 1); } } else { rls->kbuffer[rls->pos] = kb[0]; rls->kbuffer[rls->pos + 1] = '\0'; vprint(rls->fdout, &kb[0], 1); } rls->pos++; } while (kb[0] != CTRLP); if (isatty(rls->fdin)) reset_terminal(rls->fdin, &termios); return (rls->pos > 0 ? 1 : 0); } int findhistory(struct rls *rls, int start) { int len, i; /* no pattern */ len = strlen(rls->history[rls->maxhistnum]); if (len == 0) { if (start >= 0) { start++; return (start < rls->hist_total) ? start : -1; } else { // [-1 , -inf [ start = 0 - start; // [1 , inf [ start --; // [0 , inf [ return start; } } else { if (start >= 0) { start++; for (i = start; i < rls->hist_total; i++) if (!strncmp(rls->history[rls->maxhistnum], rls->history[i], len)) return i; return -1; } else { start = 0 - start; start --; for (i = start; i >= 0; i--) if (!strncmp(rls->history[rls->maxhistnum], rls->history[i], len)) return i; return -1; } } } void trimspace(char *buf) { char *p, *q; p = buf; if (p == NULL) return; q = p + strlen(p); while (q > p && *q == ' ') q--; *(q + 1) = '\0'; while (*p == ' ') p++; q = p; while (*q != '\0') *p++ = *q++; *p = '\0'; } void vprint(int fd, char *s, int len) { if (write(fd, s, len)) ; } void set_terminal(int fd, struct termios *stored_settings) { struct termios new_settings; tcgetattr(fd, stored_settings); new_settings = *stored_settings; new_settings.c_lflag &= ~(ICANON | ECHO | ISIG); //new_settings.c_iflag &= IGNCR; new_settings.c_cc[VTIME] = 1; new_settings.c_cc[VMIN] = 3; tcsetattr(fd, TCSANOW, &new_settings); return; } void reset_terminal(int fd, struct termios *stored_settings) { tcsetattr(fd, TCSANOW, stored_settings); return; } #ifdef MAIN char* cmd [] ={ "happy", "hot", "how" ,"read", "red", NULL }; char **my_complete(const char *string, const char *part) { char **matches; int i, j; matches = malloc(20 * sizeof(char *)); if (matches == NULL) return NULL; memset(matches, 0, 20 * sizeof(char*)); i = j = 0; if (part != NULL) { while (cmd[i] != NULL) { if (!strncmp(part, cmd[i], strlen(part))) matches[j++] = strdup(cmd[i]); i++; } } else { while (cmd[i] != NULL) { matches[j++] = strdup(cmd[i]); i++; } } return matches; } int main(int argc, char **argv) { struct rls *rls; char *p; int i; rls = readline_init(5, 1024); readline_tab(my_complete, rls); while (rls) { p = readline("CLI> ", rls); if (p != NULL) { printf("\nget %s\n", p); if (!strcmp(p, "h")) { printf("\n"); for (i = 0; i < rls->hist_total; i++) printf("%d: %s\n", i + 1, rls->history[i]); } else if (strcmp(p, "quit")) continue; break; } } return 1; } #endif /* end of file */ vpcs-0.8.3/src/readline.h000066400000000000000000000051321447703427300152340ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _READLINE_H_ #define _READLINE_H_ #include #include "keydef.h" struct rls { char kb[512]; int fdin; int fdout; char *kbuffer; /* key buffer */ int pos; /* pointer of key buffer */ char **history; int hist_total; /* current pointer of the history*/ char *prompt; int maxbuflen; int maxhistnum; char** (*tab_callback)(const char *string, const char *part); }; struct rls *readline_init(int histnum, int buflen); void readline_free(struct rls *rls); /* print the prompt, read a command string from the terminal and return it */ char *readline(const char *prompt, struct rls *rls); /* register tab completion callback function * * char** (*cb)(const char *string, const char *part) * args: string, the current input string * part, the partial word * return: an array of strings which is a list of completions */ int readline_tab(char** (*cb)(const char *string, const char *part), struct rls *rls); int savehistory(const char *filename, struct rls *rls); int loadhistory(const char *filename, struct rls *rls); void set_terminal(int fd, struct termios *stored_settings); void reset_terminal(int fd, struct termios *stored_settings); void kbhit(int fd); #endif /* end of file */ vpcs-0.8.3/src/relay.c000066400000000000000000000221671447703427300145670ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include "globle.h" #include "vpcs.h" #include "dev.h" #include "relay.h" #include "dump.h" struct node { u_int32_t ip; u_short port; }; struct peerlist { struct node nodea; struct node nodeb; struct peerlist *next; }; static struct peerlist *peerlist = NULL; static int relay_fd = 0; static int relay_port = 0; static FILE *relay_dumpfile = NULL; static int relaydump = 0; extern int runRelay; int run_relay(int argc, char **argv) { int port; struct peerlist peer, *tpeer, *peerhost; struct in_addr in; char tmp[32]; char *p; int i, j; if (!runRelay) { printf("Relay function is disabled\n"); return 0; } if (argc == 3 && !strcmp(argv[1], "dump")) { if (!strcasecmp(argv[2], "on")) relaydump = 1; else if (!strcasecmp(argv[2], "off")) relaydump = 0; if (relaydump) printf("dump on\n"); else printf("dump off\n"); return 0; } if (argc == 2 && !strcmp(argv[1], "dump")) { if (relaydump) printf("dump on\n"); else printf("dump off\n"); return 0; } if (argc == 3 && !strcmp(argv[1], "port")) { port = atoi(argv[2]); if (port > 1024 && port < 65534) { relay_port = port; if (relay_fd) close(relay_fd); relay_fd = open_udp(relay_port); if (relay_fd <= 0) { printf("Open relay port %d error [%s]\n", relay_port, strerror(errno)); } } else printf("The port is out of range\n"); return 0; } if (argc == 2 && !strcmp(argv[1], "show")) { printf("Relay port: %d\n", relay_port); peerhost = peerlist; printf("Relay list"); if (!peerhost || peerhost->nodea.port == 0) { printf(": none\n"); return 0; } printf(":\n"); i = 0; while (peerhost) { in.s_addr = peerhost->nodea.ip; printf(" %2d %s:%d", ++i, inet_ntoa(in), ntohs(peerhost->nodea.port)); in.s_addr = peerhost->nodeb.ip; printf(" <-> %s:%d\n", inet_ntoa(in), ntohs(peerhost->nodeb.port)); peerhost = peerhost->next; } return 0; } if (argc == 4 && !strcmp(argv[1], "add")) { p = strchr(argv[2], ':'); if (p) { bzero(tmp, sizeof(tmp)); strncpy(tmp, argv[2], p - argv[2]); peer.nodea.ip = inet_addr(tmp); i = atoi(p + 1); if (i < 1024 || i > 65534) { printf("port %d is out of range\n", i); return 0; } peer.nodea.port = htons(i); } else { peer.nodea.ip = htonl(INADDR_ANY); i = atoi(argv[2]); if (i < 1024 || i > 65534) { printf("port %d is out of range\n", i); return 0; } peer.nodea.port = htons(i); } p = strchr(argv[3], ':'); if (p) { bzero(tmp, sizeof(tmp)); strncpy(tmp, argv[3], p - argv[3]); peer.nodeb.ip = inet_addr(tmp); i = atoi(p + 1); if (i < 1024 || i > 65534) { printf("port %d is out of range\n", i); return 0; } peer.nodeb.port = htons(i); } else { peer.nodeb.ip = htonl(INADDR_ANY); i = atoi(argv[3]); if (i < 1024 || i > 65534) { printf("port %d is out of range\n", i); return 0; } peer.nodeb.port = htons(i); } /* existed ? */ peerhost = peerlist; for (j = 0;peerhost;) { if (((peerhost->nodea.ip == peer.nodea.ip) && (peerhost->nodea.port == peer.nodea.port)) || ((peerhost->nodeb.ip == peer.nodea.ip) && (peerhost->nodeb.port == peer.nodea.port))) { in.s_addr = peer.nodea.ip; port = peer.nodea.port; j = 1; break; } if (((peerhost->nodea.ip == peer.nodeb.ip) && (peerhost->nodea.port == peer.nodeb.port)) || ((peerhost->nodeb.ip == peer.nodeb.ip) && (peerhost->nodeb.port == peer.nodeb.port))) { in.s_addr = peer.nodeb.ip; port = peer.nodeb.port; j = 1; break; } peerhost = peerhost->next; } if (j == 1) { printf("%s:%d is existed\n", inet_ntoa(in), ntohs(port)); return 0; } /* append the rule */ tpeer = (struct peerlist *)malloc(sizeof(struct peerlist)); if (tpeer) { memcpy(tpeer, &peer, sizeof(peer)); tpeer->next = NULL; } else printf("Out of memory\n"); if (peerlist == NULL) peerlist = tpeer; else { peerhost = peerlist; while (peerhost->next) peerhost = peerhost->next; peerhost->next = tpeer; } return 0; } /* relay del */ if (argc == 3 && !strcmp(argv[1], "del")) { j = atoi(argv[2]); tpeer = peerlist; /* drop the head */ if (j == 1) { if (peerlist) { peerlist = peerlist->next; free(tpeer); } return 0; } peerhost = tpeer->next; i = 2; while (peerhost) { if (i == j) { tpeer->next = peerhost->next; free(peerhost); break; } tpeer = peerhost; peerhost = peerhost->next; i++; } return 0; } /* relay del port port */ if (argc == 4 && !strcmp(argv[1], "del")) { p = strchr(argv[2], ':'); if (p) { bzero(tmp, sizeof(tmp)); strncpy(tmp, argv[2], p - argv[2]); peer.nodea.ip = inet_addr(tmp); peer.nodea.port = htons(atoi(p + 1)); } else { peer.nodea.ip = htonl(INADDR_ANY); peer.nodea.port = htons(atoi(argv[2])); } p = strchr(argv[3], ':'); if (p) { bzero(tmp, sizeof(tmp)); strncpy(tmp, argv[3], p - argv[3]); peer.nodeb.ip = inet_addr(tmp); peer.nodeb.port = htons(atoi(p + 1)); } else { peer.nodeb.ip = htonl(INADDR_ANY); peer.nodea.port = htons(atoi(argv[3])); } tpeer = peerlist; peerhost = peerlist; for (;peerhost;) { if ((peerhost->nodea.ip == peer.nodea.ip) && (peerhost->nodea.port == peer.nodea.port) && (peerhost->nodeb.ip == peer.nodeb.ip) && (peerhost->nodea.port == peer.nodea.port)) { if (tpeer == peerlist) peerlist = peerhost->next; else tpeer->next = peerhost->next; free(peerhost); break; } tpeer = peerhost; peerhost = peerhost->next; } return 0; } return 0; } void save_relay(FILE *fp) { struct peerlist *peerhost = NULL; struct in_addr in; peerhost = peerlist; if (!peerhost || peerhost->nodea.port == 0) return; fprintf(fp, "relay port %d\n", relay_port); while (peerhost) { in.s_addr = peerhost->nodea.ip; fprintf(fp, "relay add %s:%d ", inet_ntoa(in), ntohs(peerhost->nodea.port)); in.s_addr = peerhost->nodeb.ip; fprintf(fp, "%s:%d\n", inet_ntoa(in), ntohs(peerhost->nodeb.port)); peerhost = peerhost->next; } } void *pth_relay(void *dummy) { char buf[1600]; int len; int n = 0; struct sockaddr_in peeraddr; struct sockaddr_in addr; socklen_t size; struct peerlist *peerhost; if (!runRelay) return NULL; relay_port = vpc[0].lport + MAX_NUM_PTHS; relay_fd = open_udp(relay_port); if (relay_fd <= 0) relay_fd = 0; /* waiting hub enable */ while (!peerlist) sleep(1); while (1) { len = sizeof(buf); size = sizeof(struct sockaddr_in); n = recvfrom(relay_fd, buf, len, 0, (struct sockaddr *)&peeraddr, &size); if (relaydump && relay_dumpfile == NULL) relay_dumpfile = open_dmpfile("relay"); if (relaydump) dmp_buffer2file(buf, n, relay_dumpfile); else if (relay_dumpfile) { close_dmpfile(relay_dumpfile); relay_dumpfile = NULL; } bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; peerhost = peerlist; for (;peerhost;) { if (peerhost->nodea.port == peeraddr.sin_port) { if (peerhost->nodea.ip == htonl(INADDR_ANY) || peerhost->nodea.ip == peeraddr.sin_addr.s_addr) { addr.sin_addr.s_addr = peerhost->nodeb.ip; addr.sin_port = peerhost->nodeb.port; break; } } if (peerhost->nodeb.port == peeraddr.sin_port) { if (peerhost->nodeb.ip == htonl(INADDR_ANY) || peerhost->nodeb.ip == peeraddr.sin_addr.s_addr) { addr.sin_addr.s_addr = peerhost->nodea.ip; addr.sin_port = peerhost->nodea.port; break; } } peerhost = peerhost->next; } if (addr.sin_port) { sendto(relay_fd, buf, n, 0, (struct sockaddr *)&addr, sizeof(addr)); } } return NULL; } /* end of file */ vpcs-0.8.3/src/relay.h000066400000000000000000000031121447703427300145610ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _RELAY_H_ #define _RELAY_H_ #include #include "vpcs.h" int run_relay(int argc, char **argv); void *pth_relay(void *dummy); void save_relay(FILE *fp); #endif /* end of file */ vpcs-0.8.3/src/remote.c000066400000000000000000000106201447703427300147350ustar00rootroot00000000000000/* * Copyright (c) 2007-2013, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include #include #include #include #include #include #include #include "globle.h" #include "remote.h" #include "readline.h" #include "utils.h" int open_remote(int fdio, const char *destip, const u_short destport) { int s; struct sockaddr_in addr_in; struct termios termios; char kb[512]; u_char outbuf[512]; int rc; int i; struct timeval tv; fd_set fset; static FILE *fpio; i = inet_addr(destip); if (i == -1) { printf("Invalid IP address\n"); return 0; } s = socket(AF_INET, SOCK_STREAM, 0); if (s == -1) return 0; bzero(&addr_in, sizeof(addr_in)); addr_in.sin_family = AF_INET; addr_in.sin_addr.s_addr = inet_addr(destip); addr_in.sin_port = htons(destport); fpio = fdopen(fdio, "w"); rc = connect(s, (struct sockaddr*)&addr_in, sizeof(struct sockaddr)); if (rc < 0) { if (errno == EINPROGRESS) { FD_ZERO(&fset); FD_SET(s, &fset); tv.tv_sec = 5; tv.tv_usec = 0; rc = select(s + 1, &fset, NULL, NULL, &tv); if (rc > 0 && FD_ISSET(s, &fset)) { i = sizeof(rc); getsockopt(s, SOL_SOCKET, SO_ERROR, &rc, (socklen_t *)&i); if (rc == 0) goto next; if (errno == EINPROGRESS) fprintf(fpio, "Connect timeout\n"); else fprintf(fpio, "Connect failed: %s\n", strerror(errno)); } else if (rc == 0) fprintf(fpio, "Connect timeout\n"); else fprintf(fpio, "Connect error: %s\n", strerror(errno)); fflush(fpio); close(s); return 1; } } next: set_terminal(fdio, &termios); fprintf(fpio, "\r\nConnect %s:%d, press Ctrl+X to quit\r\n", destip, destport); fprintf(fpio, "NOTES: you will be back to the starting point, NOT THE LAST, \r\n" " if using Ctrl+X to quit.\r\n"); fflush(fpio); while (1) { /* check socket */ kb[0] = 0xff; if (write(s, kb, 1) < 0) break; FD_ZERO(&fset); FD_SET(s, &fset); FD_SET(fdio, &fset); tv.tv_sec = 5; tv.tv_usec = 0; rc = select((fdio > s) ? (fdio + 1) : (s + 1), &fset, NULL, NULL, &tv); if (rc < 0) break; if (rc == 0) continue; if (FD_ISSET(s, &fset)) { rc = read(s, outbuf, sizeof(outbuf)); if (rc < 0) break; if (rc > 0) { i = 0; /* discard IAC */ while ( i < rc && outbuf[i] == 0xff ) i += 3; if (i < rc) { rc = write(fdio, outbuf + i, rc - i); if (rc < 0) break; } } } if (FD_ISSET(fdio, &fset)) { rc = read(fdio, kb, sizeof(kb)); if (rc < 0) break; if (kb[0] == CTRLX) break; /* my buddy likes '\r' */ if (kb[0] == LF) { rc = write(s, "\r", 1); if (rc < 0) break; continue; } if (rc > 0) { rc = write(s, kb, rc); if (rc < 0) break; } } } close(s); fprintf(fpio, "\r\nDisconnected from %s:%d\r\n", destip, destport); fflush(fpio); reset_terminal(fdio, &termios); return 0; } /* end of file */ vpcs-0.8.3/src/remote.h000066400000000000000000000030131447703427300147400ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _REMOTE_H_ #define _REMOTE_H_ int open_remote(int fdio, const char *ip, const unsigned short port); #endif /* end of file */ vpcs-0.8.3/src/tcp.c000066400000000000000000000450271447703427300142410ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include /* usleep */ #include /* random */ #include /* string op */ #include "vpcs.h" #include "tcp.h" #include "packets.h" #include "packets6.h" #include "utils.h" extern int pcid; extern int ctrl_c; extern u_int time_tick; extern int dmpflag; /******************************************************* * client server * SYN -> * <- SYN + ACK * ACk -> * (sseq+1) * ACK + PUSH + data -> * sseq + 1 * <- ACK * cseq + sizeof(data) * FIN -> * sseq+1 * wait1 * <- ACK * wait2 sseq+1 * <- FIN * close wait * ACk -> *******************************************************/ int tcp_ack(pcs *pc, int ipv) { struct packet *m = NULL; struct packet * (*fpacket)(pcs *pc); if (ipv == IPV6_VERSION) fpacket = packet6; else fpacket = packet; pc->mscb.flags = TH_ACK; m = fpacket(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); return 1; } int tcp_open(pcs *pc, int ipv) { struct packet *m, *p; int i = 0, ok; int state = 0; struct packet * (*fpacket)(pcs *pc); int (*fresponse)(struct packet *pkt, sesscb *sesscb); if (ipv == IPV6_VERSION) { fpacket = packet6; fresponse = response6; } else { fpacket = packet; fresponse = response; } /* try to connect */ while (i++ < 3 && ctrl_c == 0) { struct timeval tv; pc->mscb.flags = TH_SYN; pc->mscb.timeout = time_tick; pc->mscb.seq = rand(); pc->mscb.ack = 0; m = fpacket(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); //k = 0; ok = 0; gettimeofday(&(tv), (void*)0); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); while ((p = deq(&pc->iq)) != NULL && !timeout(tv, pc->mscb.waittime) && !ctrl_c) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if (ok == IPPROTO_ICMP) return 2; if (pc->mscb.rack == (pc->mscb.seq + 1) && pc->mscb.rflags == (TH_SYN | TH_ACK)) { state = 1; tv.tv_sec = 0; break; } if ((pc->mscb.rflags & TH_RST) != TH_RST) { pc->mscb.flags = TH_RST | TH_ACK; pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq; m = fpacket(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); delay_ms(1); tv.tv_sec = 0; break; } if ((pc->mscb.rflags & TH_RST) == TH_RST) return 3; tv.tv_sec = 0; break; } } if (state != 1) continue; /* reply ACK , ack+1 */ pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq + 1; tcp_ack(pc, ipv); return 1; } return 0; } /* * return 1 if ACK, 2 if FIN|PUSH */ int tcp_send(pcs *pc, int ipv) { struct packet *m, *p; int i = 0, ok; int state = 0; struct packet * (*fpacket)(pcs *pc); int (*fresponse)(struct packet *pkt, sesscb *sesscb); if (ipv == IPV6_VERSION) { fpacket = packet6; fresponse = response6; } else { fpacket = packet; fresponse = response; } /* drop the response if any, but update the ack */ while ((p = deq(&pc->iq)) != NULL) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if (pc->mscb.rflags == (TH_ACK | TH_PUSH) && pc->mscb.seq == pc->mscb.rack) { pc->mscb.ack = pc->mscb.rseq + pc->mscb.rdsize; tcp_ack(pc, ipv); delay_ms(1); } } /* try to send */ while (i++ < 3 && ctrl_c == 0) { struct timeval tv; pc->mscb.flags = TH_ACK | TH_PUSH; m = fpacket(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); //k = 0; ok = 0; gettimeofday(&(tv), (void*)0); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); while ((p = deq(&pc->iq)) != NULL) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if (pc->mscb.rflags == (TH_ACK) && pc->mscb.rack == pc->mscb.seq + pc->mscb.dsize) { pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq; state = 1; return 1; } if (pc->mscb.rflags == (TH_ACK | TH_PUSH)) { u_int tseq; tseq = pc->mscb.seq; pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq + pc->mscb.rdsize; tcp_ack(pc, ipv); if (pc->mscb.seq == tseq+ pc->mscb.dsize) return 1; else { delay_ms(1); continue; } } /* the remote does not like me, closing the connection */ if (pc->mscb.rflags == (TH_ACK | TH_PUSH | TH_FIN)) { pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq + pc->mscb.rdsize; state = 1; return 2; } tv.tv_sec = 0; break; } } if (state != 1) continue; return 1; } return 0; } int tcp_close(pcs *pc, int ipv) { struct packet *m, *p; int i = 0, ok; int state = 0; int rfin = 0; struct packet * (*fpacket)(pcs *pc); int (*fresponse)(struct packet *pkt, sesscb *sesscb); if (ipv == IPV6_VERSION) { fpacket = packet6; fresponse = response6; } else { fpacket = packet; fresponse = response; } /* drop the response if any, but update the ack */ while ((p = deq(&pc->iq)) != NULL) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if (pc->mscb.rflags == (TH_ACK | TH_PUSH) && pc->mscb.seq == pc->mscb.rack) { pc->mscb.ack = pc->mscb.rseq + pc->mscb.rdsize; tcp_ack(pc, ipv); delay_ms(1); continue; } if (pc->mscb.rflags == TH_ACK) { pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq; break; } if ((pc->mscb.rflags & (TH_ACK | TH_FIN)) == (TH_ACK | TH_FIN)) { pc->mscb.seq = pc->mscb.rack; pc->mscb.ack = pc->mscb.rseq; pc->mscb.ack++; tcp_ack(pc, ipv); delay_ms(1); rfin = 1; continue; } } /* try to close */ while (i++ < 3 && ctrl_c == 0) { struct timeval tv; state = 0; pc->mscb.flags = TH_FIN | TH_ACK | TH_PUSH; m = fpacket(pc); if (m == NULL) { printf("out of memory\n"); return 0; } /* push m into the background output queue which is watched by pth_output */ enq(&pc->bgoq, m); /* expect ACK */ gettimeofday(&(tv), (void*)0); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); while ((p = deq(&pc->iq)) != NULL) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if ((pc->mscb.rflags & (TH_ACK | TH_FIN) ) == (TH_ACK | TH_FIN)) state = 1; else if (pc->mscb.rflags == TH_ACK) state = 2; tv.tv_sec = 0; break; } } if (state == 0) continue; /* both side sent and received FIN/ACK, closed! */ if (rfin == 1 && state == 2) return 1; /* local send FIN/ACK first */ if (state == 2) { /* expect FIN */ state = 0; //k = 0; gettimeofday(&(tv), (void*)0); while (!timeout(tv, pc->mscb.waittime) && !ctrl_c) { delay_ms(1); while ((p = deq(&pc->iq)) != NULL) { ok = fresponse(p, &pc->mscb); del_pkt(p); if (!ok) continue; if ((pc->mscb.rflags & TH_FIN) == TH_FIN) { /* change my seq, seq += 1 */ pc->mscb.seq = pc->mscb.rack; state = 1; } tv.tv_sec = 0; break; } } } /* ACK was not received in the time */ if (state == 0) return 0; /* the remote sent FIN/ACK, response the ACK */ pc->mscb.ack++; tcp_ack(pc, ipv); return 1; } return 0; } /* tcp processor * return PKT_DROP/PKT_UP */ int tcpReplyPacket(tcphdr *th, sesscb *cb, int tcplen) { int clientfinack = 0; /* ack for fin was reply if 1 */ int dsize = 0; th->th_sport ^= th->th_dport; th->th_dport ^= th->th_sport; th->th_sport ^= th->th_dport; cb->ack = ntohl(th->th_seq); cb->rflags = th->th_flags; cb->winsize = ntohs(th->th_win); if (cb->flags != (TH_RST | TH_FIN)) { switch (th->th_flags) { case TH_SYN: cb->flags = TH_ACK | TH_SYN; cb->ack++; break; case TH_ACK | TH_PUSH: cb->flags = TH_ACK; dsize = tcplen - (th->th_off << 2); break; case TH_ACK | TH_FIN: cb->flags = (TH_ACK | TH_FIN); cb->ack++; break; case TH_ACK | TH_FIN | TH_PUSH: case TH_FIN | TH_PUSH: dsize = tcplen - (th->th_off << 2); case TH_FIN: if (cb->flags == (TH_ACK | TH_FIN)) cb->flags = TH_FIN | TH_ACK; else cb->flags = TH_ACK; if (dsize == 0) cb->ack++; clientfinack = 1; break; default: return 0; } } if (th->th_flags != TH_SYN) cb->seq = ntohl(th->th_ack); th->th_ack = htonl(cb->ack + dsize); th->th_seq = htonl(cb->seq); th->th_flags = cb->flags; /* ignore the tcp options */ if ((th->th_off << 2) > sizeof(tcphdr)) th->th_off = sizeof(tcphdr) >> 2; if (clientfinack == 1) return 2; return 1; } int tcp(pcs *pc, struct packet *m) { iphdr *ip = (iphdr *)(m->data + sizeof(ethdr)); tcpiphdr *ti = (tcpiphdr *)(ip); sesscb *cb = NULL; struct packet *p = NULL; int i; if (ip->dip != pc->ip4.ip) return PKT_DROP; /* response packet * 1. socket opened * 2. same port * 3. destination is me * 4. mscb.proto is TCP */ if (pc->mscb.sock && ntohs(ti->ti_dport) == pc->mscb.sport && ntohs(ti->ti_sport) == pc->mscb.dport && ip->sip == pc->mscb.dip && pc->mscb.proto == ip->proto) { /* mscb is actived, up to the upper application */ if (time_tick - pc->mscb.timeout <= TCP_TIMEOUT) return PKT_UP; /* not mine, reset the request */ sesscb rcb; rcb.seq = random(); rcb.sip = ip->sip; rcb.dip = ip->dip; rcb.sport = ti->ti_sport; rcb.dport = ti->ti_dport; rcb.flags = TH_RST | TH_FIN | TH_ACK; p = tcpReply(m, &rcb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } else printf("reply error\n"); /* drop the request packet */ return PKT_DROP; } /* request process * find control block */ for (i = 0; i < MAX_SESSIONS; i++) { if (ti->ti_flags == TH_SYN) { if (pc->sesscb[i].timeout == 0 || time_tick - pc->sesscb[i].timeout > TCP_TIMEOUT || (ip->sip == pc->sesscb[i].sip && ip->dip == pc->sesscb[i].dip && ti->ti_sport == pc->sesscb[i].sport && ti->ti_dport == pc->sesscb[i].dport)) { /* get new scb */ cb = &pc->sesscb[i]; cb->timeout = time_tick; cb->seq = random(); cb->sip = ip->sip; cb->dip = ip->dip; cb->sport = ti->ti_sport; cb->dport = ti->ti_dport; break; } } else { if ((time_tick - pc->sesscb[i].timeout <= TCP_TIMEOUT) && ip->sip == pc->sesscb[i].sip && ip->dip == pc->sesscb[i].dip && ti->ti_sport == pc->sesscb[i].sport && ti->ti_dport == pc->sesscb[i].dport) { /* get the scb */ cb = &pc->sesscb[i]; break; } } } if (ti->ti_flags == TH_SYN && cb == NULL) { printf("VPCS %d out of session\n", pc->id); return PKT_DROP; } if (cb != NULL) { if (ti->ti_flags == TH_ACK && cb->flags == TH_FIN) { /* clear session */ memset(cb, 0, sizeof(sesscb)); } else { cb->timeout = time_tick; p = tcpReply(m, cb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } /* send FIN after ACK if got FIN */ if ((cb->rflags & TH_FIN) == TH_FIN && cb->flags == (TH_ACK | TH_FIN)) { p = tcpReply(m, cb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } } } } /* anyway tell caller to drop this packet */ return PKT_DROP; } struct packet *tcpReply(struct packet *m0, sesscb *cb) { ethdr *eh; iphdr *ip; tcpiphdr *ti; tcphdr *th; struct packet *m; char b[9]; int len; int tcplen = 0; len = sizeof(ethdr) + sizeof(iphdr) + sizeof(tcphdr); m = new_pkt(len); if (m == NULL) return NULL; memcpy(m->data, m0->data, m->len); eh = (ethdr *)(m->data); ip = (iphdr *)(eh + 1); ti = (tcpiphdr *)ip; th = (tcphdr *)(ip + 1); tcplen = ntohs(ip->len) - sizeof(iphdr); ip->len = htons(len - sizeof(ethdr)); ip->dip ^= ip->sip; ip->sip ^= ip->dip; ip->dip ^= ip->sip; ip->ttl = TTL; int rt = tcpReplyPacket(th, cb, tcplen); if (rt == 0) { del_pkt(m); return NULL; } ti->ti_len = htons(len - sizeof(iphdr)); bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ti->ti_sum = 0; ti->ti_sum = cksum((u_short*)ti, len); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); ip->cksum = 0; ip->cksum = cksum((u_short *)ip, sizeof(iphdr)); swap_ehead(m->data); /* save the status, ACK for TH_FIN of client was sent * so send FIN on the next time */ if (rt == 2) cb->flags = (TH_ACK | TH_FIN); return m; } int tcp6(pcs *pc, struct packet *m) { ip6hdr *ip = (ip6hdr *)(m->data + sizeof(ethdr)); struct tcphdr *th = (struct tcphdr *)(ip + 1); sesscb *cb = NULL; struct packet *p = NULL; int i; /* from linklocal */ if (ip->src.addr16[0] == IPV6_ADDR_INT16_ULL) { if (!IP6EQ(&(pc->link6.ip), &(ip->dst)))// || th->th_sport != th->th_dport) return PKT_DROP; } else { if (!IP6EQ(&(pc->ip6.ip), &(ip->dst)))// || th->th_sport != th->th_dport) return PKT_DROP; } /* response packet * 1. socket opened * 2. same port * 3. destination is me * 4. mscb.proto is TCP */ if (pc->mscb.sock && pc->mscb.proto == ip->ip6_nxt && ntohs(th->th_dport) == pc->mscb.sport && ntohs(th->th_sport) == pc->mscb.dport && IP6EQ(&(pc->mscb.dip6), &(ip->src))) { /* mscb is actived, up to the upper application */ if (time_tick - pc->mscb.timeout <= TCP_TIMEOUT) return PKT_UP; /* not mine, reset the request*/ sesscb rcb; rcb.seq = random(); memcpy(rcb.sip6.addr8, ip->src.addr8, 16); memcpy(rcb.dip6.addr8, ip->dst.addr8, 16); rcb.sport = th->th_sport; rcb.dport = th->th_dport; rcb.flags = TH_RST | TH_FIN | TH_ACK; rcb.seq = time(0); p = tcp6Reply(m, &rcb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } else printf("reply error\n"); /* drop the request packet */ return PKT_DROP; } /* request process * find control block */ for (i = 0; i < MAX_SESSIONS; i++) { if (th->th_flags == TH_SYN) { if (pc->sesscb[i].timeout == 0 || (IP6EQ(&(pc->sesscb[i].sip6), &(ip->src)) && IP6EQ(&(pc->sesscb[i].dip6), &(ip->dst)) && th->th_sport == pc->sesscb[i].sport && th->th_dport == pc->sesscb[i].dport)) { /* get new scb */ cb = &pc->sesscb[i]; cb->timeout = time_tick; cb->seq = random(); memcpy(cb->sip6.addr8, ip->src.addr8, 16); memcpy(cb->dip6.addr8, ip->dst.addr8, 16); cb->sport = th->th_sport; cb->dport = th->th_dport; break; } } else { if ((time_tick - pc->sesscb[i].timeout <= TCP_TIMEOUT) && IP6EQ(&(pc->sesscb[i].sip6), &(ip->src)) && IP6EQ(&(pc->sesscb[i].dip6), &(ip->dst)) && th->th_sport == pc->sesscb[i].sport && th->th_dport == pc->sesscb[i].dport) { /* get the scb */ cb = &pc->sesscb[i]; break; } } } if (th->th_flags == TH_SYN && cb == NULL) { printf("VPCS %d out of session\n", pc->id); return PKT_DROP; } if (cb != NULL) { if (th->th_flags == TH_ACK && cb->flags == TH_FIN) { /* clear session */ memset(cb, 0, sizeof(sesscb)); } else { cb->timeout = time_tick; p = tcp6Reply(m, cb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } /* send FIN after ACK if got FIN */ if ((cb->rflags & TH_FIN) == TH_FIN && cb->flags == (TH_ACK | TH_FIN)) { p = tcp6Reply(m, cb); /* push m into the background output queue which is watched by pth_output */ if (p != NULL) { enq(&pc->bgoq, p); } } } } /* anyway tell caller to drop this packet */ return PKT_DROP; } struct packet *tcp6Reply(struct packet *m0, sesscb *cb) { ethdr *eh; ip6hdr *ip; tcphdr *th; struct packet *m; int len; int tcplen = 0; len = sizeof(ethdr) + sizeof(ip6hdr) + sizeof(tcphdr); m = new_pkt(len); if (m == NULL) return NULL; memcpy(m->data, m0->data, m->len); eh = (ethdr *)(m->data); ip = (ip6hdr *)(eh + 1); th = (struct tcphdr *)(ip + 1); swap_ehead(m->data); swap_ip6head(m); ip->ip6_hlim = TTL; tcplen = ntohs(ip->ip6_plen); ip->ip6_plen = htons((u_short)sizeof(tcphdr)); int rt = tcpReplyPacket(th, cb, tcplen); if (rt == 0) { del_pkt(m); return NULL; } th->th_sum = 0; th->th_sum = cksum6(ip, IPPROTO_TCP, len); /* save the status, ACK for TH_FIN of client was sent * so send FIN on the next time */ if (rt == 2) cb->flags = (TH_ACK | TH_FIN); return m; } /* end of file */ vpcs-0.8.3/src/tcp.h000066400000000000000000000032411447703427300142360ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _TCP_H_ #define _TCP_H_ #define TCP_TIMEOUT 60 /* seconds */ int tcp_open(pcs *pc, int ipv); int tcp_send(pcs *pc, int ipv); int tcp_close(pcs *pc, int ipv); int tcp(pcs *pc, struct packet *m0); struct packet *tcpReply(struct packet *m0, sesscb *cb); #endif /* end of file */ vpcs-0.8.3/src/utils.c000066400000000000000000000114161447703427300146060ustar00rootroot00000000000000/* * Copyright (c) 2007-2012, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include #include "utils.h" #define MAX_LEN (128) static int search_pairs(const char *s, char **lf, char **rt); int mkargv(char *str, char **argv, int max) { int n = 0; char *p, *q, *es; char **args = argv; char *sep = "=/ \t"; static char buf[MAX_LEN]; if (str == NULL) return n; memset(buf, 0, sizeof(buf)); strncpy(buf, str, sizeof(buf) - 1); p = buf; es = p + strlen(buf); while (p && p < es && n < max) { if (*p == '"') { q = strchr(p + 1, '"'); if (!q) goto ret; *q = '\0'; /* ignore "" */ if (q > p + 1) args[n++] = p + 1; p = ++q; continue; } if ((q = strsep(&p, sep)) != NULL) { /* ignore empty substring */ if (*q != '\0') args[n++] = q; continue; } break; } ret: args[n] = NULL; return n; } int insert_argv(int argc, char **argv, char *str) { char *av[20]; int i; for (i = 0; i < argc; i++) av[i] = argv[i]; argv[0] = str; for (i = 0; i < argc; i++) argv[i + 1] = av[i]; return (argc + 1); } int timeout(struct timeval tv, int mseconds) { struct timeval tvx; unsigned int usec; gettimeofday(&(tvx), (void*)0); usec = (tvx.tv_sec - tv.tv_sec) * 1000000 + tvx.tv_usec - tv.tv_usec; return ((usec / 1000) >= mseconds); } int digitstring(const char *s) { int i = 0; if (s == NULL) return 0; while (*s >= '0' && *s <= '9') { s++; i++; if (*s == '\0') return i; } return 0; } char *ttrim(char *s) { int len; int c; if (s == NULL) return NULL; len = strlen(s); len--; while (len >= 0) { c = s[len]; if (!isspace(c)) break; len--; } s[len + 1] = '\0'; return s; } int arg2int(const char* arg, int min, int max, int defval) { int r; if (arg == NULL || sscanf(arg, "%d", &r) != 1) return defval; return r; } /* Highlight {Hword} * Underline {Uword} * Color {Nword}, N from 1 to 9 */ void esc_prn(const char *fmt, ...) { va_list ap; char tmp[4096]; va_start(ap, fmt); vsprintf(tmp, fmt, ap); esc_fprn(stdout, "%s", tmp); va_end(ap); } void esc_fprn(FILE *f, const char *fmt, ...) { char *buf; char *tmp; char *p; char *lf, *rt; va_list ap; buf = malloc(4096); if (!buf) return; tmp = malloc(4096); if (!tmp) { free(buf); return; } va_start(ap, fmt); vsprintf(tmp, fmt, ap); va_end(ap); p = tmp; buf[0] = '\0'; while (1) { if (search_pairs(p, &lf, &rt) == 0) break; strncat(buf, p, lf - p); lf++; switch (*lf) { case 'H': strcat(buf, "\033[1m"); break; case 'U': strcat(buf, "\033[4m"); default: break; } lf++; strncat(buf, lf, rt - lf); strcat(buf, "\033[0m"); p = rt + 1; } if (p) strcat(buf, p); fprintf(f, "%s", buf); free(tmp); free(buf); } static int search_pairs(const char *s, char **lf, char **rt) { char *p, *q, *r; p = strchr(s, '{'); if (!p) return 0; if (*(p + 1)) { q = strchr(p + 1, '}'); r = strchr(p + 1, '{'); if (!q) return 0; /* nesting is not allowed */ if (r && r < q) return 0; *lf = p; *rt = q; return 1; } return 0; } #if 0 void preh(u_char *e) { int i; for (i = 0; i < 6; i++) printf("%2.2x ", *(e + i)); return; } #include int logs(const char *fmt, ...) { va_list ap; FILE *fp; int ret; fp = fopen("vpcs.log", "a+"); va_start(ap, fmt); ret = vfprintf(fp, fmt, ap); va_end(ap); fclose(fp); return ret; } #endif /* end of file */ vpcs-0.8.3/src/utils.h000066400000000000000000000035321447703427300146130ustar00rootroot00000000000000/* * Copyright (c) 2007-2015, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _UTILS_H_ #define _UTILS_H_ #include #include char *getkv(char *str); int mkargv(char *str, char **argv, int max); int insert_argv(int argc, char **argv, char *str); int timeout(struct timeval tv, int mseconds); int digitstring(const char *s); char *ttrim(char *s); void esc_prn(const char *fmt, ...); void esc_fprn(FILE *f, const char *fmt, ...); int arg2int(const char* arg, int min, int max, int defalt); #endif /* end of file */ vpcs-0.8.3/src/vpcs.c000066400000000000000000000373131447703427300144250ustar00rootroot00000000000000/* * Copyright (c) 2007-2016, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #include #include #include #include /* usleep */ #include #include #include #include #ifdef cygwin #include #include #endif #include "globle.h" #include "vpcs.h" #include "readline.h" #include "packets.h" #include "utils.h" #include "dev.h" #include "command.h" #include "command6.h" #include "daemon.h" #include "help.h" #include "dump.h" #include "relay.h" #include "dhcp.h" #include "frag6.h" const char *ver = "0.8.3"; /* track the binary */ static const char *ident = "$Id$"; pcs vpc[MAX_NUM_PTHS]; int pcid = 0; /* current vpc id */ int devtype = 0; int lport = 20000; int rport = 30000; int rport_flag = 0; u_int rhost = 0; /* remote host */ struct echoctl echoctl; int runLoad = 0; /* work with canEcho */ int runRelay = 1; /* sw of relay function */ int runStartup = 0; /* execute startup if 1 */ char *startupfile = NULL; const char *default_startupfile = "startup.vpc"; char *histfile = "vpcs.hist"; u_int time_tick = 0; /* time tick (second) */ int ctrl_c = 0; /* ctrl+c was pressed */ struct rls *rls = NULL; int daemon_port = 0; int num_pths = MAX_NUM_PTHS; /* number of VPCs */ char *tapname = "tap0"; /* TAP device name (only when 1 VPC is created) */ int macaddr = 0; /* the last byte of ether address */ static void *pth_reader(void *devid); static void *pth_output(void *devid); static void *pth_writer(void *devid); static void *pth_timer_tick(void *); static void *pth_bgjob(void *); void parse_cmd(char *cmdstr); static void sig_int(int sig); static void sig_clean(int sig); void clear_hist(void); static void welcome(void); void usage(); static void startup(void); static int run_quit(int argc, char **argv); static int run_disconnect(int argc, char **argv); struct stub { char *name; char *grpname; int (*f)(int argc, char **argv); int (*help)(int argc, char **argv); }; typedef struct stub cmdStub; static cmdStub cmd_entry[] = { {"?", NULL, run_help, help_help}, {"arp", "show", run_show, help_show}, {"clear", NULL, run_clear, help_clear}, {"dhcp", "ip", run_ipconfig, help_ip}, {"disconnect", NULL, run_disconnect, NULL}, {"echo", NULL, run_echo, NULL}, {"help", NULL, run_help, help_help}, {"history", NULL, run_hist, NULL}, {"relay", NULL, run_relay, help_relay}, {"ip", NULL, run_ipconfig, help_ip}, {"load", NULL, run_load, help_load}, {"neighbor", NULL, run_nb6, NULL}, {"ping", NULL, run_ping, help_ping}, {"quit", NULL, run_quit, NULL}, {"tracer", NULL, run_tracert, help_trace}, {"rlogin", NULL, run_remote, help_rlogin}, {"save", NULL, run_save, help_save}, {"write", NULL, run_save, help_write}, {"set", NULL, run_set, help_set}, {"show", NULL, run_show, help_show}, {"version", NULL, run_ver, NULL}, {"sleep", NULL, run_sleep, help_sleep}, {"zzz", NULL, run_sleep, help_sleep}, {NULL, NULL} }; #ifdef HV int vpcs(int argc, char **argv) #else int main(int argc, char **argv) #endif { int i; char prompt[MAX_LEN]; int c; pthread_t timer_pid, relay_pid, bgjob_pid; int daemon_bg = 1; char *cmd; memset(&echoctl, 0, sizeof(struct echoctl)); rhost = inet_addr("127.0.0.1"); devtype = DEV_UDP; while ((c = getopt(argc, argv, "?c:efhm:p:r:Rs:t:uvFi:d:")) != -1) { switch (c) { case 'c': rport_flag = 1; rport = arg2int(optarg, 1024, 65000, 30000); break; case 'e': devtype = DEV_TAP; break; case 'f': daemon_bg = 0; break; case 'm': macaddr = arg2int(optarg, 0, 240, 0); break; case 'p': daemon_port = arg2int(optarg, 1024, 65000, 5000); break; case 'r': startupfile = strdup(optarg); break; case 'R': runRelay = 0; break; case 's': lport = arg2int(optarg, 1024, 65000, 20000); break; case 't': if (inet_addr(optarg) != -1) rhost = inet_addr(optarg); break; case 'u': devtype = DEV_UDP; break; case 'v': run_ver(argc, argv); exit(0); break; case 'F': daemon_bg = 0; break; case 'i': num_pths = arg2int(optarg, 1, 9, 9); break; case 'd': if (num_pths != 1) { usage(); exit(0); } tapname = strdup(optarg); break; case 'h': case '?': usage(); exit(0); break; } } if (optind != argc) { if (optind + 1 == argc) startupfile = strdup(argv[optind]); else { usage(); exit(0); } } if (daemon_port && daemonize(daemon_port, daemon_bg)) exit(0); if (!isatty(0)) { printf("Please run in the tty\n"); exit(-1); } signal(SIGINT, &sig_int); signal(SIGUSR1, &sig_clean); signal(SIGCHLD, SIG_IGN); welcome(); srand(time(0)); init_ipfrag(); init_ip6frag(); memset(vpc, 0, MAX_NUM_PTHS * sizeof(pcs)); for (i = 0; i < num_pths; i++) { if (pthread_create(&(vpc[i].rpid), NULL, pth_reader, (void *)&i) != 0) { printf("PC%d error\n", i + 1); fflush(stdout); exit(-1); } strcpy(vpc[i].xname, "VPCS"); while (vpc[i].ip4.mac[4] == 0) delay_ms(10); delay_ms(100); } pthread_create(&timer_pid, NULL, pth_timer_tick, (void *)0); delay_ms(100); pthread_create(&relay_pid, NULL, pth_relay, (void *)0); pthread_create(&bgjob_pid, NULL, pth_bgjob, (void *)0); pcid = 0; delay_ms(50); autoconf6(); delay_ms(50); startup(); rls = readline_init(50, MAX_LEN); if (rls == NULL) { printf("initialize readline error\n"); return 1; } if (histfile != NULL) loadhistory(histfile, rls); while (1) { if (num_pths > 1) snprintf(prompt, sizeof(prompt), "\n\r%s[%d]> ", vpc[pcid].xname, pcid + 1); else snprintf(prompt, sizeof(prompt), "\n\r%s> ", vpc[pcid].xname); ctrl_c = 0; cmd = readline(prompt, rls); if (cmd != NULL) { ttrim(cmd); parse_cmd(cmd); } } return 0; } void parse_cmd(char *cmdstr) { cmdStub *ep = NULL, *cmd = NULL; char *argv[20]; int argc = 0; int rc = 0; char *pcmd; int at = 0; if (cmdstr[0] == '#' || cmdstr[0] == ';') return; argc = mkargv(cmdstr, (char **)argv, 20); if (argc == 0) return; if (argc == 1 && strlen(argv[0]) == 1 && num_pths >= 1 && (argv[0][0] >= '0' && argv[0][0] <= '9')) { if ((argv[0][0] - '0') <= num_pths) { if (echoctl.enable && runLoad) printf("%s[%d] %s\n", vpc[pcid].xname, pcid + 1, cmdstr); pcid = argv[0][0] - '0' - 1; } else printf("\nOnly %d VPCs actived\n", num_pths); return; } rc = 0; printf("\n"); if (!strcmp(argv[0], "srcid")) { printf("Source code ID: %s\n", ident); return; } if (!strncmp(argv[0], "echo", strlen(argv[0]))) { char *p = NULL; p = strchr(cmdstr, ' '); if (echoctl.fgcolor != 0) { if (echoctl.bgcolor != 0) printf("\033[%d;%dm", echoctl.fgcolor, echoctl.bgcolor); else printf("\033[%dm", echoctl.fgcolor); } if (p != NULL) printf("%s", p + 1); else { p = strchr(cmdstr, '\t'); if (p != NULL) printf("%s", p + 1); } if (echoctl.fgcolor != 0) printf("\033[0m"); fflush(stdout); return; } pcmd = argv[0]; if (*pcmd == '@') { at = 1; pcmd ++; } for (ep = cmd_entry; ep->name != NULL; ep++) { if(!strncmp(pcmd, ep->name, strlen(pcmd))) { if (cmd != NULL) printf("%s\n", cmd->name); cmd = ep; rc++; } } if (rc > 1) { printf("%s\n", cmd->name); return; } if(cmd && cmd->name != NULL) { if (cmd->grpname != NULL) { argc = insert_argv(argc, argv, cmd->grpname); for (ep = cmd_entry; ep->name != NULL; ep++) { if(!strcmp(pcmd, ep->name)) { cmd = ep; break; } } } if (echoctl.enable && runLoad) { if (!strcmp(cmd->name, "sleep") && (argc != 2 || !digitstring(argv[1]))) { ; } else if (at == 0) printf("%s[%d] %s\n", vpc[pcid].xname, pcid + 1, cmdstr); } if (argc > 1 && cmd->help != NULL && ((!strcmp(argv[argc - 1], "?") || !strcmp(argv[argc - 1], "help")))) { argv[0] = cmd->name; cmd->help(argc, argv); return; } /* the session control block */ memset(&vpc[pcid].mscb, 0, sizeof(vpc[pcid].mscb)); vpc[pcid].mscb.sock = 1; rc = cmd->f(argc, argv); memset(&vpc[pcid].mscb, 0, sizeof(vpc[pcid].mscb)); } else printf("Bad command: \"%s\". Use ? for help.\n", cmdstr); return; } void sig_int(int sig) { ctrl_c = 1; signal(SIGINT, &sig_int); } void *pth_reader(void *devid) { int id; pcs *pc = NULL; struct packet *m = NULL; u_char buf[PKT_MAXSIZE]; int rc; id = *(int *)devid; pc = &vpc[id]; pc->id = id; pc->rhost = rhost; pc->lport = lport + id; pc->rport = rport + id; pc->ip4.mac[0] = 0x00; pc->ip4.mac[1] = 0x50; pc->ip4.mac[2] = 0x79; pc->ip4.mac[3] = 0x66; pc->ip4.mac[4] = 0x68; pc->ip4.mac[5] = (id + macaddr) & 0xff; pc->ip4.flags |= IPF_FRAG; pc->mtu = 1500; if (pc->fd == 0) pc->fd = open_dev(id); if (pc->fd <= 0) { if (devtype == DEV_TAP) if (num_pths > 1) printf("Create TAP device tap%d error [%s]\n", id, strerror(errno)); else printf("Create TAP device %s error [%s]\n", tapname, strerror(errno)); else if (devtype == DEV_UDP) printf("Open port %d error [%s]\n", vpc[id].lport, strerror(errno)); return NULL; } pthread_mutex_init(&(pc->locker), NULL); init_queue(&pc->iq); pc->iq.type = 0 + id * 100; init_queue(&pc->oq); pc->oq.type = 1 + id * 100; init_queue(&pc->bgiq); pc->bgiq.type = 2 + id * 100; init_queue(&pc->bgoq); pc->bgoq.type = 3 + id * 100; if (pthread_create(&(pc->wpid), NULL, pth_writer, devid) != 0) { printf("PC%d error\n", id + 1); exit(-1); } if (pthread_create(&(pc->outid), NULL, pth_output, devid) != 0) { printf("PC%d error\n", id + 1); exit(-1); } while (1) { rc = VRead(pc, buf, PKT_MAXSIZE); if (rc > 0) { m = new_pkt(PKT_MAXSIZE); if (m == NULL) { printf("Out of memory.\n"); exit(-1); } memcpy(m->data, buf, rc); m->len = rc; gettimeofday(&(m->ts), (void*)0); if (!memcmp(m->data, pc->ip4.mac, ETH_ALEN) || pc->dmpflag & DMP_ALL) { if (pc->dmpflag & DMP_FILE) dmp_packet2file(m, pc->dmpfile); dmp_packet(m, pc->dmpflag); } rc = upv4(pc, &m); if (rc == PKT_UP) { if (dhcp_enq(pc, m)) continue; if (pc->mscb.sock != 0) { enq(&pc->iq, m); } else del_pkt(m); } else if (rc == PKT_DROP) del_pkt(m); } } return NULL; } void *pth_output(void *devid) { int id; pcs *pc = NULL; struct packet *m = NULL; id = *(int *)devid; pc = &vpc[id]; /* send4 or send6 will block this thread for a while to get the ether address via arpresolv or neighbor solicitation */ while (1) { m = waitdeq(&pc->bgoq); while (m) { send4(pc, m); m = deq(&pc->bgoq); } } return NULL; } void *pth_writer(void *devid) { int id; pcs *pc = NULL; id = *(int *)devid; pc = &vpc[id]; locallink6(pc); while (1) { struct packet *m = NULL; m = waitdeq(&pc->oq); while (m) { if (pc->dmpflag & DMP_FILE) dmp_packet2file(m, pc->dmpfile); dmp_packet(m, pc->dmpflag); if (VWrite(pc, m->data, m->len) != m->len) printf("Send packet error\n"); del_pkt(m); m = deq(&pc->oq); } } return NULL; } void *pth_timer_tick(void *dummy) { while (1) { time_tick = time(0); usleep(1000); } return NULL; } void *pth_bgjob(void *dummy) { int i; int t, s; i = 0; do { if (vpc[i].ip4.dhcp.svr && vpc[i].ip4.dhcp.timetick) { t = time_tick - vpc[i].ip4.dhcp.timetick; s = t - vpc[i].ip4.dhcp.renew; if (t > vpc[i].ip4.dhcp.renew && s < 4) { vpc[i].bgjobflag = 1; if (dhcp_renew(&vpc[i])) vpc[i].ip4.dhcp.timetick = time_tick; vpc[i].bgjobflag = 0; continue; } s = t - vpc[i].ip4.dhcp.rebind; if (t > vpc[i].ip4.dhcp.rebind && s < 4) { vpc[i].bgjobflag = 1; if (dhcp_rebind(&vpc[i])) vpc[i].ip4.dhcp.timetick = time_tick; vpc[i].bgjobflag = 0; continue; } } usleep(1000); i = (i + 1) % num_pths; } while (1); return NULL; } void startup(void) { FILE *fp; int argc; char *argv[3]; if (startupfile == NULL) { fp = fopen(default_startupfile, "r"); if (fp != NULL) { fclose(fp); argv[0] = "load"; argv[1] = (char *)default_startupfile; argv[2] = NULL; argc = 2; runStartup = 1; run_load(argc, argv); runStartup = 0; } return; } else { fp = fopen(startupfile, "r"); if (fp != NULL) { fclose(fp); runStartup = 1; argv[0] = "load"; argv[1] = (char *)startupfile; argv[2] = NULL; argc = 2; run_load(argc, argv); runStartup = 0; } else printf("Can't open %s\n", startupfile); return; } } void sig_clean(int sig) { int i; for (i = 0; i < num_pths; i++) close(vpc[i].fd); if (rls != NULL && histfile != NULL) savehistory(histfile, rls); } int run_quit(int argc, char **argv) { pid_t pid; if (daemon_port) { pid = getppid(); kill(pid, SIGUSR1); } sig_clean(0); printf("\n"); exit(0); } int run_disconnect(int argc, char **argv) { pid_t pid; if (daemon_port) { pid = getppid(); kill(pid, SIGQUIT); } else printf("NOT daemon mode\n"); return 0; } void clear_hist(void) { rls->hist_total = 0; } void welcome(void) { run_ver(0, NULL); printf("\nPress '?' to get help.\n"); return; } void usage() { run_ver(0, NULL); esc_prn("\r\nusage: vpcs [{UOPTIONS}] [{UFILENAME}]\r\n" "{HOPTIONS}:\r\n" " {H-h} print this help then exit\r\n" " {H-v} print version information then exit\r\n" "\r\n" " {H-R} disable relay function\r\n" " {H-i} {Unum} number of vpc instances to start (default is 9)\r\n" " {H-p} {Uport} run as a daemon listening on the tcp {Uport}\r\n" " {H-m} {Unum} start byte of ether address, default from 0\r\n" " [{H-r}] {UFILENAME} load and execute script file {HFILENAME}\r\n" "\r\n" " {H-e} tap mode, using /dev/tapx by default (linux only)\r\n" " [{H-u}] udp mode, default\r\n" "\r\nudp mode options:\r\n" " {H-s} {Uport} local udp base {Uport}, default from 20000\r\n" " {H-c} {Uport} remote udp base {Uport} (dynamips udp port), default from 30000\r\n" " {H-t} {Uip} remote host {UIP}, default 127.0.0.1\r\n" "\r\ntap mode options:\r\n" " {H-d} {Udevice} {Udevice} name, works only when -i is set to 1\r\n" "\r\nhypervisor mode option:\r\n" " {H-H} {Uport} run as the hypervisor listening on the tcp {Uport}\r\n" "\r\n" " If no {HFILENAME} specified, vpcs will read and execute the file named\r\n" " startup.vpc if it exists in the current directory.\r\n" "\r\n"); } /* end of file */ vpcs-0.8.3/src/vpcs.h000066400000000000000000000076561447703427300144410ustar00rootroot00000000000000/* * Copyright (c) 2007-2014, Paul Meng (mirnshi@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. **/ #ifndef _VPC_H_ #define _VPC_H_ #include "queue.h" #include "globle.h" #include "ip.h" #define MAX_LEN (128) typedef struct { u_char mac[6]; u_int ip; int timeout; } ipmac; typedef struct { u_int svr; u_char smac[6]; u_int timetick; u_int lease; u_int renew; u_int rebind; u_int ip; u_int netmask; u_int gw; u_int xid; u_int dns[2]; char domain[64]; } dhcp; typedef struct { int timeout; ip6 ip; int cidr; u_char mac[6]; } ip6mac; typedef struct { int timeout; ip6 ip; u_int32_t mtu; } ip6mtu; typedef struct { ip6 ip; /* local host ip6 */ int cidr; /* local host ip6 netmask */ int type; /* 1:eui-64 2:locallink */ #define IP6TYPE_NONE 0 #define IP6TYPE_EUI64 1 #define IP6TYPE_LOCALLINK 2 u_char gmac[6]; /* destination host mac */ ip6 dns[2]; /* local host ip6 */ } hipv6; typedef struct { int dynip; /* dynamic IP (dhcp) */ u_int ip; /* local host ip */ int cidr; /* local host ip netmask */ u_char mac[6]; /* local host mac */ u_int gw; /* default gateway ip */ u_char gmac[6]; /* destination host mac */ dhcp dhcp; u_int lease; /* dhcp lease time */ u_int dns[2]; /* dns server */ char domain[64]; /* search domain name */ int flags; #define IPF_FRAG 0x1 } hipv4; #define MAX_NAMES_LEN (12) #define MAX_SESSIONS 1000 #define POOL_SIZE 32 #define POOL_TIMEOUT 120 typedef struct { int id; /* pc id */ char xname[MAX_NAMES_LEN + 1]; /* pc name */ pthread_t outid; /* ip output pthread id */ pthread_t rpid; /* reader pthread id */ pthread_t wpid; /* writer pthread id */ int dmpflag; /* dump flag */ FILE *dmpfile; /* dump file pointer */ int bgjobflag; /* backgroun job flag */ int fd; /* device handle */ int rfd; /* client handle if in the udp mode */ int lport; /* local udp port */ int rport; /* remote udp port */ u_int rhost; /* remote host */ struct pq bgiq; /* background input queue */ struct pq bgoq; /* background output queue */ struct pq iq; /* queue */ struct pq oq; /* queue */ pthread_mutex_t locker; /* mutex */ sesscb mscb; /* opened by app */ sesscb sesscb[MAX_SESSIONS]; /* tcp session pool */ tcpcb6 tcpcb6[MAX_SESSIONS]; /* tcp6 session pool */ ipmac ipmac4[POOL_SIZE]; /* arp pool */ ip6mac ipmac6[POOL_SIZE]; /* neighbor pool */ ip6mtu ip6mtu[POOL_SIZE]; /* mtu6 record */ hipv4 ip4; int ip6auto; hipv6 ip6; hipv6 link6; int mtu; } pcs; struct echoctl { int enable; int fgcolor; int bgcolor; }; extern pcs vpc[MAX_NUM_PTHS]; #define delay_ms(s) usleep(s * 1000) void parse_cmd(char *cmdstr); #endif /* end of file */ vpcs-0.8.3/test/000077500000000000000000000000001447703427300134675ustar00rootroot00000000000000vpcs-0.8.3/test/aa000066400000000000000000000003631447703427300137750ustar00rootroot000000000000001 dhcp 2 ip auto 3 ip 192.168.11.2 192.168.11.1 24 ip 2001:11::2 4 ip 192.168.12.2 192.168.12.1 24 5 ip 192.168.3.5 24 6 ip 192.168.3.6 24 7 ip 192.168.4.7 24 8 ip 192.168.4.8 192.168.4.1 24 9 ip 192.168.4.9 192.168.4.1 24 4 vpcs-0.8.3/test/auto000066400000000000000000000052231447703427300143640ustar00rootroot00000000000000set echo on 1 dhcp -d -x -r sh ip 1 2 ip auto 3 ip 192.168.11.2 192.168.11.1 24 ip 2001:11::2 4 ip 192.168.12.2 /24 192.168.12.1 5 ip 192.168.3.5 255.255.255.0 192.168.3.254 6 ip 192.168.3.6 24 7 ip 192.168.4.7 24 8 ip 192.168.4.8 192.168.4.1 24 9 ip 192.168.3.9 192.168.3.1 24 set echo off slee 5 "Testing" 1 echo ping VPCS4: 192.168.12.2, all worked p 192.168.12.2 -1 -c 2 -i 1 p 192.168.12.2 -2 -c 2 -i 1 -l 128 p 192.168.12.2 -3 -c 2 p 192.168.12.2 -3 -f s -c 2 echo ------------------------------------ echo ping VPCS4 gateway: 192.168.12.1, all worked p 192.168.12.1 -3 -c 2 p 192.168.12.1 -3 -c 2 -p 23 p 192.168.12.1 -3 -f s -c 2 echo ------------------------------------ echo ping nonexist host p 192.168.12.13 -1 -c 2 p 192.168.12.13 -2 -c 2 p 192.168.12.13 -3 -c 2 p 192.168.111.111 -1 -c 2 p 192.168.111.111 -2 -c 2 p 192.168.111.111 -3 -c 2 p 0.0.0.0 -1 -c 2 p 255.255.255.255 -1 -c 2 echo ------------------------------------ echo ping Google DNS p 8.8.8.8 -c 2 p 8.8.8.8 -c 2 -2 -p 53 p 8.8.8.8 -c 2 -3 -p 80 p 8.8.8.8 -c 2 -3 -p 80 -f s echo ------------------------------------ echo ping Google.Com, icmp and tcp:80 set dump detail p www.google.com -c 2 p www.google.com -c 2 -3 -p 80 set dump off echo ------------------------------------ echo trace 192.168.12.2 t 192.168.12.2 8 t 192.168.12.2 -P 1 8 t 192.168.12.2 -P 6 -m 8 echo ------------------------------------ echo trace Google.Com t www.google.com -m 8 echo ------------------------------------ 5 echo test icmp redirect p 192.168.12.2 -c 2 echo ------------------------------------ echo ping in the same vlan p 192.168.3.254 -c 2 echo ------------------------------------ echo ping different vlan p 192.168.3.6 echo ------------------------------------ echo ************************************ echo *** test IPV6 *** 7 echo ping fe80::250:79ff:fe66:6807, worked set dump detail ping fe80::250:79ff:fe66:6807 -c 2 set d off echo ------------------------------------ 1 echo ping fe80::250:79ff:fe66:6801, not worked ping fe80::250:79ff:fe66:6801 echo ------------------------------------ echo -- ping from 2001:11::2 to 2001:11::1 router ---- 3 p 2001:11::1 -3 -c 2 p 2001:11::1 -3 -c 2 -p 23 p 2001:11::1 -3 -c 2 -p 23 -f s echo ------------------------------------ echo -- ping from 2001:11::2 to 2001:1::250:79ff:fe66:6801 ---- p 2001:1::250:79ff:fe66:6801 -1 -c 2 p 2001:1::250:79ff:fe66:6801 -2 -c 2 set dump detail p 2001:1::250:79ff:fe66:6801 -3 -c 2 -f s -P 80 set dump off echo ------------------------------------ echo -- tracerouter from PC3, 6801 can be reached, 6904 is not exist -- t 2001:1::250:79ff:fe66:6801 5 t 2001:1::250:79ff:fe66:6904 5 echo ------------------------------------ quit vpcs-0.8.3/test/b2b000066400000000000000000000003511447703427300140560ustar00rootroot00000000000000echo "TEST Back2Back" 1 ip 192.168.1.1 24 set rport 20001 2 ip 192.168.1.2 24 set rport 20000 echo ping from 192.168.1.2 to 192.168.1.1, should be ok ping 192.168.1.1 -c 1 ping 192.168.1.1 -c 1 -P 6 ping 192.168.1.1 -c 1 -P 17 quit vpcs-0.8.3/test/ex.bat000066400000000000000000000074261447703427300146040ustar00rootroot00000000000000REM REM PC: 192.168 , 2001:ip4(3)::ip4(4) REM Rt: 172.16, 2002:ip4(2:3)::ip4(4) REM 1.1 172.16 8.1 8.2 REM PC1 - f1/0 -* 1.1 1.2 2.2 2.1 *- f1/0 - PC8 REM vlan10 +-- R1 - f0/0:f0/0 - R0 - f0/1:f0/0 - R2 REM | 1.254 *- f1/1 - PC9 REM PC2 - f1/1 -* 9.1 9.2 REM vlan10 1.2 | REM | REM PC3 - f1/2 -* REM vlan11 2.1 | REM | REM PC4 - f1/3 -* REM vlan11 2.2 | REM | REM PC5 - f1/4 -* REM 3.2 REM REM --------------------------------------------------------------- mkdir r1 cd r1 start ..\dynamips -i R1 -T 2001 -P 3600 -t 3660 -X -r 160 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 ^ -p 0:NM-1FE-TX -p 1:NM-16ESW ..\c3660-jk9o3s-mz.124-15.T5.bin.unzip ^ -s 0:0:udp:7000:127.0.0.1:7001 ^ -s 1:0:udp:30000:127.0.0.1:20000 ^ -s 1:1:udp:30001:127.0.0.1:20001 ^ -s 1:2:udp:30002:127.0.0.1:20002 ^ -s 1:3:udp:30003:127.0.0.1:20003 ^ -s 1:4:udp:30004:127.0.0.1:20004 cd .. mkdir r2 cd r2 start ..\dynamips -i R2 -T 2002 -P 3600 -t 3660 -X -r 128 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 ^ -p 1:NM-4E ..\c3660-jk9o3s-mz.124-15.T5.bin.unzip ^ -s 0:0:udp:7003:127.0.0.1:7002 ^ -s 1:0:udp:30007:127.0.0.1:20007 ^ -s 1:1:udp:30008:127.0.0.1:20008 cd .. mkdir r0 cd r0 start ..\dynamips -i R0 -T 2000 -P 3600 -t 3660 -X -r 128 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 ^ ..\c3660-jk9o3s-mz.124-15.T5.bin.unzip ^ -s 0:0:udp:7001:127.0.0.1:7000 ^ -s 0:1:udp:7002:127.0.0.1:7003 cd .. exit -------------------------------------------------------- R0#sh conf hostname R0 ipv6 unicast-routing interface FastEthernet0/0 no shutdown ip address 172.16.1.2 255.255.255.0 full-duplex ipv6 address 2002:16:1::2/64 ipv6 enable ipv6 rip cisco enable interface FastEthernet0/1 no shutdown ip address 172.16.2.2 255.255.255.0 full-duplex ipv6 address 2002:16:2::2/64 ipv6 enable ipv6 rip cisco enable router rip version 2 network 172.16.0.0 no auto-summary ipv6 router rip cisco end ------------------------------------------------------ R1#sh conf hostname R1 ip dhcp pool global network 192.168.1.0 255.255.255.0 default-router 192.168.1.1 ipv6 unicast-routing ipv6 cef interface FastEthernet0/0 ip address 172.16.1.1 255.255.255.0 speed auto full-duplex ipv6 address 2002:16:1::1/64 ipv6 enable ipv6 rip cisco enable interface FastEthernet1/0 switchport access vlan 10 speed 100 interface FastEthernet1/1 switchport access vlan 10 interface FastEthernet1/2 switchport access vlan 11 interface FastEthernet1/3 switchport access vlan 11 interface FastEthernet1/4 no switchport ip address 192.168.3.1 255.255.255.0 ipv6 address 2001:3::1/64 ipv6 enable ipv6 rip cisco enable interface Vlan10 ip address 192.168.1.1 255.255.255.0 router rip version 2 network 172.16.0.0 network 192.168.1.0 network 192.168.2.0 network 192.168.3.0 no auto-summary ipv6 router rip cisco end ------------------------------------------------------ R2#sh conf hostname R2 ipv6 unicast-routing interface FastEthernet0/0 no shutdown ip address 172.16.2.2 255.255.255.0 full-duplex ipv6 address 2002:16:2::2/64 ipv6 enable ipv6 rip cisco enable interface Ethernet1/0 no shutdown ip address 192.168.8.1 255.255.255.0 full-duplex ipv6 address 2001:8::1/64 ipv6 enable ipv6 rip cisco enable interface Ethernet1/1 no shutdown ip address 192.168.9.1 255.255.255.0 full-duplex ipv6 address 2001:9::1/64 ipv6 enable ipv6 rip cisco enable router rip version 2 network 172.16.0.0 network 192.168.8.0 network 192.168.9.0 no auto-summary ipv6 router rip cisco endvpcs-0.8.3/test/ex.sh000066400000000000000000000072011447703427300144370ustar00rootroot00000000000000#!/bin/sh #----------------------------------------------------------------- # # PC: 192.168 , 2001:ip4(3)::ip4(4) # Rt: 172.16, 2002:ip4(2:3)::ip4(4) # # 1.1 172.16 8.1 8.2 # PC1 - f1/0 -* 1.1 1.2 2.2 2.1 *- f1/0 - PC8 # vlan10 +-- R1 - f0/0:f0/0 - R0 - f0/1:f0/0 - R2 # | 1.254 *- f1/1 - PC9 # PC2 - f1/1 -* 9.1 9.2 # vlan10 1.2 | # | # PC3 - f1/2 -* # vlan11 2.1 | # | # PC4 - f1/3 -* # vlan11 2.2 | # | # PC5 - f1/4 -* # 3.2 # #----------------------------------------------------------------- C=`pwd`/dynamips B=`pwd`/c3660-jk9o3s-mz.124-15.T5.bin.unzip mkdir -p r1 cd r1 $C -i R1 -T 2001 -P 3600 -t 3660 -X -r 160 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 \ -p 0:NM-1FE-TX -p 1:NM-16ESW $B \ -s 0:0:udp:7000:127.0.0.1:7001 \ -s 1:0:udp:30000:127.0.0.1:20000 \ -s 1:1:udp:30001:127.0.0.1:20001 \ -s 1:2:udp:30002:127.0.0.1:20002 \ -s 1:3:udp:30003:127.0.0.1:20003 \ -s 1:4:udp:30004:127.0.0.1:20004 cd .. mkdir -p r2 cd r2 $C -i R2 -T 2002 -P 3600 -t 3660 -X -r 128 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 \ -p 1:NM-4E $B \ -s 0:0:udp:7003:127.0.0.1:7002 \ -s 1:0:udp:30007:127.0.0.1:20007 \ -s 1:1:udp:30008:127.0.0.1:20008 cd .. mkdir -p r0 cd r0 start ..\dynamips -i R0 -T 2000 -P 3600 -t 3660 -X -r 128 -c 0x2102 --sparse-mem --idle-pc=0x607789b8 \ $B \ -s 0:0:udp:7001:127.0.0.1:7000 \ -s 0:1:udp:7002:127.0.0.1:7003 cd .. exit -------------------------------------------------------- R0 ------- conf t hostname R0 ipv6 unicast-routing interface FastEthernet0/0 no shutdown ip address 172.16.1.2 255.255.255.0 full-duplex ipv6 address 2002:16:1::2/64 ipv6 enable ipv6 rip cisco enable interface FastEthernet0/1 no shutdown ip address 172.16.2.2 255.255.255.0 full-duplex ipv6 address 2002:16:2::2/64 ipv6 enable ipv6 rip cisco enable router rip version 2 network 172.16.0.0 no auto-summary ipv6 router rip cisco end -------------------------------------------------------- R1 ------- conf t hostname R1 ip dhcp pool global network 192.168.1.0 255.255.255.0 default-router 192.168.1.1 ipv6 unicast-routing ipv6 cef interface FastEthernet0/0 ip address 172.16.1.1 255.255.255.0 speed auto full-duplex ipv6 address 2002:16:1::1/64 ipv6 enable ipv6 rip cisco enable interface FastEthernet1/0 switchport access vlan 10 speed 100 interface FastEthernet1/1 switchport access vlan 10 interface FastEthernet1/2 switchport access vlan 11 interface FastEthernet1/3 switchport access vlan 11 interface FastEthernet1/4 no switchport ip address 192.168.3.1 255.255.255.0 ipv6 address 2001:3::1/64 ipv6 enable ipv6 rip cisco enable interface Vlan10 ip address 192.168.1.1 255.255.255.0 router rip version 2 network 172.16.0.0 network 192.168.1.0 network 192.168.2.0 network 192.168.3.0 no auto-summary ipv6 router rip cisco end -------------------------------------------------------- R2 ------- conf t hostname R2 ipv6 unicast-routing interface FastEthernet0/0 no shutdown ip address 172.16.2.1 255.255.255.0 full-duplex ipv6 address 2002:16:2::1/64 ipv6 enable ipv6 rip cisco enable interface Ethernet1/0 no shutdown ip address 192.168.8.1 255.255.255.0 full-duplex ipv6 address 2001:8::1/64 ipv6 enable ipv6 rip cisco enable interface Ethernet1/1 no shutdown ip address 192.168.9.1 255.255.255.0 full-duplex ipv6 address 2001:9::1/64 ipv6 enable ipv6 rip cisco enable router rip version 2 network 172.16.0.0 network 192.168.8.0 network 192.168.9.0 no auto-summary ipv6 router rip cisco endvpcs-0.8.3/test/ex6.sh000077500000000000000000000072401447703427300145330ustar00rootroot00000000000000#!/bin/sh #----------------------------------------------------------------- # topology: # # 20000 30000 T2000 30002 20002 # PC1 ---- s0/0 -* ^ *- s0/0 - PC3 # | | | # | ^ | # T2001<-< R1 --- s1/0:s0/0 -- R0 --- s0/1:s1/0 --- R2 >-> T2002 # || 21000 21001 | 21002 21003 | # PC2 ---- s0/1 -/| | *- s0/1 - PC4 # 20001 30001 | *----*-----*------*-------* PC9 30003 20003 # | 30004 30005 30006 30007 41000 20008 # RealPC --------/ | | | | | | # 20004 20005 20006 20007 41003 30008 # PC5 PC6 PC7 PC8 | | # *-----* # | # R3 >-> T2003 #----------------------------------------------------------------- C=`pwd`/dynamips B=`pwd`/c3660-jk9o3s-mz.124-15.T5.bin.unzip B1=`pwd`/c2600-ik8s-mz.122-11.T.bin.unzip B2=`pwd`/c2600-i-mz.113-3a.T1.bin.unzip B3=`pwd`/c7200-adventerprisek9-mz.124-22.T.bin.unzip mkdir -p r61 cd r61 $C -i R1 -T 2001 -P 7200 -t npe-400 -X --sparse-mem -r 192 -c 0x2102 \ --idle-pc=0x60646da8 -p 0:C7200-IO-2FE -p 1:PA-2FE-TX \ -s 0:0:udp:30000:127.0.0.1:20000 \ -s 0:1:udp:30001:127.0.0.1:20001 \ -s 1:0:udp:21000:127.0.0.1:21001 \ -s 1:1:linux_eth:eth1 \ $B3 & cd - mkdir -p r62 cd r62 $C -i R2 -T 2002 -P 7200 -t npe-400 -X --sparse-mem -r 192 -c 0x2102 \ --idle-pc=0x60646da8 -p 0:C7200-IO-2FE -p 1:PA-2FE-TX \ -s 0:0:udp:30002:127.0.0.1:20002 \ -s 0:1:udp:30003:127.0.0.1:20003 \ -s 1:0:udp:21003:127.0.0.1:21002 \ $B3 & cd - mkdir -p r60 cd r60 $C -i R0 -T 2000 -P 3600 -t 3660 -X --sparse-mem -r 192 -c 0x2102 \ --idle-pc=0x607789b8 -p 0:NM-1FE-TX -p 1:NM-1FE-TX -p 2:NM-16ESW \ -s 0:0:udp:21001:127.0.0.1:21000 \ -s 1:0:udp:21002:127.0.0.1:21003 \ -s 2:0:udp:30004:127.0.0.1:20004 \ -s 2:1:udp:30005:127.0.0.1:20005 \ -s 2:2:udp:30006:127.0.0.1:20006 \ -s 2:3:udp:30007:127.0.0.1:20007 \ -s 2:4:udp:41000:127.0.0.1:41003 \ $B & cd .. mkdir -p r63 cd r63 $C -i R3 -T 2003 -P 3600 -t 3660 -X --sparse-mem -r 192 -c 0x2102 \ --idle-pc=0x607789b8 -p 0:NM-16ESW \ -s 0:0:udp:41003:127.0.0.1:41000 \ -s 0:1:udp:30008:127.0.0.1:20008 \ $B & cd .. exit ------------------------------------ R1 ------------------------------------ conf t interface FastEthernet0/0 ip address 172.16.1.2 255.255.255.0 no shut interface FastEthernet1/0 ip address 172.16.2.2 255.255.255.0 no shut exit router rip version 2 no auto-summary network 172.16.1.0 network 172.16.2.0 hostname R0 exit wr sh run ------------------------------------ R1 ------------------------------------ conf t interface FastEthernet0/0 ip address 192.168.1.1 255.255.255.0 no shut interface FastEthernet0/1 ip address 192.168.2.1 255.255.255.0 no shut interface FastEthernet1/0 ip address 172.16.1.1 255.255.255.0 no shut router rip version 2 no auto-summary network 172.16.1.0 network 192.168.1.0 network 192.168.2.0 hostname R1 exit wr sh run ------------------------------------ R2 ------------------------------------ conf t interface FastEthernet0/0 ip address 192.168.11.1 255.255.255.0 no shut interface FastEthernet0/1 ip address 192.168.12.1 255.255.255.0 no shut interface FastEthernet1/0 ip address 172.16.2.1 255.255.255.0 no shut router rip version 2 no auto-summary network 172.16.2.0 network 192.168.11.0 network 192.168.12.0 hostname R2 exit wr sh run vpcs-0.8.3/test/startup000066400000000000000000000021531447703427300151150ustar00rootroot00000000000000# The startup file of VPC ########################################### # pc1, pc2: ipv4, dhcp, vlan10 1 dhcp 2 dhcp ############################################ # same vlan without gateway # pc3, pc3: ipv4, vlan11 3 ip 192.168.2.1 ip 2001:2::1 64 4 ip 192.168.2.2 ip 2001:2::2 64 ############################################ # layer3 switch # pc5 5 ip 192.168.3.2 192.168.3.1 24 ip 2001:3::2 64 ############################################ # pc8, pc9: ipv6 & ipv6, no vlan 8 ip 192.168.8.2 192.168.8.1 24 ip 2001:8::2 64 9 ip 192.168.9.2 192.168.9.1 24 ip 2001:9::2 64 ############################################ # test connection # switch to PC1 3 ping 192.168.2.2 ping 2001:2::2 5 ping 2001:3::1 ping 2001:3::2 8 ping 2001:8::1 9 ping 2001:9::1 ping 2001:9::2 zzz 240 ping 2001:8::1 ping 2001:8::2 ping 2001:3::1 ping 2001:3::2 e 2001:3::2 e 2001:3::2 25 tcp t 2001:3::2 7 p 192.168.3.2 e 192.168.3.2 e 192.168.3.2 23 tcp t 192.168.3.2 7 p 192.168.1.2 e 192.168.1.2 e 192.168.1.2 23 tcp t 192.168.1.2 7 5 p 2001:8::2 e 2001:8::2 e 2001:8::2 22 tcp t 2001:8::2 7 vpcs-0.8.3/test/vpcs.hist000066400000000000000000000011021447703427300153250ustar00rootroot00000000000000ip clear clear ipv6 sh sh ip auto sh quit sh p 2001:12::C800:5DFF:FE0C:6 p FE80::C800:5DFF:FE0C:6 quit p FE80::C800:5DFF:FE0C:6 quit p FE80::C800:5DFF:FE0C:6 p FE80::C800:5DFF:FE0C:6 p FE80::C800:5DFF:FE0C:6 p FE80::C800:5DFF:FE0C:6 sh p FE80::C800:5DFF:FE0C:6 clear ? clear neightbor p FE80::C800:5DFF:FE0C:6 clear neightbor p FE80::C800:5DFF:FE0C:6 -c 1 xx p FE80::C800:5DFF:FE0C:6 -c 1 quit xx p FE80::C800:5DFF:FE0C:6 -c 1 sh quit quit quit quit quit quit quit sh quit quit sh 4 sh ip 2001:12::2050:79ff:fe66:6803 96 sh ip 2001:12::2050:79ff:fe66:6803 eui-64 sh qui sh quit