├── netunshare.c ├── .github └── workflows │ └── semgrep.yml ├── xinetd.netns.conf ├── vpnc-script-ptrtd ├── vpnc-script-win.js ├── vpnc-script-sshd ├── COPYING └── vpnc-script /netunshare.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef CLONE_NEWNET 8 | #error CLONE_NEWNET not defined 9 | #endif 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | if (argc < 1) { 14 | fprintf(stderr, "usage: %s []\n", 15 | basename(argv[0])); 16 | return 1; 17 | } 18 | argv++; 19 | 20 | if (unshare(CLONE_NEWNET) == -1) { 21 | perror("unshare"); 22 | return 1; 23 | } 24 | 25 | execv(argv[0], argv); 26 | /* Failed... */ 27 | perror("execve"); 28 | return 1; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | pull_request: {} 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - main 8 | - master 9 | schedule: 10 | - cron: '0 0 * * *' 11 | name: Semgrep config 12 | jobs: 13 | semgrep: 14 | name: semgrep/ci 15 | runs-on: ubuntu-20.04 16 | env: 17 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 18 | SEMGREP_URL: https://cloudflare.semgrep.dev 19 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 20 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 21 | container: 22 | image: returntocorp/semgrep 23 | steps: 24 | - uses: actions/checkout@v3 25 | - run: semgrep ci 26 | -------------------------------------------------------------------------------- /xinetd.netns.conf: -------------------------------------------------------------------------------- 1 | # 2 | # This is the master xinetd configuration file. Settings in the 3 | # default section will be inherited by all service configurations 4 | # unless explicitly overridden in the service configuration. See 5 | # xinetd.conf in the man pages for a more detailed explanation of 6 | # these attributes. 7 | 8 | defaults 9 | { 10 | # The next two items are intended to be a quick access place to 11 | # temporarily enable or disable services. 12 | # 13 | # enabled = 14 | # disabled = 15 | 16 | # Define general logging characteristics. 17 | log_type = SYSLOG daemon info 18 | log_on_failure = HOST 19 | log_on_success = PID HOST DURATION EXIT 20 | 21 | # Define access restriction defaults 22 | # 23 | # no_access = 24 | # only_from = 25 | # max_load = 0 26 | cps = 50 10 27 | instances = 50 28 | per_source = 10 29 | 30 | # Address and networking defaults 31 | # 32 | # bind = 33 | # mdns = yes 34 | v6only = no 35 | 36 | # setup environmental attributes 37 | # 38 | # passenv = 39 | groups = yes 40 | umask = 002 41 | 42 | # Generally, banners are not used. This sets up their global defaults 43 | # 44 | # banner = 45 | # banner_fail = 46 | # banner_success = 47 | } 48 | 49 | service smtp 50 | { 51 | disable = no 52 | port = 25 53 | socket_type = stream 54 | protocol = tcp 55 | wait = no 56 | user = root 57 | server = /usr/bin/nc 58 | server_args = smtp.company.internal 25 59 | # bind = fec0::1 60 | } 61 | 62 | service imaps 63 | { 64 | disable = no 65 | port = 993 66 | socket_type = stream 67 | protocol = tcp 68 | wait = no 69 | user = root 70 | server = /usr/bin/nc 71 | server_args = imap.company.internal 993 72 | # bind = fec0::1 73 | } 74 | 75 | -------------------------------------------------------------------------------- /vpnc-script-ptrtd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # © 2009 David Woodhouse 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | # 19 | ################ 20 | # 21 | # This is a replacement for the standard vpnc-script for use with vpnc 22 | # and openconnect. It sets up VPN routing which doesn't screw over the 23 | # _normal_ routing of the box. 24 | 25 | # It sets up a new network namespace for the VPN to use, and it runs 26 | # pTRTd (http://www.litech.org/ptrtd/) in that namespace. Connections 27 | # to the VPN are actually made as IPv6 connections, and pTRTd handles 28 | # converting them to Legacy IP and forwarding them. 29 | 30 | # The full range of Legacy IP addresses on the VPN is available to the 31 | # host through a tiny corner of the IPv6 address space; for this purpose 32 | # we use fec0:0:0:ffff:0:0:xxyy:zzww to represent the address xx.yy.zz.ww 33 | # on the VPN. 34 | 35 | # TODO: Either use totd (ftp://ftp.pasta.cs.uit.no/pub/Vermicelli/) or 36 | # preferably extend dnsmasq to handle DNS for us. We want the following: 37 | # - A queries for non-existent VPN hosts return NXDOMAIN (no munging) 38 | # - A queries for _extant_ VPN hosts return NOERROR instead of the result. 39 | # - AAAA queries return the A result, converted to the above IPv6 space. 40 | # - PTR queries within the IPv6 space converted appropriately. 41 | 42 | connect_parent() 43 | { 44 | # XXX: How do we work out what it _really_ is? 45 | export PARENT_NETNS=$$ 46 | 47 | # XXX: Make sure it doesn't exist in this namespace already 48 | export RETURNDEV=x$TUNDEV 49 | 50 | ./netunshare $0 $@ & 51 | CHILDPID=$! 52 | 53 | # XXX: If we do this too soon (before the unshare), we're just 54 | # giving it to our _own_ netns. which achieves nothing. 55 | # So give it away until we _can't_ give it away any more. 56 | while /sbin/ip link set $TUNDEV netns $CHILDPID 2>/dev/null; do 57 | sleep 0.1 58 | done 59 | 60 | # Wait for the ptrtd tundev to appear in this namespace 61 | while ! ip link show $RETURNDEV >/dev/null 2>&1 ; do 62 | sleep 1 63 | done 64 | /sbin/ip link set $RETURNDEV up 65 | /sbin/ip addr add fe80::1 dev $RETURNDEV 66 | /sbin/ip route add fec0:0:0:ffff::/64 dev $RETURNDEV 67 | 68 | # XXX: Local hack -- my company's VPN server returns 69 | # "foo.company.com" instead of just "company.com". 70 | CISCO_DEF_DOMAIN=`echo $CISCO_DEF_DOMAIN | cut -f2- -d.` 71 | 72 | # Work out the IPv6 address of the nameservers... 73 | IPV6NS= 74 | for NS in $INTERNAL_IP4_DNS; do 75 | A=`echo $NS | cut -f1 -d.` 76 | B=`echo $NS | cut -f2 -d.` 77 | C=`echo $NS | cut -f3 -d.` 78 | D=`echo $NS | cut -f4 -d.` 79 | THISNS=`printf fec0:0:0:ffff:0:0:%02x%02x:%02x%02x $A $B $C $D` 80 | IPV6NS="$THISNS $IPV6NS" 81 | DNSMASQ_CMDLINE="-S /$CISCO_DEF_DOMAIN/$IPV6NS $DNSMASQ_CMDLINE" 82 | done 83 | echo IPv6 DNS: $IPV6NS 84 | 85 | # XXX: Add totd-like capability to dnsmasq 86 | dnsmasq $DNSMASQ_CMDLINE 87 | } 88 | 89 | connect() 90 | { 91 | if [ -z "$PARENT_NETNS" ]; then 92 | connect_parent 93 | exit 0 94 | fi 95 | 96 | # Wait for the tundev to appear in this namespace 97 | while ! ip link show $TUNDEV >/dev/null 2>&1 ; do 98 | sleep 0.1 99 | done 100 | 101 | # Set up Legacy IP in the new namespace 102 | /sbin/ip link set lo up 103 | /sbin/ip link set $TUNDEV up 104 | /sbin/ip -4 addr add $INTERNAL_IP4_ADDRESS dev $TUNDEV 105 | /sbin/ip -4 route add default dev $TUNDEV 106 | if [ "$INTERNAL_IP4_MTU" != "" ]; then 107 | /sbin/ip link set $TUNDEV mtu $INTERNAL_IP4_MTU 108 | fi 109 | 110 | # ifconfig 111 | # route 112 | 113 | # For debugging, really. Lets you ssh into the netns with 114 | # ssh fec0:0:0:ffff:0:0:7f00:1 115 | /usr/sbin/sshd -D & 116 | SSHD_PID=$! 117 | 118 | # Start ptrtd 119 | ptrtd -i tun:$RETURNDEV -d >/dev/null 2>&1 & 120 | PTRTD_PID=$! 121 | 122 | # Wait for the ptrtd to make its device 123 | while ! ip link show $TUNDEV >/dev/null 2>&1 ; do 124 | sleep 0.1 125 | done 126 | 127 | # Now give the ptrtd device back to the parent 128 | ip link set $RETURNDEV down 129 | /sbin/ip link set $RETURNDEV netns $PARENT_NETNS 130 | 131 | #Hm, this doesn't work because the tundev doesn't go away when it should 132 | #while ip link show $TUNDEV 2> /dev/null ; do 133 | # sleep 1 134 | #done 135 | 136 | # Wait for ptrtd to die (which it will when disconnect() kills its tun) 137 | wait $PTRTD_PID 138 | 139 | kill -TERM $SSHD_PID 140 | 141 | # Wait a while to avoid tun BUG() if we quit and the netns goes away 142 | # before vpnc/openconnect closes its tun fd. 143 | sleep 1 144 | } 145 | 146 | disconnect() 147 | { 148 | RETURNDEV=x$TUNDEV 149 | 150 | # This will kill ptrtd inside the netns, leaving the script to clean up 151 | ip link del $RETURNDEV 152 | 153 | # XXX: Undo the dnsmasq stuff. 154 | killall dnsmasq 155 | # XXX: properly. 156 | } 157 | 158 | case $reason in 159 | connect) 160 | connect 161 | ;; 162 | 163 | disconnect) 164 | disconnect 165 | ;; 166 | esac 167 | 168 | -------------------------------------------------------------------------------- /vpnc-script-win.js: -------------------------------------------------------------------------------- 1 | // vpnc-script-win.js 2 | // 3 | // Sets up the Network interface and the routes 4 | // needed by vpnc. 5 | 6 | // -------------------------------------------------------------- 7 | // Utilities 8 | // -------------------------------------------------------------- 9 | 10 | function echo(msg) 11 | { 12 | WScript.echo(msg); 13 | } 14 | 15 | function run(cmd) 16 | { 17 | return (ws.Exec(cmd).StdOut.ReadAll()); 18 | } 19 | 20 | function getDefaultGateway() 21 | { 22 | if (run("route print").match(/0\.0\.0\.0 *(0|128)\.0\.0\.0 *([0-9\.]*)/)) { 23 | return (RegExp.$2); 24 | } 25 | return (""); 26 | } 27 | 28 | function waitForInterface() { 29 | var if_route = new RegExp(env("INTERNAL_IP4_ADDRESS") + " *255.255.255.255"); 30 | for (var i = 0; i < 5; i++) { 31 | echo("Waiting for interface to come up..."); 32 | WScript.Sleep(2000); 33 | if (run("route print").match(if_route)) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | // -------------------------------------------------------------- 41 | // Script starts here 42 | // -------------------------------------------------------------- 43 | 44 | var internal_ip4_netmask = "255.255.255.0" 45 | 46 | var ws = WScript.CreateObject("WScript.Shell"); 47 | var env = ws.Environment("Process"); 48 | 49 | // How to add the default internal route 50 | // 0 - As interface gateway when setting properties 51 | // 1 - As a 0.0.0.0/0 route with a lower metric than the default route 52 | // 2 - As 0.0.0.0/1 + 128.0.0.0/1 routes (override the default route cleanly) 53 | var REDIRECT_GATEWAY_METHOD = 0; 54 | 55 | switch (env("reason")) { 56 | case "pre-init": 57 | break; 58 | case "connect": 59 | var gw = getDefaultGateway(); 60 | var address_array = env("INTERNAL_IP4_ADDRESS").split("."); 61 | var netmask_array = env("INTERNAL_IP4_NETMASK").split("."); 62 | // Calculate the first usable address in subnet 63 | var internal_gw_array = new Array( 64 | address_array[0] & netmask_array[0], 65 | address_array[1] & netmask_array[1], 66 | address_array[2] & netmask_array[2], 67 | (address_array[3] & netmask_array[3]) + 1 68 | ); 69 | var internal_gw = internal_gw_array.join("."); 70 | 71 | echo("VPN Gateway: " + env("VPNGATEWAY")); 72 | echo("Internal Address: " + env("INTERNAL_IP4_ADDRESS")); 73 | echo("Internal Netmask: " + env("INTERNAL_IP4_NETMASK")); 74 | echo("Internal Gateway: " + internal_gw); 75 | echo("Interface: \"" + env("TUNDEV") + "\""); 76 | 77 | if (env("INTERNAL_IP4_MTU")) { 78 | echo("MTU: " + env("INTERNAL_IP4_MTU")); 79 | run("netsh interface ipv4 set subinterface \"" + env("TUNDEV") + 80 | "\" mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); 81 | if (env("INTERNAL_IP6_ADDRESS")) { 82 | run("netsh interface ipv6 set subinterface \"" + env("TUNDEV") + 83 | "\" mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); 84 | } 85 | } 86 | 87 | echo("Configuring \"" + env("TUNDEV") + "\" interface for Legacy IP..."); 88 | 89 | if (!env("CISCO_SPLIT_INC") && REDIRECT_GATEWAY_METHOD != 2) { 90 | // Interface metric must be set to 1 in order to add a route with metric 1 since Windows Vista 91 | run("netsh interface ip set interface \"" + env("TUNDEV") + "\" metric=1"); 92 | } 93 | 94 | if (env("CISCO_SPLIT_INC") || REDIRECT_GATEWAY_METHOD > 0) { 95 | run("netsh interface ip set address \"" + env("TUNDEV") + "\" static " + 96 | env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK")); 97 | } else { 98 | // The default route will be added automatically 99 | run("netsh interface ip set address \"" + env("TUNDEV") + "\" static " + 100 | env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK") + " " + internal_gw + " 1"); 101 | } 102 | 103 | // Add direct route for the VPN gateway to avoid routing loops 104 | run("route add " + env("VPNGATEWAY") + 105 | " mask 255.255.255.255 " + gw); 106 | 107 | if (env("INTERNAL_IP4_NBNS")) { 108 | var wins = env("INTERNAL_IP4_NBNS").split(/ /); 109 | for (var i = 0; i < wins.length; i++) { 110 | run("netsh interface ip add wins \"" + 111 | env("TUNDEV") + "\" " + wins[i] 112 | + " index=" + (i+1)); 113 | } 114 | } 115 | 116 | if (env("INTERNAL_IP4_DNS")) { 117 | var dns = env("INTERNAL_IP4_DNS").split(/ /); 118 | for (var i = 0; i < dns.length; i++) { 119 | run("netsh interface ip add dns \"" + 120 | env("TUNDEV") + "\" " + dns[i] 121 | + " index=" + (i+1)); 122 | } 123 | } 124 | echo("done."); 125 | 126 | // Add internal network routes 127 | echo("Configuring Legacy IP networks:"); 128 | if (env("CISCO_SPLIT_INC")) { 129 | // Waiting for the interface to be configured before to add routes 130 | if (!waitForInterface()) { 131 | echo("Interface does not seem to be up."); 132 | } 133 | 134 | for (var i = 0 ; i < parseInt(env("CISCO_SPLIT_INC")); i++) { 135 | var network = env("CISCO_SPLIT_INC_" + i + "_ADDR"); 136 | var netmask = env("CISCO_SPLIT_INC_" + i + "_MASK"); 137 | var netmasklen = env("CISCO_SPLIT_INC_" + i + 138 | "_MASKLEN"); 139 | run("route add " + network + " mask " + netmask + 140 | " " + internal_gw); 141 | } 142 | } else if (REDIRECT_GATEWAY_METHOD > 0) { 143 | // Waiting for the interface to be configured before to add routes 144 | if (!waitForInterface()) { 145 | echo("Interface does not seem to be up."); 146 | } 147 | 148 | if (REDIRECT_GATEWAY_METHOD == 1) { 149 | run("route add 0.0.0.0 mask 0.0.0.0 " + internal_gw + " metric 1"); 150 | } else { 151 | run("route add 0.0.0.0 mask 128.0.0.0 " + internal_gw); 152 | run("route add 128.0.0.0 mask 128.0.0.0 " + internal_gw); 153 | } 154 | } 155 | echo("Route configuration done."); 156 | 157 | if (env("INTERNAL_IP6_ADDRESS")) { 158 | echo("Configuring \"" + env("TUNDEV") + "\" interface for IPv6..."); 159 | 160 | run("netsh interface ipv6 set address \"" + env("TUNDEV") + "\" " + 161 | env("INTERNAL_IP6_ADDRESS") + " store=active"); 162 | 163 | echo("done."); 164 | 165 | // Add internal network routes 166 | echo("Configuring IPv6 networks:"); 167 | if (env("INTERNAL_IP6_NETMASK") && !env("INTERNAL_IP6_NETMASK").match("/128$")) { 168 | run("netsh interface ipv6 add route " + env("INTERNAL_IP6_NETMASK") + 169 | " \"" + env("TUNDEV") + "\" fe80::8 store=active") 170 | } 171 | 172 | if (env("CISCO_IPV6_SPLIT_INC")) { 173 | for (var i = 0 ; i < parseInt(env("CISCO_IPV6_SPLIT_INC")); i++) { 174 | var network = env("CISCO_IPV6_SPLIT_INC_" + i + "_ADDR"); 175 | var netmasklen = env("CISCO_SPLIT_INC_" + i + 176 | "_MASKLEN"); 177 | run("netsh interface ipv6 add route " + network + "/" + 178 | netmasklen + " \"" + env("TUNDEV") + "\" fe80::8 store=active") 179 | } 180 | } else { 181 | echo("Setting default IPv6 route through VPN."); 182 | run("netsh interface ipv6 add route 2000::/3 \"" + env("TUNDEV") + 183 | "\" fe80::8 store=active"); 184 | } 185 | echo("IPv6 route configuration done."); 186 | } 187 | 188 | if (env("CISCO_BANNER")) { 189 | echo("--------------------------------------------------"); 190 | echo(env("CISCO_BANNER")); 191 | echo("--------------------------------------------------"); 192 | } 193 | break; 194 | case "disconnect": 195 | // Delete direct route for the VPN gateway to avoid 196 | run("route delete " + env("VPNGATEWAY") + " mask 255.255.255.255"); 197 | } 198 | 199 | -------------------------------------------------------------------------------- /vpnc-script-sshd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # © 2009 David Woodhouse 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | # 19 | ################ 20 | # 21 | # This is a replacement for the standard vpnc-script used with vpnc and 22 | # openconnect. It sets up VPN routing which doesn't screw over the 23 | # _normal_ routing of the box. 24 | # 25 | # It sets up a new network namespace for the VPN to use, and it runs 26 | # a Secure Shell dæmon inside that namespace, with full access to all 27 | # routes on the VPN. 28 | # 29 | # It links the 'real' network namespace of the computer to this new one 30 | # by an IPv6 site-local connection -- you can ssh into the 'VPN namespace' 31 | # by connecting to the host 'fec0::1'. 32 | # 33 | # You don't need any IPv6 configuration or connectivity for this; you 34 | # only need to have IPv6 support in your kernel. The use of IPv6 is purely 35 | # local to your machine. 36 | # 37 | # This gives you effectively the same service as if your company used a 38 | # SSH "bastion host" for access, instead of a VPN. It's just that the 39 | # bastion host is a special network namespace in your _own_ machine. 40 | # 41 | # Since your connection to it is _private_, though, you can run a few 42 | # services that a secure bastion host could not -- like a web proxy, 43 | # for example. You can also just forward certain points so that, for 44 | # example, connections to port 25 on your bastion host are automatically 45 | # forwarded inside the VPN to your internal mail server. There should 46 | # be a sample xinetd.conf with this script which shows how to do that 47 | # using 'netcat' started from xinetd. 48 | # 49 | # It probably helps if you think of the VPN namespace as if it was a 50 | # separate machine. From the network point of view, that's what it is. 51 | # It just happens to share the file system (and a lot of other stuff) 52 | # with your _real_ computer. 53 | # 54 | # You can configure various other services to use this for connections into 55 | # your VPN, as follows... 56 | # 57 | # SOCKS 58 | # 59 | # SSH has a built-in SOCKS server. If you run 'ssh -D 1080 fec0::1', SSH 60 | # will listen on port 1080 and will forward connections through the SSH 61 | # connection and give you full SOCKS access to the VPN. 62 | # 63 | # It might make sense to make this script automatically start a SSH 64 | # connection with SOCKS enabled, if you want that to be available. 65 | # 66 | # SSH 67 | # 68 | # The OpenSSH client is capable of connecting to a SSH server by running 69 | # and arbitrary command and using its stdin/stdout, instead of having to 70 | # make a direct TCP connection to the server. 71 | # 72 | # So you can configure it to SSH into the VPN 'namespace' and use the 73 | # 'netcat' command for certain connections. You can add something like 74 | # this to your ~/.ssh/config: 75 | # 76 | # Host *.example.internal 77 | # ProxyCommand ssh fec0::1 exec nc %h %p 78 | # 79 | # (This also works if your company has made the mistake of overloading the 80 | # public 'company.com' domain for internal purposes, instead of doing the 81 | # sensible thing and using a _separate_ domain.) 82 | # 83 | # MAIL 84 | # 85 | # Like SSH, most decent mail clients are able to run a command to connect 86 | # to their IMAP server instead of being limited to a direct TCP connection. 87 | # 88 | # Commands you might want to use could look like... 89 | # ssh $MAILSRV exec /usr/sbin/dovecot --exec-mail imap 90 | # ssh $MAILSRV exec /usr/sbin/wu-imapd 91 | # ssh fec0::1 openssl s_client -quiet -connect $MAILSRV:993 -crlf 2>/dev/null 92 | # 93 | # Where '$MAILSRV' is the name of your mail server, of course. 94 | # 95 | # Note that the first two assume that you've set up SSH as described above, 96 | # so that SSH connections to the mail server work transparently. For the 97 | # latter, you probably need to redirect stderr to /dev/null to avoid 98 | # spurious output from openssl configuring your mail client (openssl doesn't 99 | # seem to take the -quiet option very seriously). 100 | # 101 | # For mail clients which _cannot_ simply run an external command for their 102 | # connection, first file a bug and then see the 'PORT FORWARDING' section 103 | # below. 104 | # 105 | # WEB 106 | # 107 | # Firefox and most other browsers should understand a 'proxy autoconfig' 108 | # file and that can tell it to use SOCKS (see above) for certain domains. 109 | # A suitable PAC file might look like this: 110 | # 111 | # function FindProxyForURL(url, host) 112 | # { 113 | # if (dnsDomainIs(host, "company.com")) 114 | # return "SOCKS5 localhost:1080"; 115 | # 116 | # return "DIRECT"; 117 | # } 118 | # 119 | # PORT FORWARDING 120 | # 121 | # You can use SSH to forward certain ports, of course -- but there's another, 122 | # simpler option. 123 | # 124 | # The included example of xinetd configuration will accept connections on 125 | # port 25 and 993 of the host fec0::1, and will automatically forward them 126 | # using netcat to the appropriate hosts within your VPN. This can be extended 127 | # to forward other ports. 128 | # 129 | # OTHER SERVICES 130 | # 131 | # Most other services should also be available through SSH, through the 132 | # SOCKS proxy, or by port forwarding in some way. If all else fails, you 133 | # can just ssh into the vpn namespace (ssh fec0::1) and have a shell with 134 | # complete access. 135 | # 136 | # BREAKING OUT OF THE VPN 137 | # 138 | # If you ssh _into_ your machine from the VPN side, you'll get a shell in 139 | # the VPN namespace. To 'break out' from there, you may want to ssh to 140 | # fec0::2 which is the normal machine. 141 | # 142 | # CONTROLLING ACCESS TO THE VPN 143 | # 144 | # One serious flaw with the _traditional_ VPN setup is that it allows 145 | # _all_ processes and users on the machine to have free access to the 146 | # VPN, instead of only the user who is supposed to have access. The 147 | # approach implemented here allows you to fix that, by running the 148 | # SSHD in the VPN namespace with a separate configuration that allows 149 | # only certain users to connect to it. 150 | # 151 | # (Be aware that using port forwarding or using SSH to run a SOCKS proxy 152 | # will negate that benefit, of course) 153 | # 154 | # David Woodhouse 155 | # 2009-06-06 156 | 157 | IP=/sbin/ip 158 | SCRIPTNAME=`basename $0` 159 | NETNSNAME=$SCRIPTNAME 160 | 161 | # XINETDCONF=`dirname $0`/xinetd.netns.conf 162 | 163 | PS4=" \$\$+ " 164 | connect_parent() 165 | { 166 | export PARENT_NETNS=$$ 167 | 168 | $IP link set $TUNDEV down 169 | if ! $IP link set $TUNDEV netns $$; then 170 | echo "Setting network namespace for $TUNDEV failed" 171 | echo "Perhaps you don't have network namespace support in your kernel?" 172 | exit 1 173 | fi 174 | 175 | $IP netns delete $NETNSNAME >/dev/null 2>&1 176 | if ! $IP netns add $NETNSNAME; then 177 | echo "Creating network namespace $NETNSNAME failed" 178 | echo "Perhaps you don't have network namespace support in your kernel?" 179 | exit 1 180 | fi 181 | 182 | $IP link add dev $TUNDEV-vpnssh%d type veth 183 | # XXX: Assume vpnssh0 and vpnssh1; ip doesn't tell us! 184 | LOCALDEV=$TUNDEV-vpnssh0 185 | export REMOTEDEV=$TUNDEV-vpnssh1 186 | 187 | $IP netns exec $NETNSNAME $0 $@ & 188 | CHILDPID=$! 189 | 190 | # XXX: If we do this too soon (before the unshare), we're just 191 | # giving it to our _own_ netns. which achieves nothing. 192 | # So give it away until we _can't_ give it away any more. 193 | while $IP link set $REMOTEDEV netns $CHILDPID 2>/dev/null; do 194 | sleep 0.1 195 | done 196 | 197 | # Give away the real VPN tun device too 198 | $IP link set $TUNDEV netns $CHILDPID 199 | 200 | $IP link set $LOCALDEV up 201 | $IP addr add fec0::2/64 dev $LOCALDEV 202 | 203 | echo "VPN now accessible through 'ssh fec0::1'" 204 | if ! grep -q 127.0.0.1 /etc/resolv.conf; then 205 | echo "WARNING: Your host needs to be running a local dnsmasq or named" 206 | echo "WARNING: and /etc/resolv.conf needs to point to 127.0.0.1" 207 | # XXX: We could probably fix that for ourselves... 208 | fi 209 | } 210 | 211 | connect() 212 | { 213 | if [ -z "$PARENT_NETNS" ]; then 214 | connect_parent 215 | exit 0 216 | fi 217 | 218 | # This is the child, which remains running in the background 219 | 220 | # Wait for the tundev to appear in this namespace 221 | while ! ip link show $TUNDEV >/dev/null 2>&1 ; do 222 | sleep 0.1 223 | done 224 | 225 | # Set up Legacy IP in the new namespace 226 | $IP link set lo up 227 | $IP link set $TUNDEV up 228 | if [ -n "$INTERNAL_IP4_ADDRESS" ]; then 229 | $IP -4 addr add $INTERNAL_IP4_ADDRESS dev $TUNDEV 230 | $IP -4 route add default dev $TUNDEV 231 | fi 232 | if [ -n "$INTERNAL_IP6_ADDRESS" ]; then 233 | $IP -6 addr add $INTERNAL_IP6_ADDRESS dev $TUNDEV 234 | $IP -6 route add default dev $TUNDEV 235 | fi 236 | if [ "$INTERNAL_IP4_MTU" != "" ]; then 237 | $IP link set $TUNDEV mtu $INTERNAL_IP4_MTU 238 | fi 239 | 240 | # Set up the veth back to the real system 241 | $IP link set $REMOTEDEV up 242 | $IP -6 addr add fec0::1/64 dev $REMOTEDEV 243 | 244 | # Run dnsmasq to provide DNS service for this namespace. 245 | # The host needs to be running its own local nameserver/dnsmasq and 246 | # /etc/resolv.conf should be pointing to 127.0.0.1 already. 247 | DNSMASQ_ARGS="--port=53 -k -R" 248 | for NS in $INTERNAL_IP4_DNS; do 249 | DNSMASQ_ARGS="$DNSMASQ_ARGS -S $NS" 250 | done 251 | for NS in $INTERNAL_IP6_DNS; do 252 | DNSMASQ_ARGS="$DNSMASQ_ARGS -S $NS" 253 | done 254 | /usr/sbin/dnsmasq $DNSMASQ_ARGS & 255 | DNSMASQ_PID=$! 256 | 257 | # Set up sshd 258 | /usr/sbin/sshd -D & 259 | SSHD_PID=$! 260 | 261 | XINETD_PID= 262 | if [ "$XINETDCONF" != "" ] && [ -r "$XINETDCONF" ]; then 263 | /usr/sbin/xinetd -dontfork -f $XINETDCONF & 264 | XINETD_PID=$! 265 | fi 266 | 267 | # Wait for the veth link to be closed... 268 | while ip link show $REMOTEDEV >/dev/null 2>&1 ; do 269 | sleep 1 270 | done 271 | 272 | kill -TERM $DNSMASQ_PID 273 | kill -TERM $SSHD_PID 274 | if [ "$XINETD_PID" != "" ]; then 275 | kill -TERM $XINETD_PID 276 | fi 277 | # Wait a while to avoid tun BUG() if we quit and the netns goes away 278 | # before vpnc/openconnect closes its tun fd. 279 | sleep 1 280 | } 281 | 282 | disconnect() 283 | { 284 | # Kill our end of the veth link, leaving the child script to clean up 285 | $IP link del $TUNDEV-vpnssh0 286 | 287 | while ! $IP netns delete $NETNSNAME >/dev/null 2>&1 ; do 288 | sleep 0.1 289 | done 290 | } 291 | 292 | case $reason in 293 | connect) 294 | connect 295 | ;; 296 | 297 | disconnect) 298 | disconnect 299 | ;; 300 | esac 301 | 302 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /vpnc-script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Originally part of vpnc source code: 4 | # © 2005-2012 Maurice Massar, Jörg Mayer, Antonio Borneo et al. 5 | # © 2009-2012 David Woodhouse 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | # 21 | ################ 22 | # 23 | # List of parameters passed through environment 24 | #* reason -- why this script was called, one of: pre-init connect disconnect reconnect 25 | #* VPNGATEWAY -- vpn gateway address (always present) 26 | #* TUNDEV -- tunnel device (always present) 27 | #* INTERNAL_IP4_ADDRESS -- address (always present) 28 | #* INTERNAL_IP4_MTU -- mtu (often unset) 29 | #* INTERNAL_IP4_NETMASK -- netmask (often unset) 30 | #* INTERNAL_IP4_NETMASKLEN -- netmask length (often unset) 31 | #* INTERNAL_IP4_NETADDR -- address of network (only present if netmask is set) 32 | #* INTERNAL_IP4_DNS -- list of dns servers 33 | #* INTERNAL_IP4_NBNS -- list of wins servers 34 | #* INTERNAL_IP6_ADDRESS -- IPv6 address 35 | #* INTERNAL_IP6_NETMASK -- IPv6 netmask 36 | #* INTERNAL_IP6_DNS -- IPv6 list of dns servers 37 | #* CISCO_DEF_DOMAIN -- default domain name 38 | #* CISCO_BANNER -- banner from server 39 | #* CISCO_SPLIT_INC -- number of networks in split-network-list 40 | #* CISCO_SPLIT_INC_%d_ADDR -- network address 41 | #* CISCO_SPLIT_INC_%d_MASK -- subnet mask (for example: 255.255.255.0) 42 | #* CISCO_SPLIT_INC_%d_MASKLEN -- subnet masklen (for example: 24) 43 | #* CISCO_SPLIT_INC_%d_PROTOCOL -- protocol (often just 0) 44 | #* CISCO_SPLIT_INC_%d_SPORT -- source port (often just 0) 45 | #* CISCO_SPLIT_INC_%d_DPORT -- destination port (often just 0) 46 | #* CISCO_IPV6_SPLIT_INC -- number of networks in IPv6 split-network-list 47 | #* CISCO_IPV6_SPLIT_INC_%d_ADDR -- IPv6 network address 48 | #* CISCO_IPV6_SPLIT_INC_$%d_MASKLEN -- IPv6 subnet masklen 49 | 50 | # FIXMEs: 51 | 52 | # Section A: route handling 53 | 54 | # 1) The 3 values CISCO_SPLIT_INC_%d_PROTOCOL/SPORT/DPORT are currently being ignored 55 | # In order to use them, we'll probably need os specific solutions 56 | # * Linux: iptables -t mangle -I PREROUTING -j ROUTE --oif $TUNDEV 57 | # This would be an *alternative* to changing the routes (and thus 2) and 3) 58 | # shouldn't be relevant at all) 59 | # 2) There are two different functions to set routes: generic routes and the 60 | # default route. Why isn't the defaultroute handled via the generic route case? 61 | # 3) In the split tunnel case, all routes but the default route might get replaced 62 | # without getting restored later. We should explicitely check and save them just 63 | # like the defaultroute 64 | # 4) Replies to a dhcp-server should never be sent into the tunnel 65 | 66 | # Section B: Split DNS handling 67 | 68 | # 1) Maybe dnsmasq can do something like that 69 | # 2) Parse dns packets going out via tunnel and redirect them to original dns-server 70 | 71 | #env | sort 72 | #set -x 73 | 74 | # =========== script (variable) setup ==================================== 75 | 76 | PATH=/sbin:/usr/sbin:$PATH 77 | 78 | OS="`uname -s`" 79 | 80 | HOOKS_DIR=/etc/vpnc 81 | DEFAULT_ROUTE_FILE=/var/run/vpnc/defaultroute 82 | RESOLV_CONF_BACKUP=/var/run/vpnc/resolv.conf-backup 83 | SCRIPTNAME=`basename $0` 84 | 85 | # some systems, eg. Darwin & FreeBSD, prune /var/run on boot 86 | if [ ! -d "/var/run/vpnc" ]; then 87 | mkdir -p /var/run/vpnc 88 | [ -x /sbin/restorecon ] && /sbin/restorecon /var/run/vpnc 89 | fi 90 | 91 | # stupid SunOS: no blubber in /usr/local/bin ... (on stdout) 92 | IPROUTE="`which ip 2> /dev/null | grep '^/'`" 93 | 94 | if ifconfig --help 2>&1 | grep BusyBox > /dev/null; then 95 | ifconfig_syntax_inet="" 96 | else 97 | ifconfig_syntax_inet="inet" 98 | fi 99 | 100 | if [ "$OS" = "Linux" ]; then 101 | ifconfig_syntax_ptp="pointopoint" 102 | route_syntax_gw="gw" 103 | route_syntax_del="del" 104 | route_syntax_netmask="netmask" 105 | else 106 | ifconfig_syntax_ptp="" 107 | route_syntax_gw="" 108 | route_syntax_del="delete" 109 | route_syntax_netmask="-netmask" 110 | fi 111 | if [ "$OS" = "SunOS" ]; then 112 | route_syntax_interface="-interface" 113 | ifconfig_syntax_ptpv6="$INTERNAL_IP6_ADDRESS" 114 | else 115 | route_syntax_interface="" 116 | ifconfig_syntax_ptpv6="" 117 | fi 118 | 119 | if [ -r /etc/openwrt_release ] && [ -n "$OPENWRT_INTERFACE" ]; then 120 | . /etc/functions.sh 121 | include /lib/network 122 | MODIFYRESOLVCONF=modify_resolvconf_openwrt 123 | RESTORERESOLVCONF=restore_resolvconf_openwrt 124 | elif [ -x /sbin/resolvconf ]; then # Optional tool on Debian, Ubuntu, Gentoo and FreeBSD 125 | MODIFYRESOLVCONF=modify_resolvconf_manager 126 | RESTORERESOLVCONF=restore_resolvconf_manager 127 | elif [ -x /sbin/netconfig ]; then # tool on Suse after 11.1 128 | MODIFYRESOLVCONF=modify_resolvconf_suse_netconfig 129 | RESTORERESOLVCONF=restore_resolvconf_suse_netconfig 130 | elif [ -x /sbin/modify_resolvconf ]; then # Mandatory tool on Suse earlier than 11.1 131 | MODIFYRESOLVCONF=modify_resolvconf_suse 132 | RESTORERESOLVCONF=restore_resolvconf_suse 133 | elif [ -x /usr/sbin/unbound-control ] && /usr/sbin/unbound-control status > /dev/null 2>&1; then 134 | MODIFYRESOLVCONF=modify_resolvconf_unbound 135 | RESTORERESOLVCONF=restore_resolvconf_unbound 136 | else # Generic for any OS 137 | MODIFYRESOLVCONF=modify_resolvconf_generic 138 | RESTORERESOLVCONF=restore_resolvconf_generic 139 | fi 140 | 141 | 142 | # =========== script hooks ================================================= 143 | 144 | run_hooks() { 145 | HOOK="$1" 146 | 147 | if [ -d ${HOOKS_DIR}/${HOOK}.d ]; then 148 | for script in ${HOOKS_DIR}/${HOOK}.d/* ; do 149 | [ -f $script ] && . $script 150 | done 151 | fi 152 | } 153 | 154 | # =========== tunnel interface handling ==================================== 155 | 156 | do_ifconfig() { 157 | if [ -n "$INTERNAL_IP4_MTU" ]; then 158 | MTU=$INTERNAL_IP4_MTU 159 | elif [ -n "$IPROUTE" ]; then 160 | MTUDEV=`$IPROUTE route get "$VPNGATEWAY" | sed -ne 's/^.*dev \([a-z0-9]*\).*$/\1/p'` 161 | MTU=`$IPROUTE link show "$MTUDEV" | sed -ne 's/^.*mtu \([[:digit:]]\+\).*$/\1/p'` 162 | if [ -n "$MTU" ]; then 163 | MTU=`expr $MTU - 88` 164 | fi 165 | fi 166 | 167 | if [ -z "$MTU" ]; then 168 | MTU=1412 169 | fi 170 | 171 | # Point to point interface require a netmask of 255.255.255.255 on some systems 172 | if [ -n "$IPROUTE" ]; then 173 | $IPROUTE link set dev "$TUNDEV" up mtu "$MTU" 174 | $IPROUTE addr add "$INTERNAL_IP4_ADDRESS/32" peer "$INTERNAL_IP4_ADDRESS" dev "$TUNDEV" 175 | else 176 | ifconfig "$TUNDEV" ${ifconfig_syntax_inet} "$INTERNAL_IP4_ADDRESS" $ifconfig_syntax_ptp "$INTERNAL_IP4_ADDRESS" netmask 255.255.255.255 mtu ${MTU} up 177 | fi 178 | 179 | if [ -n "$INTERNAL_IP4_NETMASK" ]; then 180 | set_network_route $INTERNAL_IP4_NETADDR $INTERNAL_IP4_NETMASK $INTERNAL_IP4_NETMASKLEN 181 | fi 182 | 183 | # If the netmask is provided, it contains the address _and_ netmask 184 | if [ -n "$INTERNAL_IP6_ADDRESS" ] && [ -z "$INTERNAL_IP6_NETMASK" ]; then 185 | INTERNAL_IP6_NETMASK="$INTERNAL_IP6_ADDRESS/128" 186 | fi 187 | if [ -n "$INTERNAL_IP6_NETMASK" ]; then 188 | if [ -n "$IPROUTE" ]; then 189 | $IPROUTE -6 addr add $INTERNAL_IP6_NETMASK dev $TUNDEV 190 | else 191 | # Unlike for Legacy IP, we don't specify the dest_address 192 | # here on *BSD. OpenBSD for one will refuse to accept 193 | # incoming packets to that address if we do. 194 | # OpenVPN does the same (gives dest_address for Legacy IP 195 | # but not for IPv6). 196 | # Only Solaris needs it; hence $ifconfig_syntax_ptpv6 197 | ifconfig "$TUNDEV" inet6 $INTERNAL_IP6_NETMASK $ifconfig_syntax_ptpv6 mtu $MTU up 198 | fi 199 | fi 200 | } 201 | 202 | destroy_tun_device() { 203 | case "$OS" in 204 | NetBSD|OpenBSD) # and probably others... 205 | ifconfig "$TUNDEV" destroy 206 | ;; 207 | FreeBSD) 208 | ifconfig "$TUNDEV" destroy > /dev/null 2>&1 & 209 | ;; 210 | esac 211 | } 212 | 213 | # =========== route handling ==================================== 214 | 215 | if [ -n "$IPROUTE" ]; then 216 | fix_ip_get_output () { 217 | sed -e 's/ /\n/g' | \ 218 | sed -ne '1p;/via/{N;p};/dev/{N;p};/src/{N;p};/mtu/{N;p}' 219 | } 220 | 221 | set_vpngateway_route() { 222 | $IPROUTE route add `$IPROUTE route get "$VPNGATEWAY" | fix_ip_get_output` 223 | $IPROUTE route flush cache 224 | } 225 | 226 | del_vpngateway_route() { 227 | $IPROUTE route $route_syntax_del "$VPNGATEWAY" 228 | $IPROUTE route flush cache 229 | } 230 | 231 | set_default_route() { 232 | $IPROUTE route | grep '^default' | fix_ip_get_output > "$DEFAULT_ROUTE_FILE" 233 | $IPROUTE route replace default dev "$TUNDEV" 234 | $IPROUTE route flush cache 235 | } 236 | 237 | set_network_route() { 238 | NETWORK="$1" 239 | NETMASK="$2" 240 | NETMASKLEN="$3" 241 | $IPROUTE route replace "$NETWORK/$NETMASKLEN" dev "$TUNDEV" 242 | $IPROUTE route flush cache 243 | } 244 | 245 | reset_default_route() { 246 | if [ -s "$DEFAULT_ROUTE_FILE" ]; then 247 | $IPROUTE route replace `cat "$DEFAULT_ROUTE_FILE"` 248 | $IPROUTE route flush cache 249 | rm -f -- "$DEFAULT_ROUTE_FILE" 250 | fi 251 | } 252 | 253 | del_network_route() { 254 | NETWORK="$1" 255 | NETMASK="$2" 256 | NETMASKLEN="$3" 257 | $IPROUTE route $route_syntax_del "$NETWORK/$NETMASKLEN" dev "$TUNDEV" 258 | $IPROUTE route flush cache 259 | } 260 | 261 | set_ipv6_default_route() { 262 | # We don't save/restore IPv6 default route; just add a higher-priority one. 263 | $IPROUTE -6 route add default dev "$TUNDEV" metric 1 264 | $IPROUTE -6 route flush cache 265 | } 266 | 267 | set_ipv6_network_route() { 268 | NETWORK="$1" 269 | NETMASKLEN="$2" 270 | $IPROUTE -6 route replace "$NETWORK/$NETMASKLEN" dev "$TUNDEV" 271 | $IPROUTE route flush cache 272 | } 273 | 274 | reset_ipv6_default_route() { 275 | $IPROUTE -6 route del default dev "$TUNDEV" 276 | $IPROUTE route flush cache 277 | } 278 | 279 | del_ipv6_network_route() { 280 | NETWORK="$1" 281 | NETMASKLEN="$2" 282 | $IPROUTE -6 route del "$NETWORK/$NETMASKLEN" dev "$TUNDEV" 283 | $IPROUTE -6 route flush cache 284 | } 285 | else # use route command 286 | get_default_gw() { 287 | # isn't -n supposed to give --numeric output? 288 | # apperently not... 289 | # Get rid of lines containing IPv6 addresses (':') 290 | netstat -r -n | awk '/:/ { next; } /^(default|0\.0\.0\.0)/ { print $2; }' 291 | } 292 | 293 | set_vpngateway_route() { 294 | route add -host "$VPNGATEWAY" $route_syntax_gw "`get_default_gw`" 295 | } 296 | 297 | del_vpngateway_route() { 298 | route $route_syntax_del -host "$VPNGATEWAY" $route_syntax_gw "`get_default_gw`" 299 | } 300 | 301 | set_default_route() { 302 | DEFAULTGW="`get_default_gw`" 303 | echo "$DEFAULTGW" > "$DEFAULT_ROUTE_FILE" 304 | route $route_syntax_del default $route_syntax_gw "$DEFAULTGW" 305 | route add default $route_syntax_gw "$INTERNAL_IP4_ADDRESS" $route_syntax_interface 306 | } 307 | 308 | set_network_route() { 309 | NETWORK="$1" 310 | NETMASK="$2" 311 | NETMASKLEN="$3" 312 | del_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN" 313 | route add -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$INTERNAL_IP4_ADDRESS" $route_syntax_interface 314 | } 315 | 316 | reset_default_route() { 317 | if [ -s "$DEFAULT_ROUTE_FILE" ]; then 318 | route $route_syntax_del default $route_syntax_gw "`get_default_gw`" $route_syntax_interface 319 | route add default $route_syntax_gw `cat "$DEFAULT_ROUTE_FILE"` 320 | rm -f -- "$DEFAULT_ROUTE_FILE" 321 | fi 322 | } 323 | 324 | del_network_route() { 325 | case "$OS" in 326 | Linux|NetBSD|OpenBSD|Darwin|SunOS) # and probably others... 327 | # routes are deleted automatically on device shutdown 328 | return 329 | ;; 330 | esac 331 | NETWORK="$1" 332 | NETMASK="$2" 333 | NETMASKLEN="$3" 334 | route $route_syntax_del -net "$NETWORK" $route_syntax_netmask "$NETMASK" $route_syntax_gw "$INTERNAL_IP4_ADDRESS" 335 | } 336 | 337 | set_ipv6_default_route() { 338 | route add -inet6 default "$INTERNAL_IP6_ADDRESS" $route_syntax_interface 339 | } 340 | 341 | set_ipv6_network_route() { 342 | NETWORK="$1" 343 | NETMASK="$2" 344 | route add -inet6 -net "$NETWORK/$NETMASK" "$INTERNAL_IP6_ADDRESS" $route_syntax_interface 345 | : 346 | } 347 | 348 | reset_ipv6_default_route() { 349 | route $route_syntax_del -inet6 default "$INTERNAL_IP6_ADDRESS" 350 | : 351 | } 352 | 353 | del_ipv6_network_route() { 354 | NETWORK="$1" 355 | NETMASK="$2" 356 | route $route_syntax_del -inet6 "$NETWORK/$NETMASK" "$INTERNAL_IP6_ADDRESS" 357 | : 358 | } 359 | 360 | fi 361 | 362 | # =========== resolv.conf handling ==================================== 363 | 364 | # =========== resolv.conf handling for any OS ========================= 365 | 366 | modify_resolvconf_generic() { 367 | grep '^#@VPNC_GENERATED@' /etc/resolv.conf > /dev/null 2>&1 || cp -- /etc/resolv.conf "$RESOLV_CONF_BACKUP" 368 | NEW_RESOLVCONF="#@VPNC_GENERATED@ -- this file is generated by vpnc 369 | # and will be overwritten by vpnc 370 | # as long as the above mark is intact" 371 | 372 | # Remember the original value of CISCO_DEF_DOMAIN we need it later 373 | CISCO_DEF_DOMAIN_ORIG="$CISCO_DEF_DOMAIN" 374 | # Don't step on INTERNAL_IP4_DNS value, use a temporary variable 375 | INTERNAL_IP4_DNS_TEMP="$INTERNAL_IP4_DNS" 376 | exec 6< "$RESOLV_CONF_BACKUP" 377 | while read LINE <&6 ; do 378 | case "$LINE" in 379 | nameserver*) 380 | if [ -n "$INTERNAL_IP4_DNS_TEMP" ]; then 381 | read ONE_NAMESERVER INTERNAL_IP4_DNS_TEMP <<-EOF 382 | $INTERNAL_IP4_DNS_TEMP 383 | EOF 384 | LINE="nameserver $ONE_NAMESERVER" 385 | else 386 | LINE="" 387 | fi 388 | ;; 389 | search*) 390 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 391 | LINE="$LINE $CISCO_DEF_DOMAIN" 392 | CISCO_DEF_DOMAIN="" 393 | fi 394 | ;; 395 | domain*) 396 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 397 | LINE="domain $CISCO_DEF_DOMAIN" 398 | CISCO_DEF_DOMAIN="" 399 | fi 400 | ;; 401 | esac 402 | NEW_RESOLVCONF="$NEW_RESOLVCONF 403 | $LINE" 404 | done 405 | exec 6<&- 406 | 407 | for i in $INTERNAL_IP4_DNS_TEMP ; do 408 | NEW_RESOLVCONF="$NEW_RESOLVCONF 409 | nameserver $i" 410 | done 411 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 412 | NEW_RESOLVCONF="$NEW_RESOLVCONF 413 | search $CISCO_DEF_DOMAIN" 414 | fi 415 | echo "$NEW_RESOLVCONF" > /etc/resolv.conf 416 | 417 | if [ "$OS" = "Darwin" ]; then 418 | case "`uname -r`" in 419 | # Skip for pre-10.4 systems 420 | 4.*|5.*|6.*|7.*) 421 | ;; 422 | # 10.4 and later require use of scutil for DNS to work properly 423 | *) 424 | OVERRIDE_PRIMARY="" 425 | if [ -n "$CISCO_SPLIT_INC" ]; then 426 | if [ $CISCO_SPLIT_INC -lt 1 ]; then 427 | # Must override for correct default route 428 | # Cannot use multiple DNS matching in this case 429 | OVERRIDE_PRIMARY='d.add OverridePrimary # 1' 430 | fi 431 | # Overriding the default gateway breaks split routing 432 | OVERRIDE_GATEWAY="" 433 | # Not overriding the default gateway breaks usage of 434 | # INTERNAL_IP4_DNS. Prepend INTERNAL_IP4_DNS to list 435 | # of used DNS servers 436 | SERVICE=`echo "show State:/Network/Global/IPv4" | scutil | grep -oE '[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}'` 437 | SERVICE_DNS=`echo "show State:/Network/Service/$SERVICE/DNS" | scutil | grep -oE '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | xargs` 438 | if [ X"$SERVICE_DNS" != X"$INTERNAL_IP4_DNS" ]; then 439 | scutil >/dev/null 2>&1 <<-EOF 440 | open 441 | get State:/Network/Service/$SERVICE/DNS 442 | d.add ServerAddresses * $INTERNAL_IP4_DNS $SERVICE_DNS 443 | set State:/Network/Service/$SERVICE/DNS 444 | close 445 | EOF 446 | fi 447 | else 448 | # No split routing. Override default gateway 449 | OVERRIDE_GATEWAY="d.add Router $INTERNAL_IP4_ADDRESS" 450 | fi 451 | # Uncomment the following if/fi pair to use multiple 452 | # DNS matching when available. When multiple DNS matching 453 | # is present, anything reading the /etc/resolv.conf file 454 | # directly will probably not work as intended. 455 | #if [ -z "$CISCO_DEF_DOMAIN_ORIG" ]; then 456 | # Cannot use multiple DNS matching without a domain 457 | OVERRIDE_PRIMARY='d.add OverridePrimary # 1' 458 | #fi 459 | scutil >/dev/null 2>&1 <<-EOF 460 | open 461 | d.init 462 | d.add ServerAddresses * $INTERNAL_IP4_DNS 463 | set State:/Network/Service/$TUNDEV/DNS 464 | d.init 465 | $OVERRIDE_GATEWAY 466 | d.add Addresses * $INTERNAL_IP4_ADDRESS 467 | d.add SubnetMasks * 255.255.255.255 468 | d.add InterfaceName $TUNDEV 469 | $OVERRIDE_PRIMARY 470 | set State:/Network/Service/$TUNDEV/IPv4 471 | close 472 | EOF 473 | if [ -n "$CISCO_DEF_DOMAIN_ORIG" ]; then 474 | scutil >/dev/null 2>&1 <<-EOF 475 | open 476 | get State:/Network/Service/$TUNDEV/DNS 477 | d.add DomainName $CISCO_DEF_DOMAIN_ORIG 478 | d.add SearchDomains * $CISCO_DEF_DOMAIN_ORIG 479 | d.add SupplementalMatchDomains * $CISCO_DEF_DOMAIN_ORIG 480 | set State:/Network/Service/$TUNDEV/DNS 481 | close 482 | EOF 483 | fi 484 | ;; 485 | esac 486 | fi 487 | } 488 | 489 | restore_resolvconf_generic() { 490 | if [ ! -f "$RESOLV_CONF_BACKUP" ]; then 491 | return 492 | fi 493 | grep '^#@VPNC_GENERATED@' /etc/resolv.conf > /dev/null 2>&1 && cat "$RESOLV_CONF_BACKUP" > /etc/resolv.conf 494 | rm -f -- "$RESOLV_CONF_BACKUP" 495 | 496 | if [ "$OS" = "Darwin" ]; then 497 | case "`uname -r`" in 498 | # Skip for pre-10.4 systems 499 | 4.*|5.*|6.*|7.*) 500 | ;; 501 | # 10.4 and later require use of scutil for DNS to work properly 502 | *) 503 | scutil >/dev/null 2>&1 <<-EOF 504 | open 505 | remove State:/Network/Service/$TUNDEV/IPv4 506 | remove State:/Network/Service/$TUNDEV/DNS 507 | close 508 | EOF 509 | # Split routing required prepending of INTERNAL_IP4_DNS 510 | # to list of used DNS servers 511 | if [ -n "$CISCO_SPLIT_INC" ]; then 512 | SERVICE=`echo "show State:/Network/Global/IPv4" | scutil | grep -oE '[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}'` 513 | SERVICE_DNS=`echo "show State:/Network/Service/$SERVICE/DNS" | scutil | grep -oE '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | xargs` 514 | if [ X"$SERVICE_DNS" != X"$INTERNAL_IP4_DNS" ]; then 515 | scutil >/dev/null 2>&1 <<-EOF 516 | open 517 | get State:/Network/Service/$SERVICE/DNS 518 | d.add ServerAddresses * ${SERVICE_DNS##$INTERNAL_IP4_DNS} 519 | set State:/Network/Service/$SERVICE/DNS 520 | close 521 | EOF 522 | fi 523 | fi 524 | ;; 525 | esac 526 | fi 527 | } 528 | # === resolv.conf handling via /sbin/netconfig (Suse 11.1) ===================== 529 | 530 | # Suse provides a script that modifies resolv.conf. Use it because it will 531 | # restart/reload all other services that care about it (e.g. lwresd). [unclear if this is still true, but probably --mlk] 532 | 533 | modify_resolvconf_suse_netconfig() 534 | { 535 | /sbin/netconfig modify -s vpnc -i "$TUNDEV" <<-EOF 536 | INTERFACE='$TUNDEV' 537 | DNSSERVERS='$INTERNAL_IP4_DNS' 538 | DNSDOMAIN='$CISCO_DEF_DOMAIN' 539 | EOF 540 | } 541 | # Restore resolv.conf to old contents on Suse 542 | restore_resolvconf_suse_netconfig() 543 | { 544 | /sbin/netconfig remove -s vpnc -i "$TUNDEV" 545 | } 546 | 547 | # === resolv.conf handling via /sbin/modify_resolvconf (Suse) ===================== 548 | 549 | # Suse provides a script that modifies resolv.conf. Use it because it will 550 | # restart/reload all other services that care about it (e.g. lwresd). 551 | 552 | modify_resolvconf_suse() 553 | { 554 | FULL_SCRIPTNAME=`readlink -f $0` 555 | RESOLV_OPTS='' 556 | test -n "$INTERNAL_IP4_DNS" && RESOLV_OPTS="-n \"$INTERNAL_IP4_DNS\"" 557 | test -n "$CISCO_DEF_DOMAIN" && RESOLV_OPTS="$RESOLV_OPTS -d $CISCO_DEF_DOMAIN" 558 | test -n "$RESOLV_OPTS" && eval /sbin/modify_resolvconf modify -s vpnc -p $SCRIPTNAME -f $FULL_SCRIPTNAME -e $TUNDEV $RESOLV_OPTS -t \"This file was created by $SCRIPTNAME\" 559 | } 560 | 561 | # Restore resolv.conf to old contents on Suse 562 | restore_resolvconf_suse() 563 | { 564 | FULL_SCRIPTNAME=`readlink -f $0` 565 | /sbin/modify_resolvconf restore -s vpnc -p $SCRIPTNAME -f $FULL_SCRIPTNAME -e $TUNDEV 566 | } 567 | 568 | # === resolv.conf handling via UCI (OpenWRT) ========= 569 | 570 | modify_resolvconf_openwrt() { 571 | add_dns $OPENWRT_INTERFACE $INTERNAL_IP4_DNS 572 | } 573 | 574 | restore_resolvconf_openwrt() { 575 | remove_dns $OPENWRT_INTERFACE 576 | } 577 | # === resolv.conf handling via /sbin/resolvconf (Debian, Ubuntu, Gentoo)) ========= 578 | 579 | modify_resolvconf_manager() { 580 | NEW_RESOLVCONF="" 581 | for i in $INTERNAL_IP4_DNS; do 582 | NEW_RESOLVCONF="$NEW_RESOLVCONF 583 | nameserver $i" 584 | done 585 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 586 | NEW_RESOLVCONF="$NEW_RESOLVCONF 587 | domain $CISCO_DEF_DOMAIN" 588 | fi 589 | echo "$NEW_RESOLVCONF" | /sbin/resolvconf -a $TUNDEV 590 | } 591 | 592 | restore_resolvconf_manager() { 593 | /sbin/resolvconf -d $TUNDEV 594 | } 595 | 596 | # === resolv.conf handling via unbound ========= 597 | 598 | modify_resolvconf_unbound() { 599 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 600 | /usr/sbin/unbound-control forward_add +i ${CISCO_DEF_DOMAIN} ${INTERNAL_IP4_DNS} 601 | /usr/sbin/unbound-control flush_requestlist 602 | /usr/sbin/unbound-control flush_zone ${CISCO_DEF_DOMAIN} 603 | fi 604 | } 605 | 606 | restore_resolvconf_unbound() { 607 | if [ -n "$CISCO_DEF_DOMAIN" ]; then 608 | /usr/sbin/unbound-control forward_remove +i ${CISCO_DEF_DOMAIN} 609 | /usr/sbin/unbound-control flush_zone ${CISCO_DEF_DOMAIN} 610 | /usr/sbin/unbound-control flush_requestlist 611 | fi 612 | } 613 | 614 | # ========= Toplevel state handling ======================================= 615 | 616 | kernel_is_2_6_or_above() { 617 | case `uname -r` in 618 | 1.*|2.[012345]*) 619 | return 1 620 | ;; 621 | *) 622 | return 0 623 | ;; 624 | esac 625 | } 626 | 627 | do_pre_init() { 628 | if [ "$OS" = "Linux" ]; then 629 | if (exec 6<> /dev/net/tun) > /dev/null 2>&1 ; then 630 | : 631 | else # can't open /dev/net/tun 632 | test -e /proc/sys/kernel/modprobe && `cat /proc/sys/kernel/modprobe` tun 2>/dev/null 633 | # fix for broken devfs in kernel 2.6.x 634 | if [ "`readlink /dev/net/tun`" = misc/net/tun \ 635 | -a ! -e /dev/net/misc/net/tun -a -e /dev/misc/net/tun ] ; then 636 | ln -sf /dev/misc/net/tun /dev/net/tun 637 | fi 638 | # make sure tun device exists 639 | if [ ! -e /dev/net/tun ]; then 640 | mkdir -p /dev/net 641 | mknod -m 0640 /dev/net/tun c 10 200 642 | [ -x /sbin/restorecon ] && /sbin/restorecon /dev/net/tun 643 | fi 644 | # workaround for a possible latency caused by udev, sleep max. 10s 645 | if kernel_is_2_6_or_above ; then 646 | for x in `seq 100` ; do 647 | (exec 6<> /dev/net/tun) > /dev/null 2>&1 && break; 648 | sleep 0.1 649 | done 650 | fi 651 | fi 652 | elif [ "$OS" = "FreeBSD" ]; then 653 | if ! kldstat -q -m if_tun > /dev/null; then 654 | kldload if_tun 655 | fi 656 | 657 | if ! ifconfig $TUNDEV > /dev/null; then 658 | ifconfig $TUNDEV create 659 | fi 660 | elif [ "$OS" = "GNU/kFreeBSD" ]; then 661 | if [ ! -e /dev/tun ]; then 662 | kldload if_tun 663 | fi 664 | elif [ "$OS" = "NetBSD" ]; then 665 | : 666 | elif [ "$OS" = "OpenBSD" ]; then 667 | if ! ifconfig $TUNDEV > /dev/null; then 668 | ifconfig $TUNDEV create 669 | fi 670 | : 671 | elif [ "$OS" = "SunOS" ]; then 672 | : 673 | elif [ "$OS" = "Darwin" ]; then 674 | : 675 | fi 676 | } 677 | 678 | do_connect() { 679 | if [ -n "$CISCO_BANNER" ]; then 680 | echo "Connect Banner:" 681 | echo "$CISCO_BANNER" | while read LINE ; do echo "|" "$LINE" ; done 682 | echo 683 | fi 684 | 685 | set_vpngateway_route 686 | do_ifconfig 687 | if [ -n "$CISCO_SPLIT_INC" ]; then 688 | i=0 689 | while [ $i -lt $CISCO_SPLIT_INC ] ; do 690 | eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}" 691 | eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}" 692 | eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}" 693 | if [ "$NETWORK" != "0.0.0.0" ]; then 694 | set_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN" 695 | else 696 | set_default_route 697 | fi 698 | i=`expr $i + 1` 699 | done 700 | for i in $INTERNAL_IP4_DNS ; do 701 | echo "$i" | grep : >/dev/null || \ 702 | set_network_route "$i" "255.255.255.255" "32" 703 | done 704 | elif [ -n "$INTERNAL_IP4_ADDRESS" ]; then 705 | set_default_route 706 | fi 707 | if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then 708 | i=0 709 | while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do 710 | eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}" 711 | eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}" 712 | if [ $NETMASKLEN -lt 128 ]; then 713 | set_ipv6_network_route "$NETWORK" "$NETMASKLEN" 714 | else 715 | set_ipv6_default_route 716 | fi 717 | i=`expr $i + 1` 718 | done 719 | for i in $INTERNAL_IP4_DNS ; do 720 | if echo "$i" | grep : >/dev/null; then 721 | set_ipv6_network_route "$i" "128" 722 | fi 723 | done 724 | elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then 725 | set_ipv6_default_route 726 | fi 727 | 728 | if [ -n "$INTERNAL_IP4_DNS" ]; then 729 | $MODIFYRESOLVCONF 730 | fi 731 | } 732 | 733 | do_disconnect() { 734 | if [ -n "$CISCO_SPLIT_INC" ]; then 735 | i=0 736 | while [ $i -lt $CISCO_SPLIT_INC ] ; do 737 | eval NETWORK="\${CISCO_SPLIT_INC_${i}_ADDR}" 738 | eval NETMASK="\${CISCO_SPLIT_INC_${i}_MASK}" 739 | eval NETMASKLEN="\${CISCO_SPLIT_INC_${i}_MASKLEN}" 740 | if [ "$NETWORK" != "0.0.0.0" ]; then 741 | # FIXME: This doesn't restore previously overwritten 742 | # routes. 743 | del_network_route "$NETWORK" "$NETMASK" "$NETMASKLEN" 744 | else 745 | reset_default_route 746 | fi 747 | i=`expr $i + 1` 748 | done 749 | for i in $INTERNAL_IP4_DNS ; do 750 | del_network_route "$i" "255.255.255.255" "32" 751 | done 752 | else 753 | reset_default_route 754 | fi 755 | if [ -n "$CISCO_IPV6_SPLIT_INC" ]; then 756 | i=0 757 | while [ $i -lt $CISCO_IPV6_SPLIT_INC ] ; do 758 | eval NETWORK="\${CISCO_IPV6_SPLIT_INC_${i}_ADDR}" 759 | eval NETMASKLEN="\${CISCO_IPV6_SPLIT_INC_${i}_MASKLEN}" 760 | if [ $NETMASKLEN -eq 0 ]; then 761 | reset_ipv6_default_route 762 | else 763 | del_ipv6_network_route "$NETWORK" "$NETMASKLEN" 764 | fi 765 | i=`expr $i + 1` 766 | done 767 | for i in $INTERNAL_IP6_DNS ; do 768 | del_ipv6_network_route "$i" "128" 769 | done 770 | elif [ -n "$INTERNAL_IP6_NETMASK" -o -n "$INTERNAL_IP6_ADDRESS" ]; then 771 | reset_ipv6_default_route 772 | fi 773 | 774 | del_vpngateway_route 775 | 776 | if [ -n "$INTERNAL_IP4_DNS" ]; then 777 | $RESTORERESOLVCONF 778 | fi 779 | 780 | 781 | if [ -n "$IPROUTE" ]; then 782 | if [ -n "$INTERNAL_IP4_ADDRESS" ]; then 783 | $IPROUTE addr del "$INTERNAL_IP4_ADDRESS/255.255.255.255" peer "$INTERNAL_IP4_ADDRESS" dev "$TUNDEV" 784 | fi 785 | # If the netmask is provided, it contains the address _and_ netmask 786 | if [ -n "$INTERNAL_IP6_ADDRESS" ] && [ -z "$INTERNAL_IP6_NETMASK" ]; then 787 | INTERNAL_IP6_NETMASK="$INTERNAL_IP6_ADDRESS/128" 788 | fi 789 | if [ -n "$INTERNAL_IP6_NETMASK" ]; then 790 | $IPROUTE -6 addr del $INTERNAL_IP6_NETMASK dev $TUNDEV 791 | fi 792 | else 793 | if [ -n "$INTERNAL_IP4_ADDRESS" ]; then 794 | ifconfig "$TUNDEV" 0.0.0.0 795 | fi 796 | if [ -n "$INTERNAL_IP6_ADDRESS" ] && [ -z "$INTERNAL_IP6_NETMASK" ]; then 797 | INTERNAL_IP6_NETMASK="$INTERNAL_IP6_ADDRESS/128" 798 | fi 799 | if [ -n "$INTERNAL_IP6_NETMASK" ]; then 800 | ifconfig "$TUNDEV" inet6 del $INTERNAL_IP6_NETMASK 801 | fi 802 | fi 803 | 804 | destroy_tun_device 805 | } 806 | 807 | #### Main 808 | 809 | if [ -z "$reason" ]; then 810 | echo "this script must be called from vpnc" 1>&2 811 | exit 1 812 | fi 813 | 814 | case "$reason" in 815 | pre-init) 816 | run_hooks pre-init 817 | do_pre_init 818 | ;; 819 | connect) 820 | run_hooks connect 821 | do_connect 822 | run_hooks post-connect 823 | ;; 824 | disconnect) 825 | run_hooks disconnect 826 | do_disconnect 827 | run_hooks post-disconnect 828 | ;; 829 | reconnect) 830 | run_hooks reconnect 831 | ;; 832 | *) 833 | echo "unknown reason '$reason'. Maybe vpnc-script is out of date" 1>&2 834 | exit 1 835 | ;; 836 | esac 837 | 838 | exit 0 839 | --------------------------------------------------------------------------------