├── .gitignore ├── .gitmodules ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── include ├── arch │ ├── cc.h │ └── perf.h ├── http │ ├── http.h │ └── http_server.h └── lwipopts.h └── src ├── dhcp_server.c ├── dhcp_server.h ├── forward_local.c ├── forward_local.h ├── forward_remote.c ├── forward_remote.h ├── http ├── evhttp_extra.c ├── evhttp_extra.h ├── http.c └── server.c ├── main.c ├── nat.c ├── nat.h ├── socks.c ├── socks.h ├── socks4.c ├── socks4.h ├── socks5.c └── socks5.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | tunsocks 4 | configure 5 | Makefile 6 | Makefile.in 7 | configure 8 | configure.in 9 | aclocal.m4 10 | autom4te.cache/ 11 | compile 12 | config.log 13 | config.status 14 | depcomp 15 | install-sh 16 | missing 17 | .deps/ 18 | .dirstamp 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lwip"] 2 | path = lwip 3 | url = git://git.sv.gnu.org/lwip.git 4 | [submodule "lwip-udhcpd"] 5 | path = lwip-udhcpd 6 | url = https://github.com/russdill/lwip-udhcpd.git 7 | [submodule "lwip-libevent"] 8 | path = lwip-libevent 9 | url = https://github.com/russdill/lwip-libevent.git 10 | [submodule "lwip-nat"] 11 | path = lwip-nat 12 | url = https://github.com/russdill/lwip-nat.git 13 | [submodule "eth_udp"] 14 | path = eth_udp 15 | url = https://github.com/russdill/eth_udp.git 16 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS=\ 2 | -I$(srcdir)/lwip/src/include \ 3 | -I$(srcdir)/lwip/src/include/ipv4 \ 4 | -I$(srcdir)/lwip/src/include/ipv6 \ 5 | -I$(srcdir)/lwip-libevent/include \ 6 | -I$(srcdir)/lwip-udhcpd \ 7 | -I$(srcdir)/lwip-nat/include \ 8 | -I$(srcdir)/include -Wall -Og -g 9 | 10 | tunsocks_LDADD = -ldl 11 | 12 | if HAVE_PCAP 13 | AM_CFLAGS += -DUSE_PCAP 14 | tunsocks_LDADD += $(PCAP_LIBS) 15 | endif 16 | 17 | tunsocks_SOURCES = \ 18 | lwip/src/api/err.c \ 19 | lwip/src/core/init.c \ 20 | lwip/src/core/def.c \ 21 | lwip/src/core/mem.c \ 22 | lwip/src/core/memp.c \ 23 | lwip/src/core/netif.c \ 24 | lwip/src/core/pbuf.c \ 25 | lwip/src/core/stats.c \ 26 | lwip/src/core/ip.c \ 27 | lwip/src/core/dns.c \ 28 | lwip/src/core/udp.c \ 29 | lwip/src/core/raw.c \ 30 | lwip/src/core/sys.c \ 31 | lwip/src/core/tcp.c \ 32 | lwip/src/core/tcp_in.c \ 33 | lwip/src/core/tcp_out.c \ 34 | lwip/src/core/inet_chksum.c \ 35 | lwip/src/core/ipv4/etharp.c \ 36 | lwip/src/core/ipv4/icmp.c \ 37 | lwip/src/core/ipv4/ip4.c \ 38 | lwip/src/core/ipv4/ip4_addr.c \ 39 | lwip/src/core/ipv4/ip4_frag.c \ 40 | lwip/src/netif/ethernet.c \ 41 | lwip-udhcpd/udhcp_packet.c \ 42 | lwip-udhcpd/udhcp_common.c \ 43 | lwip-udhcpd/dhcpd.c \ 44 | lwip-udhcpd/domain_codec.c \ 45 | lwip-libevent/netif/fdif.c \ 46 | lwip-libevent/netif/slirpif.c \ 47 | lwip-libevent/netif/slirpif_tcp.c \ 48 | lwip-libevent/netif/slirpif_udp.c \ 49 | lwip-libevent/netif/udptapif.c \ 50 | lwip-libevent/netif/tunif.c \ 51 | lwip-libevent/netif/vdeportif.c \ 52 | lwip-libevent/netif/vdeswitchif.c \ 53 | lwip-libevent/util/sockaddr.c \ 54 | lwip-libevent/util/lwipevbuf.c \ 55 | lwip-libevent/util/lwipevbuf_bev_join.c \ 56 | lwip-libevent/util/host.c \ 57 | lwip-libevent/util/pbuf_iovec.c \ 58 | lwip-libevent/util/nettest.c \ 59 | lwip-libevent/libevent.c \ 60 | lwip-nat/ip4_prerouting_hook.c \ 61 | lwip-nat/ip4_input_nat.c \ 62 | lwip-nat/nat_proto_tcp.c \ 63 | lwip-nat/nat_proto_udp.c \ 64 | lwip-nat/nat_proto_icmp4.c \ 65 | lwip-nat/nat_proto_ip4.c \ 66 | lwip-nat/nat.c \ 67 | src/socks4.c \ 68 | src/socks5.c \ 69 | src/socks.c \ 70 | src/forward_local.c \ 71 | src/forward_remote.c \ 72 | src/nat.c \ 73 | src/dhcp_server.c \ 74 | src/http/http.c \ 75 | src/http/server.c \ 76 | src/http/evhttp_extra.c \ 77 | src/main.c 78 | 79 | if HAVE_PCAP 80 | tunsocks_SOURCES += lwip-libevent/util/pcap.c 81 | endif 82 | 83 | bin_PROGRAMS = tunsocks 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tunsocks 2 | -------- 3 | 4 | tunsocks is a user-level SOCKS, HTTP, and port forwarding proxy for use with 5 | VPNs that typically interact with tun devices. Rather than passing bytes to and 6 | from the tun device, they can pass the data to and from this user-level 7 | program. tunsocks is implemented using lwIP. 8 | 9 | Additionally, tunsocks provides connection sharing via NAT. 10 | 11 | tunsocks has been tested with OpenConnect: 12 | 13 | http://www.infradead.org/openconnect/ 14 | 15 | Usage 16 | ----- 17 | 18 | usage: tunsocks 19 | 20 | -L [bind_address:]bind_port:host_address:host_port 21 | -D [bind_address:]bind_port SOCKS4a/5 proxy 22 | -H [bind_address:]bind_port HTTP proxy 23 | -P proxy_pac_file:bind_port HTTP server for proxy.pac 24 | -R bind_port:host_address:host_port 25 | -g Allow non-local clients (command line compatibility for ocproxy) 26 | -k keep alive interval (seconds) 27 | -m mtu (env INTERNAL_IP4_MTU) 28 | -s domain_search[,domain_search,...] (env CISCO_DEF_DOMAIN) 29 | -d dns,[dns,...] (env INTERNAL_IP4_DNS) 30 | -i ip address (env INTERNAL_IP4_ADDRESS) 31 | -n netmask 32 | -G gateway 33 | -S (Use slirp interface instead VPN, useful for testing) 34 | -l Add deLay (in ms) to inbound/outbound packets (useful for testing) 35 | -o DrOp probability ([0.0..1.0]) for inbound/outbound (useful for testing) 36 | -p pcap_file[:netif] (Default netif 'fd', VPN input) 37 | -u port (UDP listener port of TAP NAT with no length header, netif=ut) 38 | -U port (UDP listener port of TAP NAT with 2 byte length header, netif=ut) 39 | -v VDE path (Connect NAT to a VDE switch. netif=vp) 40 | -V VDE path (Expose NAT via a reduced functionality VDE switch. netif=vs) 41 | -t tun name (Expose NAT via a PTP TUN device. netif=tu) 42 | -T tap name (Expose NAT via a TAP device with DHCP. netif=ta) 43 | 44 | Some options also accept input through environmental veriables (see env 45 | above). By default, tunsocks accepts network traffic on stdin, and outputs 46 | network traffic on stdout. The "VPNFD" environmental variable can be used 47 | to pass an alternate fd. 48 | 49 | -L [bind_address:]port:host:hostport 50 | 51 | Listen on a local port and optional bind address. When a connection 52 | is accepted, tunsocks makes a connection on the remote network to 53 | host:hostport and then pipes the two connections together. If 54 | host port is not specified, it defaults to port. 55 | 56 | -D [bind_address:]port 57 | 58 | Start a SOCKS proxy on a local port and optional bind address. The 59 | SOCKS proxy supports SOCKS 4, 4A, and 5. The BIND command is 60 | accepted. If bind_address is not specified, it defaults to 61 | localhost. 62 | 63 | -H [bind_address:]port 64 | 65 | Start a http/https proxy on a local port and optional bind address. 66 | 67 | -P proxy_pac_file:port 68 | 69 | Start a http server on localhost at the given port serving up the 70 | specified proxy PAC file. The server will respond to requests for 71 | '/', '/proxy.pac', and '/wpad.dat'. The file is re-read each time 72 | it is requested. 73 | 74 | -R port:host:hostport 75 | 76 | tunsocks listens on the specified port on the remote network. When 77 | a connection is accepted, tunsocks connects to host:hostport on 78 | the local network and then pipes the two connections together. If 79 | hostport is not specified, it defaults to port, if host is not 80 | specified, it defaults to localhost. 81 | 82 | -k keep alive interval (seconds) 83 | 84 | TCP keepalive options for all connections on the remote network. 85 | 86 | -m mtu (env INTERNAL_IP4_MTU) 87 | 88 | MTU used for the remote network. 89 | 90 | -s domain_search[,domain_search,...] (env CISCO_DEF_DOMAIN) 91 | 92 | Domain search order. Follows the same order as resolv.conf(5) search 93 | with ndots fixed at 1. 94 | 95 | -d dns,[dns,...] (env INTERNAL_IP4_DNS) 96 | 97 | DNS servers for the remote network. 98 | 99 | -i ip address (env INTERNAL_IP4_ADDRESS) 100 | 101 | IP address to use on the remote network. 102 | 103 | -n netmask 104 | 105 | Netmask to use on the remote network. 106 | 107 | -g gateway 108 | 109 | IP gateway to use on the remote network. 110 | 111 | -S 112 | Use slirp interface instead VPN for outbound connection. This uses 113 | the host's IP stack to make outbound connections. 114 | 115 | -l delay_ms 116 | 117 | Add a delay (in ms) to inbound/outbound packets (useful for testing). 118 | 119 | -o probability 120 | 121 | Set a probability for dropping packets for inbound/outbound (useful 122 | for testing). 123 | 124 | -p pcap_file[:netif] 125 | 126 | If specified, all traffic is saved to the specified file in pcap 127 | format. The default interface is 'fd', which is the VPN interface. 128 | 129 | -u port 130 | 131 | Provides a NAT connection to the VPN via raw packets. The network 132 | provides a DHCP server that assigns clients an IP address, subnet, 133 | default route, DNS server, and domain names appropriately. The network 134 | is 10.0.4.0/24. 135 | 136 | tunsocks will listen for raw Ethernet packets on the given UDP port. 137 | Whenever it receives a packet, it will associated the sender's hardware 138 | address with the sender's IP and port. Any packets destined for the 139 | sender's IP address will be returned. Any packets destined for the 140 | broadcast address will be sent to all current clients. 141 | 142 | The netif name for use with -p i- 'ut'. 143 | 144 | -U port 145 | 146 | Like -u, but all packets include a 2 byte big-endian length header. 147 | 148 | -v VDE path 149 | 150 | Like -u, but connects to the given VDE switch. The network is 151 | 10.0.5.0/24. The netif name is 'vp'. 152 | 153 | -V VDE path 154 | 155 | Like -u, but emulates a VDE switch. The network is 10.0.6.0/24. The 156 | netif name is 'vs'. 157 | 158 | -T tap name 159 | 160 | Like -u but sends and receives packets via a supplied TAP device. The 161 | network is 10.0.7.0/24. The netif name is 'ta'. 162 | 163 | -t tun name 164 | 165 | Like -T but operates with TUN devices at the IP layer. This operates 166 | as a point-to-point interface and does not supply a DHCP server. The 167 | client must correctly configure IP and DNS settings. The IP address 168 | of the point-to-point device is 10.0.8.1. The netif name is 'tu'. 169 | 170 | Examples 171 | -------- 172 | 173 | openconnect --script-tun --script "tunsocks -D 8080 -R ssh \ 174 | -L 8888:webproxy.example.com:80" vpn.example.com 175 | 176 | tunsocks is configured to start a SOCKS server on localhost at port 8080. 177 | SSH connections on the remote network to our given IP address will connect 178 | to our local SSH server. A HTTP proxy is available on the remote network 179 | for accessing specific hosts, it is accessible via localhost:8888. 180 | Openconnect sets the other necessary parameters via environmental variables. 181 | 182 | 183 | tsocks configuration 184 | -------------------- 185 | 186 | tsocks can easily wrap applications via an LD_PRELOAD so that network 187 | requests instead travel via a proxy. 188 | 189 | /etc/tsocks.conf: 190 | server = 127.0.0.1 191 | server_type = 5 192 | server_port = 8080 193 | 194 | tsocks nc 10.15.12.12 55 195 | 196 | 197 | git configuration using socat 198 | ----------------------------- 199 | 200 | This configures git to use the localhost:8080 SOCKS proxy for connection 201 | to git.example.com. 202 | 203 | ~/.gitconfig: 204 | [core] 205 | gitproxy=/home/joeuser/bin/git-proxy-wrapper for git.example.com 206 | 207 | ~/bin/git-proxy-wrapper: 208 | exec socat STDIO SOCKS4A:localhost:$1:$2,socksport=8080 209 | 210 | 211 | ssh configuration using socat 212 | ----------------------------- 213 | 214 | This utilizes the localhost:8080 SOCKS proxy for any ssh connections in the 215 | *.intranet.example.com domain 216 | 217 | ~/.ssh/config: 218 | Host *.intranet.example.com 219 | ProxyCommand socat - SOCKS4A:localhost:%h:%p,socksport=8080 220 | 221 | 222 | Web browser and general desktop application configuration 223 | --------------------------------------------------------- 224 | 225 | Although web browsers and general desktop applications can be configured 226 | to use a single proxy easily, it is much more convenient to utilize a 227 | proxy.pac file. A proxy.pac file allows sets of rules for determining which 228 | connections should utilize the proxy. 229 | 230 | function FindProxyForURL(url, host) { 231 | 232 | // This rule allows single word domain names, such as "time" to 233 | // resolve via the VPN. This is common on corporate intranets. 234 | // tunsocks utilizes the domain search list in this case 235 | if (isPlainHostName(host)) 236 | return "SOCKS5 127.0.0.1:8080"; 237 | 238 | // proxy.pac can be used to easily funnel entire domains 239 | if (dnsDomainIs(host, ".intranet.example.com") || 240 | dnsDomainIs(host, ".documents.example.com")) 241 | return "SOCKS5 127.0.0.1:8080"; 242 | 243 | // Or single hosts 244 | if (host == "passwords.example.com" || host == "10.55.22.55") 245 | return "SOCKS5 127.0.0.1:8080"; 246 | 247 | // This is a slightly more complex example where certain hosts on the 248 | // intranet are only accessible by going through a web proxy available 249 | // via the VPN. A rule '-L 8888:webproxy.example.com:80' is added to 250 | // the tunsocks command line options. The following proxy.pac rule then 251 | // forwards requests for the given domain to that webproxy 252 | if (dnsDomainIs(host, "*.local.example.com")) 253 | return "PROXY localhost:8888"; 254 | 255 | // Everything else should access the Internet directly, without the 256 | // VPN 257 | return "DIRECT"; 258 | } 259 | 260 | proxy.pac files can support a wide variety of configurations, even multiplexing 261 | between multiple VPN connections. A proxy.pac file is generally assigned under 262 | the application or system proxy configuration page by selecting 'Automatic' 263 | and then using 'file:///path/to/proxy.pac' in the 'Configuration URL' field. 264 | 265 | Use of NAT with QEMU 266 | -------------------- 267 | 268 | Multiple methods can be used with QEMU, but the simplest is the UDP interface: 269 | 270 | For QEMU: 271 | 272 | -nic socket,udp=127.0.0.1:22222,localaddr=127.0.0.1:22223,mac=52:54:00:12:34:56 273 | 274 | For tunsocks: 275 | 276 | -u 22222 277 | 278 | Note that different instances of QEMU should supply different localaddr ports. 279 | 280 | Use of NAT with Vagrant 281 | ----------------------- 282 | 283 | Using the NAT interface with Vagrant is a little more complex as Vagrant 284 | requires a working interface to the host for ssh access: 285 | 286 | vb.customize ["modifyvm", :id, "--nic1", "generic"] 287 | vb.customize ["modifyvm", :id, "--nicgenericdrv1", "UDPTunnel"] 288 | vb.customize ["modifyvm", :id, "--nicproperty1", "dest=127.0.0.1"] 289 | vb.customize ["modifyvm", :id, "--nicproperty1", "dport=22222"] 290 | 291 | vb.customize ["modifyvm", :id, "--nic2", "nat"] 292 | vb.customize ["modifyvm", :id, "--natpf2", "ssh,tcp,127.0.0.1,2222,,22"] 293 | 294 | The above sets up two interfaces, one for the primary connection that uses 295 | the UDP NAT interface of tunsocks, and a second interface for ssh access. 296 | 297 | Compile 298 | ------- 299 | 300 | Compiling tunsocks is fairly easy one. You need to clone and initialize its git modules using following commands 301 | 302 | git clone https://github.com/russdill/tunsocks 303 | git submodule init 304 | git submodule update 305 | 306 | Then you need to make sure all prerequisites are installed 307 | 308 | - `libevent` 309 | - `autotools` 310 | - `make` 311 | 312 | For compiling the code you just need to run: 313 | 314 | ./autogen.sh 315 | ./configure 316 | make 317 | 318 | Credits 319 | ------- 320 | 321 | tunsocks was written by Russ Dill with inspiration from 322 | ocproxy by David Edmondson and Kevin Cernekee 323 | 324 | License 325 | ------- 326 | 327 | tunsocks is complied into and licensed under the same license as lwIP. For 328 | a copy of the license, see lwip/COPYING. 329 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | autoreconf --force --install --verbose 6 | rm -rf autom4te*.cache 7 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.61]) 2 | AC_INIT([tunsocks], [1.0], [russ.dill@gmail.com], [tunsocks], [https://github.com/russdill/tunsocks]) 3 | AM_INIT_AUTOMAKE([foreign subdir-objects]) 4 | 5 | AC_PROG_CC 6 | AC_CONFIG_FILES([Makefile]) 7 | 8 | AC_SEARCH_LIBS([event_add], [event]) 9 | 10 | AC_ARG_ENABLE([pcap], 11 | AS_HELP_STRING([--disable-pcap],[Disable optional PCAP support]), 12 | [case "${enableval}" in 13 | yes) have_pcap=yes ;; 14 | no) have_pcap=no ;; 15 | *) AC_MSG_ERROR(bad value ${enableval} for --disable-pcap) ;; 16 | esac], 17 | [have_pcap=auto]) 18 | 19 | if test "x${have_pcap}" != xno ; then 20 | AC_CHECK_LIB( 21 | [pcap], 22 | [pcap_open_dead], 23 | [have_pcap=yes], 24 | [if test "x$have_pcap" = xyes ; then 25 | AC_MSG_ERROR([*** libpcap not found.]) 26 | fi]) 27 | 28 | if test "x$have_pcap" = xyes ; then 29 | PCAP_LIBS="-lpcap" 30 | AC_DEFINE(HAVE_PCAP, 1, [PCAP available]) 31 | else 32 | have_pcap=no 33 | fi 34 | else 35 | PCAP_LIBS= 36 | fi 37 | 38 | AC_SUBST(PCAP_LIBS) 39 | AM_CONDITIONAL([HAVE_PCAP], [test "x$have_pcap" != xno]) 40 | 41 | AC_OUTPUT 42 | -------------------------------------------------------------------------------- /include/arch/cc.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_CC_H__ 2 | #define __ARCH_CC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef uint8_t u8_t; 12 | typedef int8_t s8_t; 13 | typedef uint16_t u16_t; 14 | typedef int16_t s16_t; 15 | typedef uint32_t u32_t; 16 | typedef int32_t s32_t; 17 | 18 | typedef uintptr_t mem_ptr_t; 19 | 20 | #define LWIP_ERR_T int 21 | 22 | /* Define (sn)printf formatters for these lwIP types */ 23 | #define U16_F "hu" 24 | #define S16_F "hd" 25 | #define X16_F "hx" 26 | #define U32_F "u" 27 | #define S32_F "d" 28 | #define X32_F "x" 29 | 30 | /* Compiler hints for packing structures */ 31 | #define PACK_STRUCT_FIELD(x) x 32 | #define PACK_STRUCT_STRUCT __attribute__((packed)) 33 | #define PACK_STRUCT_BEGIN 34 | #define PACK_STRUCT_END 35 | 36 | /* Plaform specific diagnostic output */ 37 | #define LWIP_PLATFORM_DIAG(x) do { \ 38 | printf x; \ 39 | } while (0) 40 | 41 | #define LWIP_PLATFORM_ASSERT(x) do { \ 42 | printf("Assert \"%s\" failed at line %d in %s\n", \ 43 | x, __LINE__, __FILE__); \ 44 | abort(); \ 45 | } while (0) 46 | 47 | #define LWIP_RAND() ((u32_t) rand()) 48 | 49 | #endif /* __ARCH_CC_H__ */ 50 | -------------------------------------------------------------------------------- /include/arch/perf.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_PERF_H__ 2 | #define __ARCH_PERF_H__ 3 | 4 | #define PERF_START do { } while(0) 5 | #define PERF_STOP(x) do { } while(0) 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /include/http/http.h: -------------------------------------------------------------------------------- 1 | #ifndef __HTTP_H__ 2 | #define __HTTP_H__ 3 | 4 | struct event_base; 5 | 6 | int http_listen(struct event_base *base, const char *host, const char *port, int keep_alive); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/http/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __HTTP_SERVER_H__ 2 | #define __HTTP_SERVER_H__ 3 | 4 | struct event_base; 5 | 6 | int http_server_listen(struct event_base *base, const char *port, const char *path); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/lwipopts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001-2003 Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 3. The name of the author may not be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 | * OF SUCH DAMAGE. 26 | * 27 | * This file is part of the lwIP TCP/IP stack. 28 | * 29 | * Author: Simon Goldschmidt 30 | * 31 | */ 32 | #ifndef __LWIPOPTS_H__ 33 | #define __LWIPOPTS_H__ 34 | 35 | #include 36 | #include 37 | 38 | #define NO_SYS_NO_TIMERS 1 39 | #define SYS_LIGHTWEIGHT_PROT 0 40 | #define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 41 | 42 | struct pbuf; 43 | struct netif; 44 | extern int ip4_input_nat(struct pbuf *p, struct netif *inp); 45 | #define LWIP_HOOK_IP4_INPUT ip4_input_nat 46 | 47 | #define MEM_LIBC_MALLOC 1 48 | #define MEMP_MEM_MALLOC 1 49 | #define MEM_ALIGNMENT 4 50 | #define MEM_SIZE (16*1024*1024) 51 | 52 | #define MEMP_NUM_UDP_PCB 1024 53 | #define MEMP_NUM_TCP_PCB 1024 54 | #define MEMP_NUM_TCP_PCB_LISTEN 1024 55 | #define MEMP_NUM_TCP_SEG 8192 56 | #define MEMP_NUM_REASSDATA 256 57 | #define MEMP_NUM_FRAG_PBUF 1024 58 | #define MEMP_NUM_TCPIP_MSG_API 1024 59 | #define MEMP_NUM_TCPIP_MSG_INPKT 1024 60 | 61 | #define LWIP_ARP 1 62 | #define LWIP_RAW 1 63 | #define LWIP_ICMP 1 64 | #define LWIP_TCP_KEEPALIVE 1 65 | #define LWIP_TCP_TIMESTAMPS 1 66 | #define IP_FORWARD 1 67 | #define LWIP_NAT 1 68 | #define LWIP_NAT_ICMP 1 69 | #define LWIP_NAT_ICMP_IP 1 70 | #define LWIP_NAT_USE_OLDEST 1 71 | #define LWIP_ETHERNET 1 72 | #define LWIP_DNS 1 73 | #define LWIP_WND_SCALE 8 74 | #define DNS_TABLE_SIZE 255 75 | #define DNS_MAX_SERVERS 8 76 | #define LWIP_IP_ACCEPT_UDP_PORT(p) (p == 67) 77 | 78 | #define TCP_MSS 1500 79 | #define TCP_WND (256*1024) 80 | #define TCP_SND_QUEUELEN 8192 81 | #define TCP_SND_BUF 65535 82 | #define TCP_RCV_SCALE 8 83 | 84 | #define SO_REUSE 1 85 | 86 | #define NO_SYS 1 87 | #define LWIP_NETCONN 0 88 | #define LWIP_SOCKET 0 89 | 90 | #define LWIP_NETIF_LINK_CALLBACK 1 91 | 92 | #define HOST_SEARCH_SIZE 6 93 | 94 | #define LWIP_DEBUG 0 95 | #define NETIF_DEBUG LWIP_DBG_OFF 96 | #define TAPNAT_DEBUG LWIP_DBG_OFF 97 | #define NAT_DEBUG LWIP_DBG_OFF 98 | #define ETHARP_DEBUG LWIP_DBG_OFF 99 | #define SLIRPIF_DEBUG LWIP_DBG_OFF 100 | #define SOCKS_DEBUG LWIP_DBG_OFF 101 | #define UDHCP_DEBUG LWIP_DBG_OFF 102 | #define HOSTS_DEBUG LWIP_DBG_OFF 103 | #define MEM_DEBUG LWIP_DBG_OFF 104 | #define IP_DEBUG LWIP_DBG_OFF 105 | #define IP_REASS_DEBUG LWIP_DBG_OFF 106 | #define TCP_DEBUG LWIP_DBG_OFF 107 | #define TCP_INPUT_DEBUG LWIP_DBG_OFF 108 | #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF 109 | #define TCP_CWND_DEBUG LWIP_DBG_OFF 110 | #define UDP_DEBUG LWIP_DBG_OFF 111 | #define DNS_DEBUG LWIP_DBG_OFF 112 | #define LWIPEVBUF_OUTPUT_DEBUG LWIP_DBG_OFF 113 | #define LWIPEVBUF_INPUT_DEBUG LWIP_DBG_OFF 114 | #define LWIPEVBUF_DEBUG LWIP_DBG_OFF 115 | #define LWIPEVBUF_BEV_JOIN_DEBUG LWIP_DBG_OFF 116 | 117 | #endif /* __LWIPOPTS_H__ */ 118 | -------------------------------------------------------------------------------- /src/dhcp_server.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "dhcp_server.h" 13 | #include "udhcp_common.h" 14 | #include "dhcpd.h" 15 | #include "util/host.h" 16 | 17 | int 18 | dhcp_server_add(struct netif *netif) 19 | { 20 | struct udhcpd_server *server; 21 | struct option_set *option; 22 | int i; 23 | int n; 24 | const char *first; 25 | uint8_t cstr[1024]; 26 | int clen; 27 | int cpos; 28 | 29 | server = udhcpd_init(netif, 67); 30 | if (!server) { 31 | return -1; 32 | } 33 | 34 | option = calloc(1, sizeof(*option) + 2 + 4); 35 | option->data = (uint8_t *)(option + 1); 36 | option->data[OPT_CODE] = DHCP_ROUTER; 37 | option->data[OPT_LEN] = 4; 38 | memcpy(option->data + 2, &netif->ip_addr.addr, 4); 39 | option->next = server->options; 40 | server->options = option; 41 | 42 | option = calloc(1, sizeof(*option) + 2 + 4); 43 | option->data = (uint8_t *)(option + 1); 44 | option->data[OPT_CODE] = DHCP_SUBNET; 45 | option->data[OPT_LEN] = 4; 46 | memcpy(option->data + 2, &netif->netmask.addr, 4); 47 | option->next = server->options; 48 | server->options = option; 49 | 50 | option = calloc(1, sizeof(*option) + 2 + 4 * DNS_MAX_SERVERS); 51 | option->data = (uint8_t *)(option + 1); 52 | option->data[OPT_CODE] = DHCP_DNS_SERVER; 53 | for (n = 0, i = 0; i < DNS_MAX_SERVERS; i++) { 54 | const ip_addr_t *dns = dns_getserver(i); 55 | if (dns->addr) { 56 | memcpy(option->data + 2 + 4 * n, &dns->addr, 4); 57 | n++; 58 | } 59 | } 60 | option->data[OPT_LEN] = 4 * n; 61 | option->next = server->options; 62 | server->options = option; 63 | 64 | clen = 0; 65 | first = NULL; 66 | for (i = 0; i < HOST_SEARCH_SIZE; i++) { 67 | const char *host = host_get_search(i); 68 | if (host) { 69 | int retlen = 0; 70 | uint8_t *dname = dname_enc(cstr, clen, host, &retlen); 71 | if (!first && strlen(host) < 255) 72 | first = host; 73 | if (dname && clen + retlen < sizeof(cstr)) { 74 | memcpy(cstr + clen, dname, retlen); 75 | clen += retlen; 76 | } 77 | free(dname); 78 | } 79 | } 80 | 81 | if (first) { 82 | option = calloc(1, sizeof(*option) + 2 + strlen(first) + 1); 83 | option->data = (uint8_t *)(option + 1); 84 | option->data[OPT_CODE] = DHCP_DOMAIN_NAME; 85 | option->data[OPT_LEN] = strlen(first) + 1; 86 | strcpy((char *)option->data + 2, first); 87 | option->next = server->options; 88 | server->options = option; 89 | } 90 | 91 | cpos = 0; 92 | while (cpos < clen) { 93 | int len = (clen - cpos) > 255 ? 255 : (clen - cpos); 94 | option = calloc(1, sizeof(*option) + 2 + len); 95 | option->data = (uint8_t *)(option + 1); 96 | option->data[OPT_CODE] = DHCP_DOMAIN_SEARCH; 97 | option->data[OPT_LEN] = len; 98 | memcpy(option->data + 2, cstr + cpos, len); 99 | option->next = server->options; 100 | server->options = option; 101 | cpos += len; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/dhcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __DHCP_SERVER_H__ 2 | #define __DHCP_SERVER_H__ 3 | 4 | struct netif; 5 | 6 | int dhcp_server_add(struct netif *netif); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/forward_local.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "forward_local.h" 11 | #include "util/lwipevbuf.h" 12 | #include "util/lwipevbuf_bev_join.h" 13 | 14 | struct forward_remote { 15 | char *host; 16 | unsigned short port; 17 | int keep_alive; 18 | }; 19 | 20 | static void forward_local_accept(struct evconnlistener *evl, 21 | evutil_socket_t new_fd, struct sockaddr *addr, int socklen, void *ctx) 22 | { 23 | struct event_base *base = evconnlistener_get_base(evl); 24 | struct forward_remote *remote = ctx; 25 | struct lwipevbuf *lwipevbuf; 26 | struct bufferevent *bev; 27 | 28 | lwipevbuf = lwipevbuf_new(NULL); 29 | 30 | if (remote->keep_alive) { 31 | lwipevbuf->pcb->so_options |= SOF_KEEPALIVE; 32 | lwipevbuf->pcb->keep_intvl = remote->keep_alive; 33 | lwipevbuf->pcb->keep_idle = remote->keep_alive; 34 | } 35 | 36 | if (lwipevbuf_connect_hostname(lwipevbuf, AF_UNSPEC, remote->host, remote->port) < 0) { 37 | lwipevbuf_free(lwipevbuf); 38 | return; 39 | } 40 | 41 | bev = bufferevent_socket_new(base, new_fd, BEV_OPT_CLOSE_ON_FREE); 42 | lwipevbuf_bev_join(bev, lwipevbuf, 256*1024, NULL, NULL, NULL, NULL, NULL, NULL); 43 | } 44 | 45 | #ifndef LEV_OPT_DEFERRED_ACCEPT 46 | #define LEV_OPT_DEFERRED_ACCEPT 0 47 | #endif 48 | 49 | int forward_local(struct event_base *base, 50 | const char *local_host, const char *local_port, 51 | const char *remote_host, const char *remote_port, int keep_alive) 52 | { 53 | struct evconnlistener *evl; 54 | struct addrinfo hints; 55 | struct addrinfo *result; 56 | struct forward_remote *remote; 57 | u_int16_t port; 58 | char *endptr; 59 | int ret; 60 | 61 | port = strtoul(remote_port, &endptr, 0); 62 | if (endptr[0]) { 63 | struct servent *s; 64 | s = getservbyname(remote_port, "tcp"); 65 | port = ntohs(s->s_port); 66 | endservent(); 67 | if (!s) 68 | return -1; 69 | } 70 | 71 | memset(&hints, 0, sizeof(hints)); 72 | hints.ai_family = AF_UNSPEC; 73 | hints.ai_socktype = SOCK_STREAM; 74 | 75 | ret = getaddrinfo(local_host, local_port, &hints, &result); 76 | if (ret < 0) { 77 | fprintf(stderr, "%s: %s\n", __func__, gai_strerror(ret)); 78 | return ret; 79 | } 80 | 81 | remote = calloc(1, sizeof(*remote)); 82 | remote->host = strdup(remote_host); 83 | remote->port = port; 84 | remote->keep_alive = keep_alive; 85 | 86 | evl = evconnlistener_new_bind(base, forward_local_accept, remote, 87 | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | 88 | LEV_OPT_REUSEABLE | LEV_OPT_DEFERRED_ACCEPT, 10, 89 | result->ai_addr, result->ai_addrlen); 90 | 91 | freeaddrinfo(result); 92 | 93 | if (!evl) { 94 | free(remote); 95 | perror(__func__); 96 | return -1; 97 | } 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /src/forward_local.h: -------------------------------------------------------------------------------- 1 | #ifndef __FORWARD_LOCAL_H__ 2 | #define __FORWARD_LOCAL_H__ 3 | 4 | struct event_base; 5 | 6 | int forward_local(struct event_base *base, const char *host, const char *port, 7 | const char *local_host, const char *local_port, int keep_alive); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/forward_remote.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "container_of.h" 10 | #include "util/host.h" 11 | #include "forward_remote.h" 12 | #include "util/lwipevbuf.h" 13 | #include "util/lwipevbuf_bev_join.h" 14 | 15 | struct forward_data { 16 | struct addrinfo *remote; 17 | struct event_base *base; 18 | int keep_alive; 19 | }; 20 | 21 | static err_t forward_tcp_accept(void *ctx, struct tcp_pcb *pcb, err_t err) 22 | { 23 | struct forward_data *data = ctx; 24 | struct addrinfo *remote = data->remote; 25 | struct bufferevent *bev; 26 | struct lwipevbuf *lwipevbuf; 27 | 28 | bev = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); 29 | 30 | if (bufferevent_socket_connect(bev, remote->ai_addr, 31 | remote->ai_addrlen) < 0) { 32 | /* die */ 33 | bufferevent_free(bev); 34 | tcp_abort(pcb); 35 | return ERR_ABRT; 36 | } 37 | 38 | if (data->keep_alive) { 39 | pcb->so_options |= SOF_KEEPALIVE; 40 | pcb->keep_intvl = data->keep_alive; 41 | pcb->keep_idle = data->keep_alive; 42 | } 43 | 44 | lwipevbuf = lwipevbuf_new(pcb); 45 | lwipevbuf_bev_join(bev, lwipevbuf, 256*1024, NULL, NULL, NULL, NULL, NULL, NULL); 46 | 47 | return ERR_OK; 48 | } 49 | 50 | 51 | static int forward_listen(struct forward_data *data, const ip_addr_t *ipaddr, int port) 52 | { 53 | struct tcp_pcb *pcb; 54 | struct tcp_pcb *_pcb; 55 | err_t ret; 56 | 57 | pcb = tcp_new(); 58 | if (!pcb) 59 | return -1; 60 | 61 | ip_set_option(pcb, SOF_REUSEADDR); 62 | 63 | ret = tcp_bind(pcb, ipaddr, port); 64 | if (ret < 0) { 65 | tcp_abort(pcb); 66 | return -1; 67 | } 68 | 69 | _pcb = tcp_listen(pcb); 70 | if (!_pcb) { 71 | tcp_abort(pcb); 72 | return -1; 73 | } 74 | pcb = _pcb; 75 | 76 | tcp_arg(pcb, data); 77 | tcp_accept(pcb, forward_tcp_accept); 78 | 79 | return 0; 80 | } 81 | 82 | int forward_remote(struct event_base *base, const char *remote_port, 83 | const char *local_host, const char *local_port, int keep_alive) 84 | { 85 | u_int16_t port; 86 | char *endptr; 87 | struct addrinfo hints; 88 | struct addrinfo *result; 89 | struct forward_data *data; 90 | int success = 0; 91 | err_t ret; 92 | 93 | port = strtoul(remote_port, &endptr, 0); 94 | if (endptr[0]) { 95 | struct servent *s; 96 | s = getservbyname(remote_port, "tcp"); 97 | port = ntohs(s->s_port); 98 | endservent(); 99 | if (!s) 100 | return -1; 101 | } 102 | 103 | memset(&hints, 0, sizeof(hints)); 104 | hints.ai_family = AF_UNSPEC; 105 | hints.ai_socktype = SOCK_STREAM; 106 | 107 | ret = getaddrinfo(local_host, local_port, &hints, &result); 108 | if (ret < 0) { 109 | fprintf(stderr, "%s: %s\n", __func__, gai_strerror(ret)); 110 | return ret; 111 | } 112 | 113 | data = calloc(1, sizeof(*data)); 114 | data->remote = result; 115 | data->base = base; 116 | data->keep_alive = keep_alive; 117 | 118 | #if LWIP_IPV4 119 | success = forward_listen(data, IP4_ADDR_ANY, port) == 0; 120 | #endif 121 | #if LWIP_IPV6 122 | success = forward_listen(data, IP6_ADDR_ANY, port) == 0; 123 | #endif 124 | 125 | if (!success) { 126 | freeaddrinfo(result); 127 | free(data); 128 | } 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /src/forward_remote.h: -------------------------------------------------------------------------------- 1 | #ifndef __FORWARD_REMOTE_H__ 2 | #define __FORWARD_REMOTE_H__ 3 | 4 | struct event_base; 5 | 6 | int forward_remote(struct event_base *base, const char *remote_port, 7 | const char *local_host, const char *local_port, int keep_alive); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/http/evhttp_extra.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "evhttp_extra.h" 4 | 5 | const char * 6 | evhttp_method(enum evhttp_cmd_type type) 7 | { 8 | const char *method; 9 | 10 | switch (type) { 11 | case EVHTTP_REQ_GET: 12 | method = "GET"; 13 | break; 14 | case EVHTTP_REQ_POST: 15 | method = "POST"; 16 | break; 17 | case EVHTTP_REQ_HEAD: 18 | method = "HEAD"; 19 | break; 20 | case EVHTTP_REQ_PUT: 21 | method = "PUT"; 22 | break; 23 | case EVHTTP_REQ_DELETE: 24 | method = "DELETE"; 25 | break; 26 | case EVHTTP_REQ_OPTIONS: 27 | method = "OPTIONS"; 28 | break; 29 | case EVHTTP_REQ_TRACE: 30 | method = "TRACE"; 31 | break; 32 | case EVHTTP_REQ_CONNECT: 33 | method = "CONNECT"; 34 | break; 35 | case EVHTTP_REQ_PATCH: 36 | method = "PATCH"; 37 | break; 38 | default: 39 | method = NULL; 40 | break; 41 | } 42 | 43 | return (method); 44 | } 45 | -------------------------------------------------------------------------------- /src/http/evhttp_extra.h: -------------------------------------------------------------------------------- 1 | #ifndef __EVHTTP_EXTRA_H__ 2 | #define __EVHTTP_EXTRA_H__ 3 | 4 | enum evhttp_cmd_type; 5 | struct evhttp_request; 6 | struct evbuffer; 7 | 8 | enum message_read_status { 9 | ALL_DATA_READ = 1, 10 | MORE_DATA_EXPECTED = 0, 11 | DATA_CORRUPTED = -1, 12 | REQUEST_CANCELED = -2, 13 | DATA_TOO_LONG = -3 14 | }; 15 | 16 | 17 | void 18 | evhttp_response_code_(struct evhttp_request *req, int code, const char *reason); 19 | 20 | void 21 | evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf); 22 | 23 | enum message_read_status 24 | evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer); 25 | 26 | enum message_read_status 27 | evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer); 28 | 29 | const char *evhttp_method(enum evhttp_cmd_type type); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/http/http.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "http/http.h" 20 | 21 | #include "evhttp_extra.h" 22 | 23 | #ifndef LIBEVENT_TEST 24 | #include "util/lwipevbuf_bev_join.h" 25 | #include "util/lwipevbuf.h" 26 | #else 27 | #include "bufferevent_join.h" 28 | #endif 29 | 30 | #ifndef PACKAGE 31 | #define PACKAGE "util/libevent-http" 32 | #endif 33 | #ifndef VERSION 34 | #define VERSION "0.1" 35 | #endif 36 | 37 | struct evhttp_proxy_request { 38 | #ifndef LIBEVENT_TEST 39 | struct lwipevbuf *server_bev; 40 | #else 41 | struct bufferevent *server_bev; 42 | #endif 43 | struct evhttp_request *server_req; 44 | struct evhttp_request *client_req; 45 | }; 46 | 47 | struct http_proxy { 48 | #ifdef LIBEVENT_TEST 49 | struct evdns_base *dnsbase; 50 | #endif 51 | struct evhttp *evh; 52 | int keep_alive; 53 | }; 54 | 55 | static void 56 | client_send_error(struct evhttp_request *req, int error, const char *format, ...) 57 | { 58 | struct evbuffer *buf = evbuffer_new(); 59 | va_list args; 60 | evhttp_response_code_(req, error, NULL); 61 | 62 | evbuffer_add_printf(buf, "%d %s", 63 | error, req->response_code_line); 64 | va_start(args, format); 65 | evbuffer_add_vprintf(buf, format, args); 66 | va_end(args); 67 | evbuffer_add_printf(buf, ""); 68 | 69 | evhttp_send_page_(req, buf); 70 | evbuffer_free(buf); 71 | } 72 | 73 | static void 74 | client_req_eof(struct bufferevent *bev, void *ctx) 75 | { 76 | struct evhttp_connection *evcon = ctx; 77 | evhttp_connection_free(evcon); 78 | } 79 | 80 | static void 81 | proxy_req_join(struct evhttp_proxy_request *proxy_req) 82 | { 83 | struct evhttp_connection *client_evcon = proxy_req->client_req->evcon; 84 | struct bufferevent *client_bev = evhttp_connection_get_bufferevent(client_evcon); 85 | 86 | evhttp_connection_set_closecb(client_evcon, NULL, NULL); 87 | #ifndef LIBEVENT_TEST 88 | lwipevbuf_bev_join(client_bev, proxy_req->server_bev, 256*1024, 89 | client_req_eof, client_evcon, NULL, NULL, NULL, NULL); 90 | #else 91 | bufferevent_join(client_bev, proxy_req->server_bev, 256*1024, 92 | client_req_eof, client_evcon, NULL, NULL, NULL, NULL); 93 | #endif 94 | 95 | if (proxy_req->server_req) 96 | evhttp_request_free(proxy_req->server_req); 97 | 98 | free(proxy_req); 99 | } 100 | 101 | static void 102 | remove_headers(struct evkeyvalq *headers, const char *key) 103 | { 104 | const char *val; 105 | char *s, *n, *sdup; 106 | /* remove connection headers */ 107 | val = evhttp_find_header(headers, key); 108 | if (!val) 109 | return; 110 | 111 | sdup = strdup(val); 112 | for (n = sdup, s = sdup; n; s = n + 1) { 113 | n = strpbrk(s, "()<>@,;:\\\"/[]?={} \t"); 114 | if (n) 115 | *n = '\0'; 116 | if (*s) 117 | evhttp_remove_header(headers, s); 118 | } 119 | free(sdup); 120 | 121 | evhttp_remove_header(headers, key); 122 | } 123 | 124 | static int 125 | proxy_req_server_headers_done(struct evhttp_proxy_request *proxy_req) 126 | { 127 | struct evhttp_request *client_req = proxy_req->client_req; 128 | struct bufferevent *client_bev; 129 | struct evhttp_connection *client_evcon; 130 | struct evhttp_request *server_req = proxy_req->server_req; 131 | struct evbuffer *client_output; 132 | struct evkeyval *header; 133 | const char *via; 134 | const char *hostname = "unknown"; 135 | 136 | evhttp_response_code_(client_req, server_req->response_code, server_req->response_code_line); 137 | 138 | client_evcon = evhttp_request_get_connection(client_req); 139 | client_bev = evhttp_connection_get_bufferevent(client_evcon); 140 | client_output = bufferevent_get_output(client_bev); 141 | evbuffer_add_printf(client_output, 142 | "HTTP/%d.%d %d %s\r\n", 143 | client_req->major, client_req->minor, client_req->response_code, 144 | client_req->response_code_line); 145 | 146 | remove_headers(client_req->input_headers, "connection"); 147 | remove_headers(client_req->input_headers, "proxy-connection"); 148 | 149 | evhttp_remove_header(server_req->input_headers, "keep-alive"); 150 | evhttp_remove_header(server_req->input_headers, "proxy-authenticate"); 151 | evhttp_remove_header(server_req->input_headers, "proxy-authorization"); 152 | 153 | /* Add our via header */ 154 | via = evhttp_find_header(server_req->input_headers, "via"); 155 | if (via) { 156 | evbuffer_add_printf(client_output, "Via: %s, ", via); 157 | evhttp_remove_header(server_req->input_headers, "via"); 158 | } else 159 | evbuffer_add_printf(client_output, "Via: "); 160 | evbuffer_add_printf(client_output, "%d.%d %s (%s/%s)\r\n", 161 | server_req->major, server_req->minor, 162 | hostname, PACKAGE, VERSION); 163 | 164 | TAILQ_FOREACH(header, server_req->input_headers, next) { 165 | evbuffer_add_printf(client_output, "%s: %s\r\n", 166 | header->key, header->value); 167 | } 168 | evbuffer_add(client_output, "\r\n", 2); 169 | 170 | /* Queue any data the server already sent */ 171 | bufferevent_write_buffer(client_bev, evhttp_request_get_input_buffer(server_req)); 172 | 173 | proxy_req_join(proxy_req); 174 | 175 | return 0; 176 | } 177 | 178 | static void 179 | proxy_req_client_closecb(struct evhttp_connection *evcon, void *ctx) 180 | { 181 | struct evhttp_proxy_request *proxy_req = ctx; 182 | #ifndef LIBEVENT_TEST 183 | lwipevbuf_free(proxy_req->server_bev); 184 | #else 185 | bufferevent_free(proxy_req->server_bev); 186 | #endif 187 | if (proxy_req->server_req) 188 | evhttp_request_free(proxy_req->server_req); 189 | free(proxy_req); 190 | } 191 | 192 | static void 193 | proxy_req_free(struct evhttp_proxy_request *proxy_req) 194 | { 195 | struct evhttp_connection *client_evcon; 196 | 197 | #ifndef LIBEVENT_TEST 198 | lwipevbuf_free(proxy_req->server_bev); 199 | #else 200 | bufferevent_free(proxy_req->server_bev); 201 | #endif 202 | 203 | if (proxy_req->server_req) 204 | evhttp_request_free(proxy_req->server_req); 205 | 206 | client_evcon = evhttp_request_get_connection(proxy_req->client_req); 207 | evhttp_connection_set_closecb(client_evcon, NULL, NULL); 208 | 209 | if (!proxy_req->client_req->userdone) 210 | evhttp_connection_free(client_evcon); 211 | 212 | free(proxy_req); 213 | } 214 | 215 | static void 216 | #ifndef LIBEVENT_TEST 217 | proxy_req_eventcb(struct lwipevbuf *bev, short what, void *ctx) 218 | #else 219 | proxy_req_eventcb(struct bufferevent *bev, short what, void *ctx) 220 | #endif 221 | { 222 | struct evhttp_proxy_request *proxy_req = ctx; 223 | struct evhttp_request *client_req = proxy_req->client_req; 224 | 225 | if (what & BEV_EVENT_TIMEOUT) { 226 | client_send_error(client_req, 403, 227 | "Server communication timed out"); 228 | } else if (what & BEV_EVENT_ERROR) { 229 | const char *str; 230 | 231 | #ifndef LIBEVENT_TEST 232 | str = evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()); 233 | #elif defined(LWIP_DEBUG) 234 | str = lwip_strerr(bev->tcp_err); 235 | #else 236 | str = "unspecified"; 237 | #endif 238 | if (what & BEV_EVENT_READING) { 239 | client_send_error(client_req, 503, 240 | "Error reading data from server: %s", str); 241 | } else { 242 | client_send_error(client_req, 503, 243 | "Error writing data to server: %s", str); 244 | } 245 | } else if (what & BEV_EVENT_EOF) { 246 | client_send_error(client_req, 500, 247 | "EOF while establishing communication with server"); 248 | } 249 | 250 | proxy_req_free(proxy_req); 251 | } 252 | 253 | static void 254 | #ifndef LIBEVENT_TEST 255 | proxy_req_read_header(struct lwipevbuf *bufev, void *arg) 256 | #else 257 | proxy_req_read_header(struct bufferevent *bufev, void *arg) 258 | #endif 259 | { 260 | enum message_read_status res; 261 | struct evhttp_proxy_request *proxy_req = arg; 262 | struct evhttp_request *req = proxy_req->server_req; 263 | struct evhttp_request *client_req = proxy_req->client_req; 264 | struct evbuffer *input; 265 | 266 | #ifndef LIBEVENT_TEST 267 | input = bufev->input_buffer; 268 | #else 269 | input = bufferevent_get_input(bufev); 270 | #endif 271 | 272 | res = evhttp_parse_headers_(req, input); 273 | if (res == DATA_CORRUPTED) { 274 | client_send_error(client_req, 503, 275 | "Error parsing HTTP headers from server"); 276 | proxy_req_free(proxy_req); 277 | return; 278 | } else if (res == DATA_TOO_LONG) { 279 | /* Error while reading, terminate */ 280 | client_send_error(client_req, 503, 281 | "HTTP headers from server too long"); 282 | proxy_req_free(proxy_req); 283 | return; 284 | } else if (res == MORE_DATA_EXPECTED) { 285 | /* Need more header lines */ 286 | return; 287 | } 288 | 289 | proxy_req_server_headers_done(proxy_req); 290 | } 291 | 292 | static void 293 | #ifndef LIBEVENT_TEST 294 | proxy_req_read_firstline(struct lwipevbuf *bufev, void *arg) 295 | #else 296 | proxy_req_read_firstline(struct bufferevent *bufev, void *arg) 297 | #endif 298 | { 299 | enum message_read_status res; 300 | struct evhttp_proxy_request *proxy_req = arg; 301 | struct evhttp_request *req = proxy_req->server_req; 302 | struct evhttp_request *client_req = proxy_req->client_req; 303 | struct evbuffer *input; 304 | 305 | #ifndef LIBEVENT_TEST 306 | input = bufev->input_buffer; 307 | #else 308 | input = bufferevent_get_input(bufev); 309 | #endif 310 | 311 | res = evhttp_parse_firstline_(req, input); 312 | if (res == DATA_CORRUPTED) { 313 | client_send_error(client_req, 503, 314 | "Error parsing response line from server"); 315 | proxy_req_free(proxy_req); 316 | return; 317 | } else if (res == DATA_TOO_LONG) { 318 | client_send_error(client_req, 503, 319 | "Response line from server too long"); 320 | proxy_req_free(proxy_req); 321 | return; 322 | } else if (res == MORE_DATA_EXPECTED) { 323 | /* Need more header lines */ 324 | return; 325 | } 326 | 327 | #ifndef LIBEVENT_TEST 328 | lwipevbuf_setcb(bufev, proxy_req_read_header, NULL, proxy_req_eventcb, proxy_req); 329 | #else 330 | bufferevent_setcb(bufev, proxy_req_read_header, NULL, proxy_req_eventcb, proxy_req); 331 | #endif 332 | proxy_req_read_header(bufev, arg); 333 | } 334 | 335 | static void 336 | proxy_req_connected(struct evhttp_proxy_request *proxy_req) 337 | { 338 | #ifndef LIBEVENT_TEST 339 | struct lwipevbuf *server_bev = proxy_req->server_bev; 340 | struct evbuffer *server_output = server_bev->output_buffer; 341 | #else 342 | struct bufferevent *server_bev = proxy_req->server_bev; 343 | struct evbuffer *server_output = bufferevent_get_output(server_bev); 344 | #endif 345 | struct evhttp_request *client_req = proxy_req->client_req; 346 | struct evhttp_connection *client_evcon; 347 | 348 | client_evcon = evhttp_request_get_connection(client_req); 349 | 350 | if (client_req->type != EVHTTP_REQ_CONNECT) { 351 | struct evhttp_request *server_req; 352 | struct evkeyval *header; 353 | const char *hostname = "unknown"; 354 | const char *via; 355 | const char *url; 356 | const char *host; 357 | 358 | host = evhttp_request_get_host(client_req); 359 | url = evhttp_request_get_uri(client_req); 360 | 361 | server_req = evhttp_request_new(NULL, NULL); 362 | server_req->kind = EVHTTP_RESPONSE; 363 | server_req->type = client_req->type; 364 | server_req->uri = strdup(url); 365 | server_req->major = client_req->major; 366 | server_req->minor = client_req->minor; 367 | server_req->evcon = client_evcon; /* For max header length */ 368 | 369 | evbuffer_add_printf(server_output, 370 | "%s %s HTTP/%d.%d\r\n", 371 | evhttp_method(client_req->type), url, client_req->major, client_req->minor); 372 | 373 | /* remove connection headers */ 374 | remove_headers(client_req->input_headers, "connection"); 375 | remove_headers(client_req->input_headers, "proxy-connection"); 376 | 377 | /* remove headers we shouldn't forward */ 378 | evhttp_remove_header(client_req->input_headers, "util/host"); 379 | evhttp_remove_header(client_req->input_headers, "keep-alive"); 380 | evhttp_remove_header(client_req->input_headers, "te"); 381 | evhttp_remove_header(client_req->input_headers, "trailers"); 382 | 383 | /* Add our via header */ 384 | via = evhttp_find_header(client_req->input_headers, "via"); 385 | if (via) { 386 | evbuffer_add_printf(server_output, "Via: %s, ", via); 387 | evhttp_remove_header(client_req->input_headers, "via"); 388 | } else 389 | evbuffer_add_printf(server_output, "Via: "); 390 | evbuffer_add_printf(server_output, "%d.%d %s (%s/%s)\r\n", 391 | client_req->major, client_req->minor, 392 | hostname, PACKAGE, VERSION); 393 | 394 | TAILQ_FOREACH(header, client_req->input_headers, next) { 395 | evbuffer_add_printf(server_output, "%s: %s\r\n", 396 | header->key, header->value); 397 | } 398 | evbuffer_add_printf(server_output, "Host: %s\r\n", host); 399 | evbuffer_add_printf(server_output, "Connection: %s\r\n", "close"); 400 | evbuffer_add(server_output, "\r\n", 2); 401 | 402 | #ifndef LIBEVENT_TEST 403 | lwipevbuf_output(server_bev); 404 | #endif 405 | 406 | proxy_req->server_req = server_req; 407 | #ifdef LIBEVENT_TEST 408 | bufferevent_setcb(server_bev, proxy_req_read_firstline, NULL, proxy_req_eventcb, proxy_req); 409 | #else 410 | lwipevbuf_setcb(server_bev, proxy_req_read_firstline, NULL, proxy_req_eventcb, proxy_req); 411 | #endif 412 | /* Queue any data the client already sent */ 413 | evbuffer_add_buffer(server_output, evhttp_request_get_input_buffer(client_req)); 414 | 415 | } else { 416 | struct bufferevent *client_bev; 417 | struct evbuffer *client_output; 418 | 419 | client_bev = evhttp_connection_get_bufferevent(client_evcon); 420 | client_output = bufferevent_get_output(client_bev); 421 | 422 | evbuffer_add_printf(client_output, "HTTP/1.0 200 Connection established\r\n"); 423 | evbuffer_add_printf(client_output, "Proxy-agent: %s/%s\r\n", PACKAGE, VERSION); 424 | evbuffer_add(client_output, "\r\n", 2); 425 | 426 | /* Queue any data the client already sent */ 427 | evbuffer_add_buffer(server_output, evhttp_request_get_input_buffer(client_req)); 428 | 429 | proxy_req_join(proxy_req); 430 | } 431 | } 432 | 433 | static void 434 | #ifndef LIBEVENT_TEST 435 | proxy_req_connectcb(struct lwipevbuf *bev, short what, void *ctx) 436 | #else 437 | proxy_req_connectcb(struct bufferevent *bev, short what, void *ctx) 438 | #endif 439 | { 440 | struct evhttp_proxy_request *proxy_req = ctx; 441 | struct evhttp_request *client_req = proxy_req->client_req; 442 | 443 | if (what & BEV_EVENT_CONNECTED) { 444 | proxy_req_connected(proxy_req); 445 | return; 446 | } 447 | 448 | if (what & BEV_EVENT_TIMEOUT) { 449 | client_send_error(client_req, 403, 450 | "Server communication timed out"); 451 | } else if (what & BEV_EVENT_ERROR) { 452 | int err; 453 | const char *str; 454 | #ifndef LIBEVENT_TEST 455 | err = bev->host_err; 456 | #else 457 | err = bufferevent_socket_get_dns_error(bev); 458 | #endif 459 | if (err) { 460 | #ifdef LIBEVENT_TEST 461 | str = evutil_gai_strerror(err); 462 | #elif defined(LWIP_DEBUG) 463 | str = lwip_strerr(bev->tcp_err); 464 | #else 465 | str = "unspecified"; 466 | #endif 467 | client_send_error(client_req, 500, 468 | "DNS lookup failed: %s"); 469 | } else { 470 | #ifndef LIBEVENT_TEST 471 | err = EVUTIL_SOCKET_ERROR(); 472 | str = evutil_socket_error_to_string(err); 473 | #elif defined(LWIP_DEBUG) 474 | str = lwip_strerr(bev->tcp_err); 475 | #else 476 | str = "unspecified"; 477 | #endif 478 | client_send_error(client_req, 500, 479 | "Connect failed: %s", str); 480 | } 481 | } 482 | 483 | proxy_req_free(proxy_req); 484 | } 485 | 486 | static void 487 | client_request_cb(struct evhttp_request *client_req, void *ctx) 488 | { 489 | struct http_proxy *http = ctx; 490 | const char *scheme; 491 | const char *host; 492 | struct evhttp_connection *client_evcon; 493 | #ifndef LIBEVENT_TEST 494 | struct lwipevbuf *server_bev; 495 | #else 496 | struct bufferevent *server_bev; 497 | struct event_base *base; 498 | #endif 499 | int port; 500 | struct evhttp_proxy_request *proxy_req; 501 | 502 | #ifdef LIBEVENT_TEST 503 | base = evhttp_connection_get_base(client_req->evcon); 504 | #endif 505 | scheme = evhttp_uri_get_scheme(client_req->uri_elems); 506 | client_evcon = evhttp_request_get_connection(client_req); 507 | 508 | port = evhttp_uri_get_port(client_req->uri_elems); 509 | if (scheme && !strcasecmp(scheme, "http")) { 510 | host = evhttp_request_get_host(client_req); 511 | if (port == -1) 512 | port = 80; 513 | } else if (client_req->type == EVHTTP_REQ_CONNECT) { 514 | /* libevent 2.1.8-stable and below do not handle authority strings correctly */ 515 | if (!evhttp_uri_get_host(client_req->uri_elems)) { 516 | char *auth; 517 | if (asprintf(&auth, "//%s/", client_req->uri)) { 518 | } 519 | evhttp_uri_free(client_req->uri_elems); 520 | client_req->uri_elems = evhttp_uri_parse(auth); 521 | free(auth); 522 | if (client_req->host_cache != NULL) { 523 | free(client_req->host_cache); 524 | client_req->host_cache = NULL; 525 | } 526 | } 527 | host = evhttp_request_get_host(client_req); 528 | if (port == -1) 529 | port = 443; 530 | } else { 531 | client_send_error(client_req, 501, "Method not implemented: %s", 532 | evhttp_method(client_req->type)); 533 | return; 534 | } 535 | 536 | #ifndef LIBEVENT_TEST 537 | server_bev = lwipevbuf_new(NULL); 538 | if (http->keep_alive) { 539 | server_bev->pcb->so_options |= SOF_KEEPALIVE; 540 | server_bev->pcb->keep_intvl = http->keep_alive; 541 | server_bev->pcb->keep_idle = http->keep_alive; 542 | } 543 | lwipevbuf_connect_hostname(server_bev, AF_UNSPEC, host, port); 544 | #else 545 | server_bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); 546 | bufferevent_socket_connect_hostname(server_bev, http->dnsbase, AF_UNSPEC, host, port); 547 | bufferevent_enable(server_bev, EV_WRITE|EV_READ); 548 | #endif 549 | proxy_req = calloc(1, sizeof(*proxy_req)); 550 | proxy_req->server_bev = server_bev; 551 | proxy_req->client_req = client_req; 552 | 553 | evhttp_connection_set_closecb(client_evcon, proxy_req_client_closecb, proxy_req); 554 | #ifndef LIBEVENT_TEST 555 | lwipevbuf_setcb(server_bev, NULL, NULL, proxy_req_connectcb, proxy_req); 556 | #else 557 | bufferevent_setcb(server_bev, NULL, NULL, proxy_req_connectcb, proxy_req); 558 | #endif 559 | } 560 | 561 | int http_listen(struct event_base *base, const char *host, const char *port_str, int keep_alive) 562 | { 563 | struct http_proxy *http; 564 | char *endptr; 565 | int port; 566 | int ret; 567 | 568 | port = strtoul(port_str, &endptr, 0); 569 | if (*endptr) 570 | return -1; 571 | 572 | http = calloc(1, sizeof(*http)); 573 | http->evh = evhttp_new(base); 574 | http->keep_alive = keep_alive; 575 | 576 | evhttp_set_max_headers_size(http->evh, 16*1024); 577 | /* evhttp_set_timeout(http->evh, 3); */ 578 | evhttp_set_allowed_methods(http->evh, 579 | EVHTTP_REQ_GET | 580 | EVHTTP_REQ_POST | 581 | EVHTTP_REQ_HEAD | 582 | EVHTTP_REQ_PUT | 583 | EVHTTP_REQ_DELETE | 584 | EVHTTP_REQ_OPTIONS | 585 | EVHTTP_REQ_TRACE | 586 | EVHTTP_REQ_CONNECT | 587 | EVHTTP_REQ_PATCH); 588 | evhttp_set_gencb(http->evh, client_request_cb, http); 589 | 590 | ret = evhttp_bind_socket(http->evh, host, port); 591 | if (ret < 0) { 592 | evhttp_free(http->evh); 593 | #ifdef LIBEVENT_TEST 594 | evdns_free(http->dnsbase); 595 | #endif 596 | free(http); 597 | } 598 | return ret; 599 | } 600 | 601 | #ifdef LIBEVENT_TEST 602 | int main(void) 603 | { 604 | struct event_base *base; 605 | int ret; 606 | int port = 8555; 607 | 608 | base = event_base_new(); 609 | ret = http_listen(base, port); 610 | if (ret < 0) 611 | return 1; 612 | event_base_dispatch(base); 613 | 614 | return 0; 615 | } 616 | #endif 617 | -------------------------------------------------------------------------------- /src/http/server.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "http/http_server.h" 15 | 16 | static void 17 | file_request_cb(struct evhttp_request *req, void *ctx) 18 | { 19 | const char *path = ctx; 20 | struct evbuffer *buffer; 21 | int fd; 22 | struct stat st; 23 | 24 | fd = open(path, O_RDONLY); 25 | if (fd < 0) { 26 | if (errno == ENOENT) 27 | evhttp_send_error(req, HTTP_NOTFOUND, strerror(errno)); 28 | else 29 | evhttp_send_error(req, HTTP_INTERNAL, strerror(errno)); 30 | return; 31 | } 32 | 33 | if (fstat(fd, &st) < 0) { 34 | evhttp_send_error(req, HTTP_INTERNAL, strerror(errno)); 35 | close(fd); 36 | return; 37 | } 38 | 39 | buffer = evbuffer_new(); 40 | evbuffer_add_file(buffer, fd, 0, st.st_size); 41 | 42 | evhttp_add_header(evhttp_request_get_output_headers(req), 43 | "Content-Type", "application/x-ns-proxy-autoconfig"); 44 | evhttp_send_reply(req, HTTP_OK, "OK", buffer); 45 | evbuffer_free(buffer); 46 | } 47 | 48 | int http_server_listen(struct event_base *base, const char *port_str, const char *path) 49 | { 50 | struct evhttp *evh; 51 | char *path_copy; 52 | char *endptr; 53 | int port; 54 | int ret; 55 | 56 | port = strtoul(port_str, &endptr, 0); 57 | if (*endptr) 58 | return -1; 59 | 60 | evh = evhttp_new(base); 61 | path_copy = strdup(path); 62 | 63 | evhttp_set_max_headers_size(evh, 16*1024); 64 | evhttp_set_allowed_methods(evh, EVHTTP_REQ_GET); 65 | evhttp_set_cb(evh, "/", file_request_cb, path_copy); 66 | evhttp_set_cb(evh, "/wpad.dat", file_request_cb, path_copy); 67 | evhttp_set_cb(evh, "/proxy.pac", file_request_cb, path_copy); 68 | 69 | ret = evhttp_bind_socket(evh, "localhost", port); 70 | if (ret < 0) { 71 | evhttp_free(evh); 72 | free(path_copy); 73 | } 74 | return ret; 75 | } 76 | 77 | #ifdef LIBEVENT_TEST 78 | int main(void) 79 | { 80 | struct event_base *base; 81 | int ret; 82 | int port = 8555; 83 | 84 | base = event_base_new(); 85 | ret = http_server_listen(base, port); 86 | if (ret < 0) 87 | return 1; 88 | event_base_dispatch(base); 89 | 90 | return 0; 91 | } 92 | #endif 93 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "socks.h" 14 | #include "http/http.h" 15 | #include "http/http_server.h" 16 | #include "util/host.h" 17 | #include "forward_local.h" 18 | #include "forward_remote.h" 19 | #include "nat.h" 20 | 21 | #include "nat/nat.h" 22 | 23 | #include "util/pcap.h" 24 | #include "util/nettest.h" 25 | #include "util/libevent.h" 26 | 27 | #include "netif/fdif.h" 28 | #include "netif/slirpif.h" 29 | #include "netif/udptapif.h" 30 | #include "netif/vdeportif.h" 31 | #include "netif/vdeswitchif.h" 32 | #include "netif/tunif.h" 33 | 34 | struct conn_info { 35 | char *bind; 36 | char *bind_port; 37 | char *host; 38 | char *host_port; 39 | struct conn_info *next; 40 | }; 41 | 42 | struct pcap_entry { 43 | char *file; 44 | char *netif; 45 | struct pcap_entry *next; 46 | }; 47 | 48 | static char *tokenize(const char *str, const char *sep, char **endptr) 49 | { 50 | int i; 51 | 52 | /* left strip */ 53 | while (str[0] && strchr(sep, str[0])) 54 | str++; 55 | 56 | if (!str[0]) 57 | return NULL; 58 | 59 | for (i = 0; str[i] && !strchr(sep, str[i]); i++); 60 | 61 | *endptr = (char *) str + i; 62 | 63 | return strndup(str, i); 64 | } 65 | 66 | static struct conn_info *parse_conn_info(const char *str, int fmin, int fmax) 67 | { 68 | int fields = 1; 69 | int f0; 70 | const char *field[4] = {NULL, NULL, NULL, NULL}; 71 | struct conn_info *info; 72 | 73 | for (field[0] = str; *str; str++) 74 | if (*str == ':') { 75 | if (fields == fmax) 76 | return NULL; 77 | field[fields] = str + 1; 78 | fields++; 79 | } 80 | 81 | if (fields < fmin) 82 | return NULL; 83 | 84 | info = calloc(1, sizeof(*info)); 85 | 86 | /* Bind address is the leading optional field */ 87 | if (fields > fmin) { 88 | f0 = 1; 89 | fields--; 90 | info->bind = strndup(field[0], field[1] - field[0] - 1); 91 | } else { 92 | f0 = 0; 93 | info->bind = NULL; 94 | } 95 | 96 | info->bind_port = strndup(field[f0], field[f0 + 1] - field[f0] - 1); 97 | 98 | if (fields >= 2) 99 | info->host = strndup(field[f0 + 1], 100 | field[f0 + 2] - field[f0 + 1] - 1); 101 | else 102 | info->host = NULL; 103 | 104 | if (fields >= 3) { 105 | if (f0) 106 | info->host_port = strdup(field[f0 + 2]); 107 | else 108 | info->host_port = strndup(field[f0 + 2], 109 | field[f0 + 3] - field[f0 + 2] - 1); 110 | } else 111 | info->host_port = strdup(info->bind_port); 112 | 113 | return info; 114 | } 115 | 116 | static void free_conn_info(struct conn_info *info) 117 | { 118 | free(info->bind); 119 | free(info->bind_port); 120 | free(info->host); 121 | free(info->host_port); 122 | free(info); 123 | } 124 | 125 | static void print_usage(const char *argv0) 126 | { 127 | fprintf(stderr, 128 | "usage: %s \n\n" 129 | " -L [bind_address:]bind_port:host_address:host_port\n" 130 | " -D [bind_address:]bind_port SOCKS4a/5 proxy\n" 131 | " -H [bind_address:]bind_port HTTP proxy\n" 132 | " -P proxy_pac_file:bind_port HTTP server for proxy.pac\n" 133 | " -R bind_port:host_address:host_port\n" 134 | " -g Allow non-local clients (command line compatibility for ocproxy)\n" 135 | " -k keep alive interval (seconds)\n" 136 | " -m mtu (env INTERNAL_IP4_MTU)\n" 137 | " -s domain_search[,domain_search,...] (env CISCO_DEF_DOMAIN)\n" 138 | " -d dns,[dns,...] (env INTERNAL_IP4_DNS)\n" 139 | " -i ip address (env INTERNAL_IP4_ADDRESS)\n" 140 | " -n netmask\n" 141 | " -G gateway\n" 142 | " -S (Use slirp interface instead VPN, useful for testing)\n" 143 | " -l Add deLay (in ms) to inbound/outbound packets (useful for testing)\n" 144 | " -o DrOp probability ([0.0..1.0]) for inbound/outbound (useful for testing)\n" 145 | #ifdef USE_PCAP 146 | " -p pcap_file[:netif] (Default netif 'fd', VPN input)\n" 147 | #endif 148 | " -u port (UDP listener port of TAP NAT with no length header, netif=ut)\n" 149 | " -U port (UDP listener port of TAP NAT with 2 byte length header, netif=ut)\n" 150 | " -v VDE path (Connect NAT to a VDE switch. netif=vp)\n" 151 | " -V VDE path (Expose NAT via a reduced functionality VDE switch. netif=vs)\n" 152 | " -t tun name (Expose NAT via a PTP TUN device. netif=tu)\n" 153 | " -T tap name (Expose NAT via a TAP device with DHCP. netif=ta)\n" 154 | "\n", basename((char *) argv0)); 155 | exit(1); 156 | } 157 | 158 | int main(int argc, char *argv[]) 159 | { 160 | int c; 161 | int keep_alive; 162 | int non_local; 163 | struct netif *netif; 164 | int dns_count; 165 | char *str; 166 | char *endptr; 167 | char *vdeswitch; 168 | char *vdeport; 169 | char *tunname; 170 | char *tapname; 171 | int mtu; 172 | int use_slirp; 173 | unsigned int delay_ms; 174 | float drop; 175 | unsigned short nat_port_raw; 176 | unsigned short nat_port_len; 177 | int fd_in; 178 | int fd_out; 179 | ip_addr_t ipaddr; 180 | ip_addr_t netmask; 181 | ip_addr_t gateway; 182 | ip_addr_t dns; 183 | #if LWIP_IPV4 184 | ip_addr_t ipaddr4; 185 | ip_addr_t netmask4; 186 | ip_addr_t gateway4; 187 | #endif 188 | #if LWIP_IPV6 189 | ip_addr_t ipaddr6; 190 | ip_addr_t netmask6; 191 | ip_addr_t gateway6; 192 | #endif 193 | struct event_base *base; 194 | #ifdef USE_PCAP 195 | struct pcap_entry *pcap_entries, *pcap_entry; 196 | #endif 197 | struct conn_info *local; 198 | struct conn_info *remote; 199 | struct conn_info *socks; 200 | struct conn_info *http; 201 | struct conn_info *http_server; 202 | struct conn_info *info; 203 | 204 | #if LWIP_IPV4 205 | IP4_ADDR(&ipaddr4, 10, 0, 3, 1); 206 | IP4_ADDR(&netmask4, 255, 255, 255, 0); 207 | ip_addr_set_zero(&gateway4); 208 | #endif 209 | #if LWIP_IPV6 210 | ip_addr_set_zero(&ipaddr6); 211 | ip_addr_set_zero(&netmask6); 212 | ip_addr_set_zero(&gateway6); 213 | #endif 214 | 215 | local = remote = socks = http = http_server = NULL; 216 | dns_count = 0; 217 | keep_alive = 0; 218 | use_slirp = 0; 219 | delay_ms = 0; 220 | drop = 0.0; 221 | fd_in = 0; 222 | fd_out = 1; 223 | mtu = 0; 224 | #ifdef USE_PCAP 225 | pcap_entries = NULL; 226 | #endif 227 | non_local = 0; 228 | nat_port_raw = 0; 229 | nat_port_len = 0; 230 | vdeswitch = NULL; 231 | vdeport = NULL; 232 | tunname = NULL; 233 | tapname = NULL; 234 | 235 | signal(SIGPIPE, SIG_IGN); 236 | 237 | base = event_base_new(); 238 | lwip_init(); 239 | libevent_timeouts_init(base); 240 | #if LWIP_NAT 241 | sys_timer_add_internal(base, LWIP_NAT_TICK_PERIOD_MS, nat_timer_tick); 242 | #endif 243 | 244 | 245 | #if LWIP_IPV4 246 | if ((str = getenv("INTERNAL_IP4_ADDRESS"))) 247 | ip4addr_aton(str, ip_2_ip4(&ipaddr4)); 248 | 249 | if ((str = getenv("INTERNAL_IP4_NETMASK"))) 250 | ip4addr_aton(str, ip_2_ip4(&netmask4)); 251 | 252 | if ((str = getenv("INTERNAL_IP4_DNS"))) { 253 | endptr = str; 254 | while ((str = tokenize(endptr, ", ", &endptr))) { 255 | ip4addr_aton(str, ip_2_ip4(&dns)); 256 | dns_setserver(dns_count++, &dns); 257 | free(str); 258 | } 259 | } 260 | #endif 261 | 262 | if ((str = getenv("INTERNAL_IP4_MTU"))) 263 | mtu = strtoul(str, NULL, 0); 264 | 265 | #if LWIP_IPV6 266 | if ((str = getenv("INTERNAL_IP6_ADDRESS"))) 267 | ip6addr_aton(str, ip_2_ip6(&ipaddr6)); 268 | 269 | if ((str = getenv("INTERNAL_IP6_NETMASK"))) 270 | ip6addr_aton(str, ip_2_ip6(&netmask6)); 271 | 272 | if ((str = getenv("INTERNAL_IP6_DNS"))) { 273 | endptr = str; 274 | while ((str = tokenize(endptr, ", ", &endptr))) { 275 | ip6addr_aton(str, ip_2_ip6(&dns)); 276 | dns_setserver(dns_count++, &dns); 277 | free(str); 278 | } 279 | } 280 | #endif 281 | 282 | if ((str = getenv("VPNFD"))) 283 | fd_in = fd_out = strtoul(str, NULL, 0); 284 | 285 | if ((str = getenv("CISCO_DEF_DOMAIN"))) { 286 | endptr = str; 287 | while ((str = tokenize(endptr, ", ", &endptr))) 288 | host_add_search(str); 289 | } 290 | 291 | while ((c = getopt(argc, argv, "Sl:o:L:D:H:P:R:k:m:s:d:i:n:G:p:gu:U:v:V:t:T:h")) != -1) { 292 | 293 | switch (c) { 294 | case 'S': 295 | use_slirp = 1; 296 | break; 297 | case 'l': 298 | delay_ms = strtoul(optarg, &endptr, 0); 299 | if (*endptr) 300 | print_usage(argv[0]); 301 | break; 302 | case 'o': 303 | drop = strtof(optarg, &endptr); 304 | if (*endptr || !(drop >= 0.0 && drop <= 1.0)) 305 | print_usage(argv[0]); 306 | break; 307 | case 'L': 308 | info = parse_conn_info(optarg, 3, 4); 309 | if (!info) 310 | print_usage(argv[0]); 311 | 312 | info->next = local; 313 | local = info; 314 | break; 315 | case 'D': 316 | info = parse_conn_info(optarg, 1, 2); 317 | if (!info) 318 | print_usage(argv[0]); 319 | 320 | info->next = socks; 321 | socks = info; 322 | break; 323 | case 'H': 324 | info = parse_conn_info(optarg, 1, 2); 325 | if (!info) 326 | print_usage(argv[0]); 327 | 328 | info->next = http; 329 | http = info; 330 | break; 331 | case 'P': 332 | info = parse_conn_info(optarg, 2, 2); 333 | if (!info) 334 | print_usage(argv[0]); 335 | 336 | info->next = http_server; 337 | http_server = info; 338 | break; 339 | case 'R': 340 | info = parse_conn_info(optarg, 3, 3); 341 | if (!info) 342 | print_usage(argv[0]); 343 | 344 | info->next = remote; 345 | remote = info; 346 | break; 347 | case 'k': 348 | keep_alive = strtoul(optarg, &endptr, 0); 349 | if (*endptr) 350 | print_usage(argv[0]); 351 | keep_alive *= 1000; 352 | break; 353 | case 'm': 354 | mtu = strtoul(optarg, &endptr, 0); 355 | if (*endptr) 356 | print_usage(argv[0]); 357 | break; 358 | case 's': 359 | while ((str = tokenize(optarg, ", ", &optarg))) 360 | host_add_search(str); 361 | break; 362 | case 'd': 363 | while ((str = tokenize(optarg, ", ", &optarg))) { 364 | if (!ip4addr_aton(str, &dns)) 365 | print_usage(argv[0]); 366 | dns_setserver(dns_count++, &dns); 367 | free(str); 368 | } 369 | break; 370 | case 'i': 371 | if (!ipaddr_aton(optarg, &ipaddr)) 372 | print_usage(argv[0]); 373 | #if LWIP_IPV4 374 | if (IP_IS_V4(&ipaddr)) 375 | ip_addr_copy(ipaddr4, ipaddr); 376 | #endif 377 | #if LWIP_IPV6 378 | if (IP_IS_V6(&ipaddr)) 379 | ip_addr_copy(ipaddr6, ipaddr); 380 | #endif 381 | break; 382 | case 'n': 383 | if (!ipaddr_aton(optarg, &netmask)) 384 | print_usage(argv[0]); 385 | #if LWIP_IPV4 386 | if (IP_IS_V4(&netmask)) 387 | ip_addr_copy(netmask4, netmask); 388 | #endif 389 | #if LWIP_IPV6 390 | if (IP_IS_V6(&netmask)) 391 | ip_addr_copy(netmask6, netmask); 392 | #endif 393 | break; 394 | case 'G': 395 | if (!ipaddr_aton(optarg, &gateway)) 396 | print_usage(argv[0]); 397 | #if LWIP_IPV4 398 | if (IP_IS_V4(&gateway)) 399 | ip_addr_copy(gateway4, gateway); 400 | #endif 401 | #if LWIP_IPV6 402 | if (IP_IS_V6(&gateway)) 403 | ip_addr_copy(gateway6, gateway); 404 | #endif 405 | break; 406 | #ifdef USE_PCAP 407 | case 'p': 408 | pcap_entry = calloc(1, sizeof(*pcap_entry)); 409 | pcap_entry->next = pcap_entries; 410 | pcap_entries = pcap_entry; 411 | pcap_entry->file = strdup(optarg); 412 | pcap_entry->netif = strchr(pcap_entry->file, ':'); 413 | if (pcap_entry->netif) { 414 | pcap_entry->netif[0] = '\0'; 415 | pcap_entry->netif++; 416 | } 417 | break; 418 | #endif 419 | case 'g': 420 | non_local = 1; 421 | break; 422 | case 'u': 423 | nat_port_raw = strtoul(optarg, &endptr, 0); 424 | if (*endptr) 425 | print_usage(argv[0]); 426 | break; 427 | case 'U': 428 | nat_port_len = strtoul(optarg, &endptr, 0); 429 | if (*endptr) 430 | print_usage(argv[0]); 431 | break; 432 | case 'v': 433 | vdeport = strdup(optarg); 434 | break; 435 | case 'V': 436 | vdeswitch = strdup(optarg); 437 | break; 438 | case 't': 439 | tunname = strdup(optarg); 440 | break; 441 | case 'T': 442 | tapname = strdup(optarg); 443 | break; 444 | default: 445 | print_usage(argv[0]); 446 | } 447 | } 448 | 449 | while (local) { 450 | info = local; 451 | str = info->bind && info->bind[0] ? info->bind : NULL; 452 | if (!non_local) 453 | str = str ? : "localhost"; 454 | 455 | if (forward_local(base, str, info->bind_port, 456 | info->host, info->host_port, keep_alive) < 0) 457 | return -1; 458 | 459 | local = info->next; 460 | free_conn_info(info); 461 | } 462 | 463 | while (socks) { 464 | info = socks; 465 | str = info->bind && info->bind[0] ? info->bind : NULL; 466 | if (!non_local) 467 | str = str ? : "localhost"; 468 | if (socks_listen(base, str, info->bind_port, keep_alive) < 0) 469 | return -1; 470 | socks = socks->next; 471 | free_conn_info(info); 472 | } 473 | 474 | while (http) { 475 | info = http; 476 | str = info->bind && info->bind[0] ? info->bind : NULL; 477 | if (!non_local) 478 | str = str ? : "localhost"; 479 | if (http_listen(base, str, info->bind_port, keep_alive) < 0) 480 | return -1; 481 | http = http->next; 482 | free_conn_info(info); 483 | } 484 | 485 | while (http_server) { 486 | info = http_server; 487 | if (http_server_listen(base, info->host, info->bind_port) < 0) 488 | return -1; 489 | http_server = http_server->next; 490 | free_conn_info(info); 491 | } 492 | 493 | while (remote) { 494 | info = remote; 495 | if (forward_remote(base, info->bind_port, info->host, 496 | info->host_port, keep_alive) < 0) 497 | return -1; 498 | remote = info->next; 499 | free_conn_info(info); 500 | } 501 | 502 | /* "External" interface */ 503 | if (use_slirp) 504 | netif = slirpif_add(base); 505 | else 506 | netif = fdif_add(base, fd_in, fd_out, 0); 507 | netif_set_default(netif); 508 | 509 | netif_set_ipaddr(netif, &ipaddr4); 510 | netif_set_netmask(netif, &netmask4); 511 | netif_set_gw(netif, &gateway4); 512 | if (mtu) 513 | netif->mtu = mtu; 514 | 515 | if (nat_port_raw || nat_port_len) { 516 | struct netif *natif; 517 | natif = udptapif_add(base, nat_port_raw, nat_port_len); 518 | if (!natif) 519 | return -1; 520 | IP4_ADDR(&ipaddr4, 10, 0, 4, 1); 521 | IP4_ADDR(&netmask4, 255, 255, 255, 0); 522 | netif_set_ipaddr(natif, &ipaddr4); 523 | netif_set_netmask(natif, &netmask4); 524 | if (nat_add(netif, natif) < 0) 525 | return -1; 526 | netif_set_up(natif); 527 | } 528 | 529 | if (vdeport) { 530 | struct netif *vportif; 531 | vportif = vdeportif_add(base, vdeport); 532 | if (!vportif) 533 | return -1; 534 | IP4_ADDR(&ipaddr4, 10, 0, 5, 1); 535 | IP4_ADDR(&netmask4, 255, 255, 255, 0); 536 | netif_set_ipaddr(vportif, &ipaddr4); 537 | netif_set_netmask(vportif, &netmask4); 538 | if (nat_add(netif, vportif) < 0) 539 | return -1; 540 | netif_set_up(vportif); 541 | } 542 | 543 | if (vdeswitch) { 544 | struct netif *vswitchif; 545 | vswitchif = vdeswitchif_add(base, vdeswitch); 546 | if (!vswitchif) 547 | return -1; 548 | IP4_ADDR(&ipaddr4, 10, 0, 6, 1); 549 | IP4_ADDR(&netmask4, 255, 255, 255, 0); 550 | netif_set_ipaddr(vswitchif, &ipaddr4); 551 | netif_set_netmask(vswitchif, &netmask4); 552 | if (nat_add(netif, vswitchif) < 0) 553 | return -1; 554 | netif_set_up(vswitchif); 555 | } 556 | 557 | if (tunname) { 558 | struct netif *tunif; 559 | tunif = tunif_add(base, tunname, 0); 560 | if (!tunif) 561 | return -1; 562 | IP4_ADDR(&ipaddr4, 10, 0, 7, 1); 563 | IP4_ADDR(&netmask4, 255, 255, 255, 255); 564 | netif_set_ipaddr(tunif, &ipaddr4); 565 | netif_set_netmask(tunif, &netmask4); 566 | if (nat_add(netif, tunif) < 0) 567 | return -1; 568 | netif_set_up(tunif); 569 | } 570 | 571 | if (tapname) { 572 | struct netif *tapif; 573 | tapif = tunif_add(base, tapname, 0); 574 | if (!tapif) 575 | return -1; 576 | IP4_ADDR(&ipaddr4, 10, 0, 8, 1); 577 | IP4_ADDR(&netmask4, 255, 255, 255, 0); 578 | netif_set_ipaddr(tapif, &ipaddr4); 579 | netif_set_netmask(tapif, &netmask4); 580 | if (nat_add(netif, tapif) < 0) 581 | return -1; 582 | netif_set_up(tapif); 583 | } 584 | 585 | #ifdef USE_PCAP 586 | for (pcap_entry = pcap_entries; pcap_entry; pcap_entry = pcap_entry->next) { 587 | const char *name = pcap_entry->netif; 588 | struct netif *pcapif = NULL; 589 | if (strlen(name) == 2) { 590 | NETIF_FOREACH(pcapif) { 591 | if (name[0] == pcapif->name[0] && name[1] == pcapif->name[1]) 592 | break; 593 | } 594 | } else if (strlen(name) > 2) 595 | pcapif = netif_find(name); 596 | 597 | if (!pcapif) { 598 | fprintf(stderr, "Could not find netif: '%s'\n", name); 599 | print_usage(argv[0]); 600 | } 601 | if (pcap_dump_add(pcapif, pcap_entry->file) < 0) 602 | return -1; 603 | } 604 | #endif 605 | 606 | if (delay_ms || drop != 0.0) 607 | nettest_add(base, netif, delay_ms, drop); 608 | 609 | netif_set_up(netif); 610 | event_base_dispatch(base); 611 | 612 | return 0; 613 | } 614 | -------------------------------------------------------------------------------- /src/nat.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "nat/nat.h" 4 | #include "dhcp_server.h" 5 | 6 | int 7 | nat_add(struct netif *out_if, struct netif *in_if) 8 | { 9 | struct nat_rule *rule; 10 | err_t ret; 11 | 12 | if (in_if->flags & (NETIF_FLAG_ETHERNET | NETIF_FLAG_ETHARP)) { 13 | if (dhcp_server_add(in_if) < 0) 14 | return -1; 15 | } 16 | 17 | rule = calloc(1, sizeof(*rule)); 18 | rule->inp = in_if; 19 | rule->outp = out_if; 20 | ret = nat_rule_add(rule); 21 | if (ret < 0) 22 | free(rule); 23 | 24 | return ret; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/nat.h: -------------------------------------------------------------------------------- 1 | #ifndef __NAT_H__ 2 | #define __NAT_H__ 3 | 4 | struct netif; 5 | 6 | int nat_add(struct netif *out_if, struct netif *in_if); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/socks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "socks.h" 15 | #include "socks4.h" 16 | #include "socks5.h" 17 | #include "util/host.h" 18 | #include "container_of.h" 19 | #include "util/sockaddr.h" 20 | #include "util/lwipevbuf.h" 21 | 22 | void 23 | socks_kill(struct socks_data *data) 24 | { 25 | if (data->bev) { 26 | bufferevent_free(data->bev); 27 | data->bev = NULL; 28 | } 29 | host_abort(&data->host); 30 | if (data->lwipevbuf) { 31 | lwipevbuf_free(data->lwipevbuf); 32 | data->lwipevbuf = NULL; 33 | } 34 | #if LWIP_IPV4 35 | if (data->listen_pcb4) { 36 | tcp_err(data->listen_pcb4, NULL); 37 | tcp_abort(data->listen_pcb4); 38 | data->listen_pcb4 = NULL; 39 | } 40 | if (data->upcb4) { 41 | udp_remove(data->upcb4); 42 | data->upcb4 = NULL; 43 | } 44 | #endif 45 | #if LWIP_IPV6 46 | if (data->listen_pcb6) { 47 | tcp_err(data->listen_pcb6, NULL); 48 | tcp_abort(data->listen_pcb6); 49 | data->listen_pcb6 = NULL; 50 | } 51 | if (data->upcb6) { 52 | udp_remove(data->upcb6); 53 | data->upcb6 = NULL; 54 | } 55 | #endif 56 | if (data->udp_event) { 57 | event_free(data->udp_event); 58 | data->udp_event = NULL; 59 | } 60 | if (data->udp_pbuf) { 61 | pbuf_free(data->udp_pbuf); 62 | data->udp_pbuf = NULL; 63 | } 64 | data->kill(data); 65 | } 66 | 67 | static void 68 | bufferevent_finish_writecb(struct bufferevent *bev, void *ctx) 69 | { 70 | struct evbuffer *buf = bufferevent_get_output(bev); 71 | if (!evbuffer_get_length(buf)) 72 | bufferevent_free(bev); 73 | } 74 | 75 | static void 76 | bufferevent_finish_eventcb(struct bufferevent *bev, short events, void *ctx) 77 | { 78 | if (events & (BEV_EVENT_ERROR|BEV_EVENT_EOF)) 79 | bufferevent_free(bev); 80 | } 81 | 82 | static void 83 | bufferevent_finish(struct bufferevent *bev) 84 | { 85 | bufferevent_disable(bev, EV_READ); 86 | bufferevent_setwatermark(bev, EV_WRITE, 0, 0); 87 | bufferevent_setcb(bev, NULL, bufferevent_finish_writecb, 88 | bufferevent_finish_eventcb, NULL); 89 | bufferevent_finish_writecb(bev, NULL); 90 | } 91 | 92 | void 93 | socks_flush(struct socks_data *data) 94 | { 95 | bufferevent_finish(data->bev); 96 | data->bev = NULL; 97 | socks_kill(data); 98 | } 99 | 100 | static void 101 | socks_udp_recv(void *priv, struct udp_pcb *pcb, struct pbuf *p, 102 | const ip_addr_t *addr, u16_t port) 103 | { 104 | struct socks_data *data = priv; 105 | data->udp_recv(data, p, addr, port); 106 | pbuf_free(p); 107 | } 108 | 109 | static void 110 | socks_udp_read(const int fd, short int method, void *priv) 111 | { 112 | struct socks_data *data = priv; 113 | struct pbuf *p = data->udp_pbuf; 114 | unsigned int offset; 115 | int len; 116 | 117 | offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + 118 | PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; 119 | 120 | /* Reset the pbuf and allocate network header space */ 121 | p->len = p->tot_len = data->udp_pbuf_len; 122 | p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + 123 | LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + offset)); 124 | 125 | len = recv(fd, p->payload, p->len, 0); 126 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: read %d bytes of udp from client\n", __func__, len)); 127 | if (len < 0) { 128 | if (errno == EAGAIN || errno == EINTR) 129 | return; 130 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: UDP read error\n", __func__)); 131 | return; 132 | } 133 | p->len = p->tot_len = len; 134 | data->udp_send(data, p); 135 | } 136 | 137 | struct udp_pcb * 138 | socks_udp_bind_pcb(struct socks_data *data, const ip_addr_t *ipaddr) 139 | { 140 | struct udp_pcb *pcb = udp_new(); 141 | if (!pcb) 142 | return NULL; 143 | 144 | if (udp_bind(pcb, ipaddr, data->port) < 0) { 145 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: udp_bind failed\n", __func__)); 146 | udp_remove(pcb); 147 | return NULL; 148 | } 149 | 150 | udp_recv(pcb, socks_udp_recv, data); 151 | 152 | return pcb; 153 | } 154 | 155 | int 156 | socks_udp_bind(struct event_base *base, struct socks_data *data) 157 | { 158 | struct event *event; 159 | struct sockaddr addr; 160 | socklen_t addrlen; 161 | int fd; 162 | int success = 0; 163 | 164 | memcpy(&addr, &data->server->addr, data->server->addr_len); 165 | if (addr.sa_family == AF_INET) 166 | ((struct sockaddr_in *) &addr)->sin_port = 0; 167 | else if (addr.sa_family == AF_INET6) 168 | ((struct sockaddr_in6 *) &addr)->sin6_port = 0; 169 | else { 170 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: Invalid address family\n", __func__)); 171 | return -1; 172 | } 173 | 174 | fd = socket(addr.sa_family, SOCK_DGRAM|O_NONBLOCK, IPPROTO_UDP); 175 | if (fd < 0) { 176 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: socket %m\n", __func__)); 177 | return -1; 178 | } 179 | 180 | if (bind(fd, &addr, data->server->addr_len) < 0) { 181 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: bind %m\n", __func__)); 182 | close(fd); 183 | return -1; 184 | } 185 | 186 | memset(&addr, 0, sizeof(addr)); 187 | addrlen = sizeof(addr); 188 | if (getsockname(fd, &addr, &addrlen) < 0) { 189 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: getsockname %m\n", __func__)); 190 | close(fd); 191 | return -1; 192 | } 193 | 194 | if (addr.sa_family == AF_INET) 195 | data->udp_port = 196 | ntohs(((struct sockaddr_in *) &addr)->sin_port); 197 | else if (addr.sa_family == AF_INET6) 198 | data->udp_port = 199 | ntohs(((struct sockaddr_in6 *) &addr)->sin6_port); 200 | 201 | addrlen = sizeof(addr); 202 | if (ip_addr_to_sockaddr(&data->ipaddr, data->port, &addr, &addrlen) < 0) { 203 | close(fd); 204 | return -1; 205 | } 206 | 207 | if (connect(fd, &addr, addrlen) < 0) { 208 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: connect %m\n", __func__)); 209 | close(fd); 210 | return -1; 211 | } 212 | 213 | event = event_new(base, fd, EV_READ|EV_PERSIST, socks_udp_read, data); 214 | event_add(event, NULL); 215 | 216 | #if LWIP_IPV4 217 | data->upcb4 = socks_udp_bind_pcb(data, IP4_ADDR_ANY); 218 | if (data->upcb4) 219 | success = 1; 220 | #endif 221 | #if LWIP_IPV6 222 | data->upcb6 = socks_udp_bind_pcb(data, IP6_ADDR_ANY); 223 | if (data->upcb6) 224 | success = 1; 225 | #endif 226 | 227 | if (!success) { 228 | event_free(event); 229 | close(fd); 230 | return -1; 231 | } 232 | 233 | data->udp_pbuf = pbuf_alloc(PBUF_RAW, 2048, PBUF_RAM); 234 | data->udp_pbuf_len = 2048; 235 | data->udp_fd = fd; 236 | data->udp_event = event; 237 | 238 | return 0; 239 | } 240 | 241 | static err_t 242 | socks_tcp_accept(void *ctx, struct tcp_pcb *pcb, err_t err) 243 | { 244 | struct socks_data *data = ctx; 245 | 246 | if (err < 0) { 247 | socks_kill(data); 248 | return err; 249 | } 250 | 251 | #if LWIP_IPV4 252 | tcp_abort(data->listen_pcb4); 253 | data->listen_pcb4 = NULL; 254 | #endif 255 | #if LWIP_IPV6 256 | tcp_abort(data->listen_pcb6); 257 | data->listen_pcb6 = NULL; 258 | #endif 259 | 260 | data->lwipevbuf = lwipevbuf_new(pcb); 261 | 262 | if (data->server->keep_alive) { 263 | pcb->so_options |= SOF_KEEPALIVE; 264 | pcb->keep_intvl = data->server->keep_alive; 265 | pcb->keep_idle = data->server->keep_alive; 266 | } 267 | 268 | data->connect_ok(data); 269 | 270 | return ERR_OK; 271 | } 272 | 273 | static struct tcp_pcb * 274 | socks_tcp_listen(struct socks_data *data, const ip_addr_t *ipaddr) 275 | { 276 | struct tcp_pcb *pcb, *listen_pcb; 277 | err_t ret; 278 | 279 | pcb = tcp_new(); 280 | if (!pcb) 281 | return NULL; 282 | 283 | ip_set_option(pcb, SOF_REUSEADDR); 284 | 285 | /* FIXME: Listen on both when dual stack */ 286 | ret = tcp_bind(pcb, ipaddr, data->port); 287 | if (ret < 0) { 288 | tcp_abort(pcb); 289 | return NULL; 290 | } 291 | 292 | listen_pcb = tcp_listen(pcb); 293 | if (!listen_pcb) { 294 | tcp_abort(pcb); 295 | return NULL; 296 | } 297 | 298 | tcp_arg(listen_pcb, data); 299 | tcp_accept(listen_pcb, socks_tcp_accept); 300 | 301 | return listen_pcb; 302 | } 303 | 304 | int 305 | socks_tcp_bind(struct socks_data *data) 306 | { 307 | int ret = -1; 308 | #if LWIP_IPV4 309 | data->listen_pcb4 = socks_tcp_listen(data, IP4_ADDR_ANY); 310 | if (data->listen_pcb4) 311 | ret = 0; 312 | #endif 313 | #if LWIP_IPV6 314 | data->listen_pcb6 = socks_tcp_listen(data, IP6_ADDR_ANY); 315 | if (data->listen_pcb6) 316 | ret = 0; 317 | #endif 318 | 319 | return ret; 320 | } 321 | 322 | static void 323 | socks_tcp_eventcb(struct lwipevbuf *bev, short what, void *ctx) 324 | { 325 | struct socks_data *data = ctx; 326 | 327 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s\n", __func__)); 328 | 329 | if (what & BEV_EVENT_CONNECTED) { 330 | data->connect_ok(data); 331 | } else { 332 | lwipevbuf_free(data->lwipevbuf); 333 | data->lwipevbuf = NULL; 334 | data->connect_failed(data); 335 | } 336 | } 337 | 338 | static void 339 | socks_tcp_connect_init(struct socks_data *data) 340 | { 341 | struct lwipevbuf *lwipevbuf; 342 | 343 | bufferevent_disable(data->bev, EV_READ); 344 | lwipevbuf = lwipevbuf_new(NULL); 345 | if (data->server->keep_alive) { 346 | lwipevbuf->pcb->so_options |= SOF_KEEPALIVE; 347 | lwipevbuf->pcb->keep_intvl = data->server->keep_alive; 348 | lwipevbuf->pcb->keep_idle = data->server->keep_alive; 349 | } 350 | data->lwipevbuf = lwipevbuf; 351 | 352 | lwipevbuf_setcb(lwipevbuf, NULL, NULL, socks_tcp_eventcb, data); 353 | } 354 | 355 | void 356 | socks_tcp_connect(struct socks_data *data) 357 | { 358 | struct sockaddr addr; 359 | socklen_t addrlen; 360 | 361 | socks_tcp_connect_init(data); 362 | 363 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: %s:%d\n", __func__, 364 | ipaddr_ntoa(&data->ipaddr), data->port)); 365 | 366 | addrlen = sizeof(addr); 367 | ip_addr_to_sockaddr(&data->ipaddr, data->port, &addr, &addrlen); 368 | 369 | lwipevbuf_connect(data->lwipevbuf, &addr, addrlen); 370 | } 371 | 372 | void 373 | socks_tcp_connect_hostname(struct socks_data *data) 374 | { 375 | socks_tcp_connect_init(data); 376 | 377 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: %s:%d\n", __func__, 378 | data->host.fqdn, data->port)); 379 | 380 | lwipevbuf_connect_hostname(data->lwipevbuf, AF_UNSPEC, data->host.fqdn, data->port); 381 | } 382 | 383 | static void 384 | socks_request_eventcb(struct bufferevent *bev, short what, void *ctx) 385 | { 386 | socks_kill(ctx); 387 | } 388 | 389 | static void 390 | socks_request_cb(struct bufferevent *bev, void *ctx) 391 | { 392 | struct socks_data *data = ctx; 393 | 394 | if (evbuffer_get_length(bufferevent_get_input(bev)) < data->req_len) { 395 | bufferevent_enable(bev, EV_READ); 396 | bufferevent_setwatermark(bev, EV_READ, data->req_len, 256*1024); 397 | bufferevent_setcb(bev, socks_request_cb, NULL, 398 | socks_request_eventcb, ctx); 399 | } else 400 | data->req_cb(ctx); 401 | } 402 | 403 | void 404 | socks_request(struct socks_data *data, int n, void (*cb)(struct socks_data*)) 405 | { 406 | data->req_len = n; 407 | data->req_cb = cb; 408 | socks_request_cb(data->bev, data); 409 | } 410 | 411 | static void 412 | socks_version(struct bufferevent *bev, void *ctx) 413 | { 414 | struct socks_server *s = ctx; 415 | u_char version; 416 | 417 | bufferevent_read(bev, &version, 1); 418 | 419 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: socks version %d\n", __func__, version)); 420 | 421 | switch (version) { 422 | #if LWIP_IPV4 423 | case 4: 424 | socks4_start(s, bev); 425 | break; 426 | #endif 427 | case 5: 428 | socks5_start(s, bev); 429 | break; 430 | default: 431 | bufferevent_free(bev); 432 | } 433 | } 434 | 435 | static void 436 | socks_error(struct bufferevent *bev, short events, void *ctx) 437 | { 438 | bufferevent_free(bev); 439 | } 440 | 441 | static void 442 | socks_accept(struct evconnlistener *evl, evutil_socket_t new_fd, 443 | struct sockaddr *addr, int socklen, void *ctx) 444 | { 445 | struct event_base *base = evconnlistener_get_base(evl); 446 | struct bufferevent *bev; 447 | 448 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: Accepting socks connection\n", __func__)); 449 | 450 | bev = bufferevent_socket_new(base, new_fd, BEV_OPT_CLOSE_ON_FREE); 451 | bufferevent_setcb(bev, socks_version, NULL, socks_error, ctx); 452 | bufferevent_setwatermark(bev, EV_READ, 1, 262144); 453 | bufferevent_enable(bev, EV_READ|EV_WRITE); 454 | } 455 | 456 | #ifndef LEV_OPT_DEFERRED_ACCEPT 457 | #define LEV_OPT_DEFERRED_ACCEPT 0 458 | #endif 459 | 460 | int 461 | socks_listen(struct event_base *base, const char *host, const char *port, 462 | int keep_alive) 463 | { 464 | struct evconnlistener *evl; 465 | struct addrinfo hints; 466 | struct addrinfo *result; 467 | struct socks_server *s; 468 | int ret; 469 | 470 | s = malloc(sizeof(*s)); 471 | memset(s, 0, sizeof(*s)); 472 | s->keep_alive = keep_alive; 473 | 474 | memset(&hints, 0, sizeof(hints)); 475 | /* Default to IPv4 if host isn't specified */ 476 | hints.ai_family = host ? AF_UNSPEC : AF_INET; 477 | hints.ai_socktype = SOCK_STREAM; 478 | 479 | ret = getaddrinfo(host, port, &hints, &result); 480 | if (ret < 0) { 481 | fprintf(stderr, "%s: %s\n", __func__, gai_strerror(ret)); 482 | return ret; 483 | } 484 | 485 | memcpy(&s->addr, result->ai_addr, result->ai_addrlen); 486 | s->addr_len = result->ai_addrlen; 487 | 488 | evl = evconnlistener_new_bind(base, socks_accept, (void *) s, 489 | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | 490 | LEV_OPT_REUSEABLE | LEV_OPT_DEFERRED_ACCEPT, 10, 491 | result->ai_addr, result->ai_addrlen); 492 | 493 | freeaddrinfo(result); 494 | 495 | if (!evl) { 496 | perror(__func__); 497 | return -1; 498 | } 499 | 500 | return 0; 501 | } 502 | -------------------------------------------------------------------------------- /src/socks.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOCKS_H__ 2 | #define __SOCKS_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "util/host.h" 8 | 9 | struct event_base; 10 | struct bufferevent; 11 | struct tcp_pcb; 12 | struct udp_pcb; 13 | struct pbuf; 14 | struct lwipevbuf; 15 | 16 | struct socks_server { 17 | int keep_alive; 18 | struct sockaddr_storage addr; 19 | socklen_t addr_len; 20 | }; 21 | 22 | struct socks_data { 23 | struct socks_server *server; 24 | 25 | ip_addr_t ipaddr; 26 | u_int16_t port; 27 | struct host_data host; 28 | struct lwipevbuf *lwipevbuf; 29 | struct bufferevent *bev; 30 | void (*connect_ok)(struct socks_data*); 31 | void (*connect_failed)(struct socks_data*); 32 | void (*kill)(struct socks_data*); 33 | int req_len; 34 | void (*req_cb)(struct socks_data*); 35 | 36 | #if LWIP_IPV4 37 | struct tcp_pcb *listen_pcb4; 38 | struct udp_pcb *upcb4; 39 | #endif 40 | #if LWIP_IPV6 41 | struct tcp_pcb *listen_pcb6; 42 | struct udp_pcb *upcb6; 43 | #endif 44 | 45 | int udp_fd; 46 | u_int16_t udp_port; 47 | void (*udp_recv)(struct socks_data*, struct pbuf*, 48 | const ip_addr_t*, u16_t); 49 | void (*udp_send)(struct socks_data*, struct pbuf*); 50 | struct event *udp_event; /* Provides notification callbacks for linux side */ 51 | struct pbuf *udp_pbuf; 52 | int udp_pbuf_len; 53 | }; 54 | 55 | void socks_kill(struct socks_data *data); 56 | void socks_flush(struct socks_data *data); 57 | int socks_udp_bind(struct event_base *base, struct socks_data *data); 58 | int socks_tcp_bind(struct socks_data *data); 59 | void socks_tcp_connect(struct socks_data *data); 60 | void socks_tcp_connect_hostname(struct socks_data *data); 61 | void socks_request(struct socks_data *data, int n, 62 | void (*cb)(struct socks_data*)); 63 | int socks_listen(struct event_base *base, const char *host, 64 | const char *port, int keep_alive); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/socks4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "container_of.h" 8 | #include "socks.h" 9 | #include "socks4.h" 10 | 11 | #include "util/lwipevbuf_bev_join.h" 12 | #include "util/sockaddr.h" 13 | #include "util/lwipevbuf.h" 14 | 15 | #if LWIP_IPV4 16 | 17 | #define SOCKS4_CMD_CONNECT 1 18 | #define SOCKS4_CMD_BIND 2 19 | #define SOCKS4_CMD_RESOLVE 240 /* TOR extension */ 20 | 21 | #define SOCKS4_RESP_GRANT 90 22 | #define SOCKS4_RESP_REJECT 91 23 | 24 | struct socks4_hdr { 25 | u_char version; 26 | u_char cmd; 27 | u_int16_t port; 28 | u_int32_t addr; 29 | } __attribute__((__packed__)); 30 | 31 | struct socks4_data { 32 | struct socks_data socks; 33 | u_char pos; 34 | u_char cmd; 35 | }; 36 | 37 | static void 38 | socks4_kill(struct socks_data *sdata) 39 | { 40 | struct socks4_data *data; 41 | data = container_of(sdata, struct socks4_data, socks); 42 | free(data); 43 | } 44 | 45 | static void 46 | socks4_response(struct socks_data *sdata, int code, int connected, int die) 47 | { 48 | struct socks4_hdr hdr = {.version = 0, .cmd = code}; 49 | struct socks4_data *data; 50 | data = container_of(sdata, struct socks4_data, socks); 51 | 52 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: %d%s\n", __func__, code, 53 | die ? " die" : "")); 54 | if (!die) { 55 | struct tcp_pcb *pcb = sdata->lwipevbuf->pcb; 56 | if (connected && data->cmd == SOCKS4_CMD_BIND) { 57 | hdr.port = htons(pcb->remote_port); 58 | hdr.addr = ip4_addr_get_u32(ip_2_ip4(&pcb->remote_ip)); 59 | } else { 60 | hdr.port = htons(pcb->local_port); 61 | hdr.addr = ip4_addr_get_u32(ip_2_ip4(&pcb->local_ip)); 62 | } 63 | } else { 64 | hdr.port = 0; 65 | hdr.addr = ip4_addr_get_u32(ip_2_ip4(&sdata->ipaddr)); 66 | } 67 | 68 | bufferevent_write(sdata->bev, &hdr, sizeof(hdr)); 69 | 70 | if (die) 71 | socks_flush(sdata); 72 | } 73 | 74 | static void 75 | socks4_connect_ok(struct socks_data *sdata) 76 | { 77 | struct socks4_data *data; 78 | data = container_of(sdata, struct socks4_data, socks); 79 | 80 | socks4_response(sdata, SOCKS4_RESP_GRANT, 1, 0); 81 | 82 | lwipevbuf_bev_join(sdata->bev, sdata->lwipevbuf, 256*1024, NULL, NULL, NULL, NULL, NULL, NULL); 83 | free(data); 84 | } 85 | 86 | static void 87 | socks4_connect_failed(struct socks_data *sdata) 88 | { 89 | socks4_response(sdata, SOCKS4_RESP_REJECT, 0, 1); 90 | } 91 | 92 | static void 93 | socks4_connect(struct socks_data *sdata) 94 | { 95 | struct socks4_data *data; 96 | data = container_of(sdata, struct socks4_data, socks); 97 | 98 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s\n", __func__)); 99 | if (data->cmd == SOCKS4_CMD_CONNECT) 100 | socks_tcp_connect(sdata); 101 | 102 | else if (socks_tcp_bind(sdata) < 0) 103 | socks4_response(sdata, SOCKS4_RESP_REJECT, 0, 1); 104 | else { 105 | /* 106 | * If the user sends any input data at this point, it is an 107 | * error 108 | */ 109 | socks_request(sdata, 1, socks4_kill); 110 | socks4_response(sdata, SOCKS4_RESP_GRANT, 0, 0); 111 | } 112 | } 113 | 114 | static void 115 | socks4_host_found(struct host_data *hdata) 116 | { 117 | struct socks_data *sdata = container_of(hdata, struct socks_data, host); 118 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s\n", __func__)); 119 | sdata->ipaddr = hdata->ipaddr; 120 | socks4_response(sdata, SOCKS4_RESP_GRANT, 0, 1); 121 | } 122 | 123 | static void 124 | socks4_host_failed(struct host_data *hdata, err_t err) 125 | { 126 | struct socks_data *sdata = container_of(hdata, struct socks_data, host); 127 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: %s\n", __func__, lwip_strerr(err))); 128 | socks4_response(sdata, SOCKS4_RESP_REJECT, 0, 1); 129 | } 130 | 131 | static void 132 | socks4_read_fqdn(struct socks_data *sdata) 133 | { 134 | struct socks4_data *data; 135 | unsigned char ch; 136 | 137 | data = container_of(sdata, struct socks4_data, socks); 138 | 139 | while (bufferevent_read(sdata->bev, &ch, 1) > 0) { 140 | sdata->host.fqdn[data->pos] = ch; 141 | if (!ch) { 142 | bufferevent_disable(sdata->bev, EV_READ); 143 | if (data->cmd == SOCKS4_CMD_RESOLVE) 144 | host_lookup(&sdata->host); 145 | else 146 | socks_tcp_connect_hostname(sdata); 147 | return; 148 | } 149 | data->pos++; 150 | if (data->pos == 255) { 151 | socks4_response(sdata, SOCKS4_RESP_REJECT, 0, 1); 152 | return; 153 | } 154 | } 155 | 156 | socks_request(sdata, 1, socks4_read_fqdn); 157 | } 158 | 159 | static void 160 | socks4_read_user(struct socks_data *sdata) 161 | { 162 | u_char ch; 163 | 164 | while (bufferevent_read(sdata->bev, &ch, 1) > 0 && ch); 165 | 166 | if (!ch) { 167 | unsigned int ip; 168 | ip = ntohl(ip4_addr_get_u32(ip_2_ip4(&sdata->ipaddr))); 169 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s\n", __func__)); 170 | if (ip < 0x100 && ip) 171 | socks_request(sdata, 1, socks4_read_fqdn); 172 | else 173 | socks4_connect(sdata); 174 | } else 175 | socks_request(sdata, 1, socks4_read_user); 176 | } 177 | 178 | static void 179 | socks4_read_hdr(struct socks_data *sdata) 180 | { 181 | struct socks4_data *data; 182 | struct socks4_hdr hdr = {.version = 4}; 183 | 184 | data = container_of(sdata, struct socks4_data, socks); 185 | 186 | bufferevent_read(sdata->bev, ((char *) &hdr) + 1, sizeof(hdr) - 1); 187 | 188 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: cmd %d\n", __func__, hdr.cmd)); 189 | 190 | if (hdr.cmd != SOCKS4_CMD_CONNECT && hdr.cmd != SOCKS4_CMD_BIND && 191 | !(hdr.cmd == SOCKS4_CMD_RESOLVE && !hdr.port)) { 192 | socks4_response(sdata, SOCKS4_RESP_REJECT, 0, 1); 193 | return; 194 | } 195 | 196 | data->cmd = hdr.cmd; 197 | raw_to_ip4_addr(&hdr.addr, &sdata->ipaddr); 198 | sdata->port = ntohs(hdr.port); 199 | 200 | socks_request(sdata, 1, socks4_read_user); 201 | } 202 | 203 | void 204 | socks4_start(struct socks_server *s, struct bufferevent *bev) 205 | { 206 | struct socks4_data *data; 207 | struct socks_data *sdata; 208 | data = calloc(1, sizeof(struct socks4_data)); 209 | sdata = &data->socks; 210 | sdata->server = s; 211 | sdata->host.found = socks4_host_found; 212 | sdata->host.failed = socks4_host_failed; 213 | sdata->kill = socks4_kill; 214 | sdata->connect_ok = socks4_connect_ok; 215 | sdata->connect_failed = socks4_connect_failed; 216 | sdata->bev = bev; 217 | socks_request(sdata, sizeof(struct socks4_hdr) - 1, 218 | socks4_read_hdr); 219 | } 220 | 221 | #else 222 | void 223 | socks4_start(struct socks_server *s, struct bufferevent *bev) 224 | { 225 | } 226 | #endif -------------------------------------------------------------------------------- /src/socks4.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOCKS4_H__ 2 | #define __SOCKS4_H__ 3 | 4 | struct bufferevent; 5 | struct socks_server; 6 | 7 | void socks4_start(struct socks_server *s, struct bufferevent *bev); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/socks5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "container_of.h" 10 | #include "socks.h" 11 | #include "socks5.h" 12 | #include "util/sockaddr.h" 13 | #include "util/lwipevbuf.h" 14 | #include "util/lwipevbuf_bev_join.h" 15 | 16 | #define SOCKS5_ATYP_IPV4 0x01 17 | #define SOCKS5_ATYP_FQDN 0x03 18 | #define SOCKS5_ATYP_IPV6 0x04 19 | 20 | #define SOCKS5_CMD_CONNECT 0x01 21 | #define SOCKS5_CMD_BIND 0x02 22 | #define SOCKS5_CMD_UDP 0x03 23 | #define SOCKS5_CMD_RESOLVE 0xf0 /* TOR extension */ 24 | 25 | #define SOCKS5_RESP_GRANTED 0x00 26 | #define SOCKS5_RESP_FAILURE 0x01 27 | #define SOCKS5_RESP_PERM 0x02 28 | #define SOCKS5_RESP_NET_UNREACH 0x03 29 | #define SOCKS5_RESP_HOST_UNREACH 0x04 30 | #define SOCKS5_RESP_REFUSED 0x05 31 | #define SOCKS5_RESP_TTL 0x06 32 | #define SOCKS5_RESP_CMD_UNSUP 0x07 33 | #define SOCKS5_RESP_ADDR_UNSUP 0x08 34 | 35 | struct socks5_req { 36 | u_char version; 37 | u_char cmd; 38 | u_char reserved; 39 | u_char atyp; 40 | } __attribute__((__packed__)); 41 | 42 | struct socks5_rep { 43 | u_char version; 44 | u_char auth; 45 | } __attribute__((__packed__)); 46 | 47 | struct socks5_data { 48 | struct socks_data socks; 49 | u_char cmd; 50 | }; 51 | 52 | struct socks5_udp_hdr { 53 | u_short rsv; 54 | u_char frag; 55 | u_char atyp; 56 | } __attribute__((__packed__)); 57 | 58 | struct socks5_udp_ipv4 { 59 | u_int addr; 60 | u_short port; 61 | } __attribute__((__packed__)); 62 | 63 | struct socks5_udp_ipv6 { 64 | u_char addr[16]; 65 | u_short port; 66 | } __attribute__((__packed__)); 67 | 68 | static void 69 | socks5_kill(struct socks_data *sdata) 70 | { 71 | struct socks5_data *data; 72 | data = container_of(sdata, struct socks5_data, socks); 73 | free(data); 74 | } 75 | 76 | static void 77 | socks5_response(struct socks_data *sdata, int code, int connected, int die) 78 | { 79 | struct socks5_data *data; 80 | struct socks5_req req = { 81 | .version = 5, 82 | .cmd = code, 83 | }; 84 | u_int16_t port; 85 | void *addr; 86 | u_char addr_len; 87 | int zero = 0; 88 | 89 | data = container_of(sdata, struct socks5_data, socks); 90 | 91 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: code %d, die %d\n", __func__, code, die)); 92 | if (!die) { 93 | if (data->cmd == SOCKS5_CMD_UDP) { 94 | struct sockaddr_storage *ss = &sdata->server->addr; 95 | if (ss->ss_family == AF_INET6) { 96 | struct sockaddr_in6 *sin; 97 | sin = (struct sockaddr_in6 *) ss; 98 | req.atyp = SOCKS5_ATYP_IPV6; 99 | addr = &sin->sin6_addr.s6_addr; 100 | addr_len = 16; 101 | } else { 102 | struct sockaddr_in *sin; 103 | sin = (struct sockaddr_in *) ss; 104 | req.atyp = SOCKS5_ATYP_IPV4; 105 | addr = &sin->sin_addr.s_addr; 106 | addr_len = 4; 107 | if (ss->ss_family != AF_INET) { 108 | req.cmd = SOCKS5_RESP_FAILURE; 109 | die = 1; 110 | } 111 | } 112 | port = htons(sdata->udp_port); 113 | } else if (connected && data->cmd == SOCKS5_CMD_BIND) { 114 | /* BIND second message */ 115 | struct tcp_pcb *pcb = sdata->lwipevbuf->pcb; 116 | req.atyp = IP_IS_V4(&pcb->remote_ip) ? SOCKS5_ATYP_IPV4 : SOCKS5_ATYP_IPV6; 117 | addr = &pcb->remote_ip; 118 | addr_len = IP_IS_V4(&pcb->remote_ip) ? 4 : 16; 119 | port = htons(pcb->remote_port); 120 | } else { 121 | /* CONNECT or BIND first message*/ 122 | struct tcp_pcb *pcb = sdata->lwipevbuf->pcb; 123 | req.atyp = IP_IS_V4(&pcb->local_ip) ? SOCKS5_ATYP_IPV4 : SOCKS5_ATYP_IPV6; 124 | addr = &pcb->local_ip; 125 | addr_len = IP_IS_V4(&pcb->local_ip) ? 4 : 16; 126 | port = htons(pcb->local_port); 127 | } 128 | } else { 129 | /* 130 | * RFC doesn't seem to spec what address info goes into 131 | * a failed reply. Just put the bare minimum. 132 | */ 133 | req.atyp = SOCKS5_ATYP_IPV4; 134 | addr = &zero; 135 | addr_len = 4; 136 | port = 0; 137 | } 138 | bufferevent_write(sdata->bev, &req, sizeof(req)); 139 | bufferevent_write(sdata->bev, addr, addr_len); 140 | bufferevent_write(sdata->bev, &port, 2); 141 | if (die) 142 | socks_flush(sdata); 143 | } 144 | 145 | static void 146 | socks5_connect_ok(struct socks_data *sdata) 147 | { 148 | struct socks5_data *data; 149 | data = container_of(sdata, struct socks5_data, socks); 150 | 151 | socks5_response(sdata, SOCKS5_RESP_GRANTED, 1, 0); 152 | 153 | lwipevbuf_bev_join(sdata->bev, sdata->lwipevbuf, 256*1024, NULL, NULL, NULL, NULL, NULL, NULL); 154 | free(data); 155 | } 156 | 157 | static void 158 | socks5_connect_failed(struct socks_data *sdata) 159 | { 160 | socks5_response(sdata, SOCKS5_RESP_HOST_UNREACH, 0, 1); 161 | } 162 | 163 | static void 164 | socks5_udp_send(struct socks_data *data, struct pbuf *p) 165 | { 166 | struct socks5_udp_hdr *hdr; 167 | #if LWIP_IPV4 168 | struct socks5_udp_ipv4 *ipv4; 169 | #endif 170 | #if LWIP_IPV6 171 | struct socks5_udp_ipv6 *ipv6; 172 | #endif 173 | ip_addr_t ipaddr; 174 | u_short port; 175 | err_t err; 176 | u_char *len; 177 | char *fqdn; 178 | 179 | hdr = p->payload; 180 | if (pbuf_header(p, -(short) sizeof(*hdr))) { 181 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: runt\n", __func__)); 182 | return; 183 | } 184 | 185 | if (hdr->frag) { 186 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: frag not supported\n", __func__)); 187 | return; 188 | } 189 | 190 | switch (hdr->atyp) { 191 | 192 | #if LWIP_IPV4 193 | case SOCKS5_ATYP_IPV4: 194 | ipv4 = p->payload; 195 | if (pbuf_header(p, -(short) sizeof(*ipv4))) { 196 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: runt\n", __func__)); 197 | return; 198 | } 199 | raw_to_ip4_addr(&ipv4->addr, &ipaddr); 200 | port = ntohs(ipv4->port); 201 | break; 202 | #endif 203 | #if LWIP_IPV6 204 | case SOCKS5_ATYP_IPV6: 205 | ipv6 = p->payload; 206 | if (pbuf_header(p, -(short) sizeof(*ipv6))) { 207 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: runt\n", __func__)); 208 | return; 209 | } 210 | raw_to_ip6_addr(ipv6->addr, &ipaddr); 211 | port = ntohs(ipv6->port); 212 | break; 213 | #endif 214 | case SOCKS5_ATYP_FQDN: 215 | len = p->payload; 216 | fqdn = p->payload + 1; 217 | if (pbuf_header(p, -1) || pbuf_header(p, -(short) *len)) { 218 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: runt\n", __func__)); 219 | return; 220 | } 221 | port = *((typeof(&port)) p->payload); 222 | if (pbuf_header(p, -(short) sizeof(port))) { 223 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: runt\n", __func__)); 224 | return; 225 | } 226 | 227 | if (!strncmp(data->host.fqdn, fqdn, *len) && 228 | !data->host.fqdn[*len]) { 229 | /* Matches current lookup */ 230 | if (host_busy(&data->host)) 231 | return; 232 | ipaddr = data->host.ipaddr; 233 | } else { 234 | /* New lookup */ 235 | if (host_busy(&data->host)) { 236 | /* Concurrent DNS lookups drop waiting packet */ 237 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: concurrent lookup\n", __func__)); 238 | } 239 | memcpy(data->host.fqdn, fqdn, *len); 240 | data->host.fqdn[*len] = '\0'; 241 | host_lookup(&data->host); 242 | return; 243 | } 244 | break; 245 | default: 246 | /* Unsupported */ 247 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: Unsupported address type\n", __func__)); 248 | return; 249 | } 250 | 251 | #if LWIP_IPV4 252 | if (IP_IS_V4(&ipaddr)) 253 | err = udp_sendto(data->upcb4, p, &ipaddr, port); 254 | #endif 255 | #if LWIP_IPV6 256 | if (IP_IS_V6(&ipaddr)) 257 | err = udp_sendto(data->upcb6, p, &ipaddr, port); 258 | #endif 259 | if (err < 0) 260 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: udp_sendto failed: %d\n", __func__, err)); 261 | } 262 | 263 | static void 264 | socks5_udp_recv(struct socks_data *data, struct pbuf *p, 265 | const ip_addr_t *addr, u16_t port) 266 | { 267 | struct socks5_udp_hdr *hdr; 268 | 269 | if (pbuf_header(p, sizeof(port))) { 270 | /* Not enough header space */ 271 | return; 272 | } 273 | *((typeof(&port)) p->payload) = port; 274 | 275 | if (pbuf_header(p, IP_IS_V4(addr) ? 4 : 16)) { 276 | /* Not enough header space */ 277 | return; 278 | } 279 | memcpy(p->payload, &addr, IP_IS_V4(addr) ? 4 : 16); 280 | 281 | if (pbuf_header(p, sizeof(*hdr))) { 282 | /* Not enough header space */ 283 | return; 284 | } 285 | hdr = p->payload; 286 | 287 | hdr->rsv = 0; 288 | hdr->frag = 0; 289 | hdr->atyp = IP_IS_V4(addr) ? SOCKS5_ATYP_IPV4 : SOCKS5_ATYP_IPV6; 290 | 291 | if (send(data->udp_fd, p->payload, p->len, 0) < 0) { 292 | /* Error sending packet */ 293 | } 294 | } 295 | 296 | static void 297 | socks5_lookup_done(struct socks_data *sdata) 298 | { 299 | struct socks5_data *data; 300 | struct event_base *base; 301 | data = container_of(sdata, struct socks5_data, socks); 302 | 303 | switch (data->cmd) { 304 | case SOCKS5_CMD_BIND: 305 | if (socks_tcp_bind(sdata) < 0) { 306 | socks5_response(sdata, SOCKS5_RESP_FAILURE, 0, 1); 307 | } else { 308 | /* 309 | * If the user sends any input data at this point, it is 310 | * an error 311 | */ 312 | socks_request(sdata, 1, socks_kill); 313 | socks5_response(sdata, SOCKS5_RESP_GRANTED, 0, 0); 314 | } 315 | break; 316 | case SOCKS5_CMD_UDP: 317 | base = bufferevent_get_base(sdata->bev); 318 | if (socks_udp_bind(base, sdata) < 0) { 319 | socks5_response(sdata, SOCKS5_RESP_FAILURE, 0, 1); 320 | } else { 321 | socks_request(sdata, 1, socks_kill); 322 | socks5_response(sdata, SOCKS5_RESP_GRANTED, 0, 0); 323 | } 324 | break; 325 | case SOCKS5_CMD_RESOLVE: 326 | socks5_response(sdata, SOCKS5_RESP_GRANTED, 0, 1); 327 | break; 328 | default: 329 | socks5_response(sdata, SOCKS5_RESP_CMD_UNSUP, 0, 1); 330 | } 331 | } 332 | 333 | static void 334 | socks5_host_found(struct host_data *hdata) 335 | { 336 | struct socks_data *sdata; 337 | 338 | sdata = container_of(hdata, struct socks_data, host); 339 | 340 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s\n", __func__)); 341 | 342 | if (sdata->udp_pbuf) { 343 | u16_t port; 344 | port = *((typeof(&port)) (sdata->udp_pbuf->payload - 2)); 345 | 346 | #if LWIP_IPV4 347 | if (IP_IS_V4(&hdata->ipaddr)) 348 | udp_sendto(sdata->upcb4, sdata->udp_pbuf, &hdata->ipaddr, port); 349 | #endif 350 | #if LWIP_IPV6 351 | if (IP_IS_V6(&hdata->ipaddr)) 352 | udp_sendto(sdata->upcb6, sdata->udp_pbuf, &hdata->ipaddr, port); 353 | #endif 354 | } else 355 | socks5_lookup_done(sdata); 356 | } 357 | 358 | static void 359 | socks5_host_failed(struct host_data *hdata, err_t err) 360 | { 361 | struct socks_data *sdata; 362 | 363 | sdata = container_of(hdata, struct socks_data, host); 364 | 365 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: %s\n", __func__, lwip_strerr(err))); 366 | 367 | if (sdata->udp_pbuf) { 368 | /* Matching fqdn indicates lookup success */ 369 | sdata->host.fqdn[0] = '\0'; 370 | } else 371 | socks5_response(sdata, SOCKS5_RESP_FAILURE, 0, 1); 372 | } 373 | 374 | static void 375 | socks5_read_port(struct socks_data *sdata) 376 | { 377 | struct socks5_data *data; 378 | data = container_of(sdata, struct socks5_data, socks); 379 | 380 | bufferevent_read(sdata->bev, &sdata->port, 2); 381 | sdata->port = ntohs(sdata->port); 382 | 383 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: port %d\n", __func__, sdata->port)); 384 | 385 | if (data->cmd == SOCKS5_CMD_CONNECT) { 386 | if (sdata->host.fqdn[0]) 387 | socks_tcp_connect_hostname(sdata); 388 | else 389 | socks_tcp_connect(sdata); 390 | } else if (sdata->host.fqdn[0]) { 391 | bufferevent_disable(sdata->bev, EV_READ); 392 | host_lookup(&sdata->host); 393 | } else { 394 | socks5_lookup_done(sdata); 395 | } 396 | } 397 | 398 | #if LWIP_IPV4 399 | static void 400 | socks5_read_ipv4(struct socks_data *sdata) 401 | { 402 | bufferevent_read(sdata->bev, &sdata->ipaddr, 4); 403 | socks_request(sdata, 2, socks5_read_port); 404 | } 405 | #endif 406 | 407 | #if LWIP_IPV6 408 | static void 409 | socks5_read_ipv6(struct socks_data *sdata) 410 | { 411 | bufferevent_read(sdata->bev, &sdata->ipaddr, 16); 412 | socks_request(sdata, 2, socks5_read_port); 413 | } 414 | #endif 415 | 416 | static void 417 | socks5_read_fqdn(struct socks_data *sdata) 418 | { 419 | bufferevent_read(sdata->bev, sdata->host.fqdn, sdata->req_len); 420 | sdata->host.fqdn[sdata->req_len] = '\0'; 421 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: fqdn %s\n", __func__, sdata->host.fqdn)); 422 | if (!sdata->host.fqdn[0]) 423 | socks5_response(sdata, SOCKS5_RESP_CMD_UNSUP, 0, 1); 424 | else 425 | socks_request(sdata, 2, socks5_read_port); 426 | } 427 | 428 | static void 429 | socks5_read_n_fqdn(struct socks_data *sdata) 430 | { 431 | unsigned char nfqdn; 432 | 433 | bufferevent_read(sdata->bev, &nfqdn, 1); 434 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: nfqdn %d\n", __func__, nfqdn)); 435 | if (!nfqdn) 436 | socks5_response(sdata, SOCKS5_RESP_CMD_UNSUP, 0, 1); 437 | else 438 | socks_request(sdata, nfqdn, socks5_read_fqdn); 439 | } 440 | 441 | static void 442 | socks5_read_hdr(struct socks_data *sdata) 443 | { 444 | struct socks5_data *data; 445 | struct socks5_req req; 446 | 447 | data = container_of(sdata, struct socks5_data, socks); 448 | 449 | bufferevent_read(sdata->bev, &req, sizeof(req)); 450 | if (req.version != 5) { 451 | socks_kill(sdata); 452 | return; 453 | } 454 | 455 | data->cmd = req.cmd; 456 | 457 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: cmd %d, atyp %d\n", __func__, req.cmd, req.atyp)); 458 | 459 | sdata->host.fqdn[0] = '\0'; 460 | 461 | switch (req.atyp) { 462 | #if LWIP_IPV4 463 | case SOCKS5_ATYP_IPV4: 464 | IP_SET_TYPE(&sdata->ipaddr, IPADDR_TYPE_V4); 465 | socks_request(sdata, 4, socks5_read_ipv4); 466 | break; 467 | #endif 468 | #if LWIP_IPV6 469 | case SOCKS5_ATYP_IPV6: 470 | IP_SET_TYPE(&sdata->ipaddr, IPADDR_TYPE_V6); 471 | socks_request(sdata, 16, socks5_read_ipv6); 472 | break; 473 | #endif 474 | case SOCKS5_ATYP_FQDN: 475 | socks_request(sdata, 1, socks5_read_n_fqdn); 476 | break; 477 | default: 478 | socks5_response(sdata, SOCKS5_RESP_ADDR_UNSUP, 0, 1); 479 | } 480 | } 481 | 482 | static void 483 | socks5_read_auth(struct socks_data *sdata) 484 | { 485 | u_char auth[255]; 486 | struct socks5_rep rep = {5, 0}; 487 | 488 | if (sdata->req_len) 489 | bufferevent_read(sdata->bev, auth, sdata->req_len); 490 | 491 | bufferevent_write(sdata->bev, &rep, sizeof(rep)); 492 | 493 | socks_request(sdata, sizeof(struct socks5_req), socks5_read_hdr); 494 | } 495 | 496 | static void 497 | socks5_read_n_auth(struct socks_data *sdata) 498 | { 499 | unsigned char nauth; 500 | 501 | bufferevent_read(sdata->bev, &nauth, 1); 502 | 503 | LWIP_DEBUGF(SOCKS_DEBUG, ("%s: nauth %d\n", __func__, nauth)); 504 | 505 | socks_request(sdata, nauth, socks5_read_auth); 506 | } 507 | 508 | void 509 | socks5_start(struct socks_server *s, struct bufferevent *bev) 510 | { 511 | struct socks5_data *data; 512 | struct socks_data *sdata; 513 | 514 | data = calloc(1, sizeof(struct socks5_data)); 515 | sdata = &data->socks; 516 | sdata->server = s; 517 | sdata->host.found = socks5_host_found; 518 | sdata->host.failed = socks5_host_failed; 519 | sdata->connect_ok = socks5_connect_ok; 520 | sdata->connect_failed = socks5_connect_failed; 521 | sdata->kill = socks5_kill; 522 | sdata->udp_send = socks5_udp_send; 523 | sdata->udp_recv = socks5_udp_recv; 524 | sdata->bev = bev; 525 | socks_request(sdata, 1, socks5_read_n_auth); 526 | } 527 | -------------------------------------------------------------------------------- /src/socks5.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOCKS5_H__ 2 | #define __SOCKS5_H__ 3 | 4 | struct bufferevent; 5 | struct socks_server; 6 | 7 | void socks5_start(struct socks_server *s, struct bufferevent *bev); 8 | 9 | #endif 10 | --------------------------------------------------------------------------------