├── 3rdparty └── libtins │ └── README.md ├── LICENSE ├── Makefile ├── README.md ├── client.cpp ├── server.cpp └── socketwrapper.h /3rdparty/libtins/README.md: -------------------------------------------------------------------------------- 1 | Place libtins `include` folder and `lib` folder here. 2 | 3 | Version: [commit 78b94fa350ebd14f49b59cdb3ac59121f586bb94](https://github.com/mfontanini/libtins/tree/78b94fa350ebd14f49b59cdb3ac59121f586bb94) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CXXFLAGS = -g -std=c++11 -I./3rdparty/libtins/include/ -L./3rdparty/libtins/lib -ltins 3 | 4 | all: client.elf server.elf 5 | @echo "Done" 6 | 7 | client.elf: client.o socketwrapper.h 8 | $(CC) client.o $(CXXFLAGS) -o $@ 9 | 10 | server.elf: server.o socketwrapper.h 11 | $(CC) server.o $(CXXFLAGS) -o $@ 12 | 13 | client.o: client.cpp 14 | $(CC) client.cpp -c $(CXXFLAGS) 15 | 16 | server.o: server.cpp 17 | $(CC) server.cpp -c $(CXXFLAGS) 18 | 19 | clean: 20 | rm ./*.elf 21 | rm ./*.o 22 | 23 | .PHONY: clean all 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## UDPTUN 2 | 3 | Simple UDP Tunnel program. 4 | 5 | ### Usage 6 | 7 | #### Client: 8 | 9 | ``` shell 10 | sudo ./client.elf -s 11 | ``` 12 | 13 | After client up and running, route packet into the network interface called `clienttun` which created by this program. For example: 14 | 15 | ``` shell 16 | route add default dev clienttun # this will route all your traffic into clienttun 17 | route add 123.123.123.123 clienttun # or like this, route traffic of a specify ip (123.123.123.123) 18 | route add gw dev # use `route -n` to see your gateway 19 | ``` 20 | 21 | #### Server: 22 | 23 | ``` shell 24 | sudo ./server.elf 25 | ``` 26 | 27 | Server will create a tun named `servertun`. If you'd like to watch the traffic: 28 | 29 | ``` shell 30 | tcpdump -i servertun -vv -n 31 | ``` 32 | 33 | ### FYI 34 | 35 | This is a learning purpose program. May contains bug. 36 | 37 | Associate blog about this program: [cnblogs:Make a simple udp-tunnel program](http://www.cnblogs.com/blumia/p/Make-a-simple-udp-tunnel-program.html) (Chinese). -------------------------------------------------------------------------------- /client.cpp: -------------------------------------------------------------------------------- 1 | #include /* O_RDWR */ 2 | #include /* memset(), memcpy() */ 3 | #include /* perror(), printf(), fprintf() */ 4 | #include /* exit(), malloc(), free() */ 5 | #include /* read(), close() */ 6 | #include /* select() */ 7 | 8 | /* cxx */ 9 | #include 10 | 11 | using namespace std; 12 | 13 | /* 3rd party libs */ 14 | #include "socketwrapper.h" 15 | #include 16 | 17 | using namespace Tins; 18 | 19 | char remote_ip[16] = ""; 20 | 21 | void process_arguments(int argc, char **argv) { 22 | bool argMissing = true; 23 | int opt; 24 | 25 | while (~(opt = getopt(argc, argv, "hHs:S:"))) { 26 | switch(opt) { 27 | case 's': case 'S': 28 | if (optarg) { 29 | strncpy(remote_ip,optarg,15); 30 | argMissing = false; 31 | } else { 32 | fputs("?\n", stdout); 33 | exit(0); 34 | } 35 | break; 36 | case 'h': case 'H': 37 | fputs("?\n", stdout); 38 | exit(0); 39 | //break; 40 | } 41 | } 42 | 43 | if (argMissing) { 44 | fputs("?\n", stdout); 45 | exit(0); 46 | } 47 | } 48 | 49 | int main(int argc, char *argv[]) 50 | { 51 | int socketfd, tunfd, nbytes; 52 | char buf[1600]; 53 | 54 | process_arguments(argc, argv); 55 | 56 | // dgram 57 | struct sockaddr_in srvaddr; 58 | socketfd = Socket(AF_INET, SOCK_DGRAM/* | SOCK_NONBLOCK*/, 0); 59 | bzero(&srvaddr, sizeof(srvaddr)); 60 | srvaddr.sin_family = AF_INET; 61 | srvaddr.sin_port = htons(SERV_PORT); 62 | inet_pton(AF_INET, remote_ip, &srvaddr.sin_addr); 63 | 64 | // tun 65 | tunfd = tun_open("clienttun"); 66 | system("route add 123.123.123.123 clienttun"); 67 | 68 | fputs("Client now running in UDP mode.\n", stdout); 69 | 70 | int maxfd = (socketfd > tunfd) ? socketfd : tunfd; 71 | 72 | while(1) { 73 | 74 | fd_set rd_set; 75 | 76 | FD_ZERO(&rd_set); 77 | FD_SET(tunfd, &rd_set); FD_SET(socketfd, &rd_set); 78 | 79 | int ret = select(maxfd + 1, &rd_set, NULL, NULL, NULL); 80 | if (ret < 0 && errno == EINTR) continue; 81 | if (ret < 0) { 82 | perror("select()"); exit(1); 83 | } 84 | 85 | if(FD_ISSET(tunfd, &rd_set)) { 86 | nbytes = read(tunfd, buf, sizeof(buf)); 87 | printf("Read %d bytes from clienttun\n", nbytes); 88 | //hex_dump(buf, nbytes); 89 | RawPDU p((uint8_t *)buf, nbytes); 90 | try { 91 | IP ip(p.to()); 92 | cout << "IP Packet: " << ip.src_addr() << " -> " << ip.dst_addr() << std::endl; 93 | sendto(socketfd, buf, nbytes, 0, (sockaddr*)&srvaddr, sizeof(srvaddr)); 94 | } catch (...) { 95 | continue; 96 | } 97 | } 98 | 99 | if(FD_ISSET(socketfd, &rd_set)) { 100 | int size84 = recvfrom(socketfd, buf, 1600, 0, NULL, NULL); 101 | printf("Recv %d bytes from udp socket\n", nbytes); 102 | write(tunfd, buf, size84); 103 | } 104 | } 105 | return 0; 106 | } -------------------------------------------------------------------------------- /server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "socketwrapper.h" 9 | 10 | /* cxx */ 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | /* 3rd party libs */ 17 | #include 18 | 19 | using namespace Tins; 20 | 21 | typedef std::pair AddrPort; 22 | 23 | int tunfd; 24 | char buf[1600]; 25 | in_addr_t cli_v4addr, tun_v4addr; 26 | map snat_map; 27 | struct sockaddr_in cliaddr, srvaddr; 28 | 29 | void process_arguments(int argc, char **argv) { 30 | int opt; 31 | 32 | while (~(opt = getopt(argc, argv, "rRhH"))) { 33 | switch(opt) { 34 | case 'r': case 'R': 35 | system("iptables -t nat -A POSTROUTING -s 192.168.61.0/24 -o eth0 -j MASQUERADE"); 36 | break; 37 | case 'h': case 'H': 38 | fputs("?\n", stdout); 39 | exit(0); 40 | //break; 41 | } 42 | } 43 | } 44 | 45 | void mainloop(int socketfd, SA* pcliaddr, socklen_t clilen) { 46 | int n, nbytes; 47 | socklen_t len; 48 | char buf[MAXLINE+1]; 49 | 50 | int maxfd = (socketfd > tunfd)? socketfd : tunfd; 51 | 52 | tun_v4addr = inet_addr("192.168.61.123"); 53 | 54 | for(;;) { 55 | fd_set rd_set; 56 | 57 | FD_ZERO(&rd_set); 58 | FD_SET(tunfd, &rd_set); FD_SET(socketfd, &rd_set); 59 | 60 | int ret = select(maxfd + 1, &rd_set, NULL, NULL, NULL); 61 | if (ret < 0 && errno == EINTR) continue; 62 | if (ret < 0) { 63 | perror("select()"); exit(1); 64 | } 65 | 66 | if(FD_ISSET(tunfd, &rd_set)) { 67 | // data avaliable from tun dev 68 | nbytes = read(tunfd, buf, sizeof(buf)); 69 | if (nbytes > 0) { 70 | printf("[Cli-TUN] [Srv-TUN]<<< [Remote] : Read %d bytes from servertun\n", nbytes); 71 | //hex_dump(buf, nbytes); 72 | RawPDU p((uint8_t *)buf, nbytes); 73 | try { 74 | IP ip(p.to()); 75 | cout << "IP Packet: " << ip.src_addr() << " <- " << ip.dst_addr() << std::endl; 76 | 77 | // dNAT 78 | AddrPort srcaddr, dstaddr; 79 | if (ip.protocol() == IPPROTO_TCP) { 80 | TCP& tcp = ip.rfind_pdu(); 81 | srcaddr = std::make_pair(ip.src_addr(), tcp.sport()); 82 | } 83 | if (ip.protocol() == IPPROTO_UDP) { 84 | UDP& udp = ip.rfind_pdu(); 85 | srcaddr = std::make_pair(ip.src_addr(), udp.sport()); 86 | } 87 | dstaddr = snat_map[srcaddr]; 88 | ip.dst_addr(dstaddr.first); 89 | 90 | // sent packet to client 91 | PDU::serialization_type serval = ip.serialize(); 92 | memcpy(buf, serval.data(), serval.size()); 93 | sendto(socketfd, buf, serval.size(), 0, pcliaddr, clilen); 94 | printf("[Cli-TUN]<<< [Srv-TUN] [Remote] : Sent %d bytes to client\n", serval.size()); 95 | 96 | } catch (...) { 97 | continue; 98 | } 99 | } 100 | } 101 | 102 | if(FD_ISSET(socketfd, &rd_set)) { 103 | // data avaliable from udp socket 104 | len = clilen; 105 | n = recvfrom(socketfd, buf, MAXLINE, 0, pcliaddr, &len); 106 | 107 | printf("[Cli-TUN] >>>[Srv-TUN] [Remote] : Read %d bytes from udp socket\n", n); 108 | //hex_dump(buf, n); 109 | RawPDU p((uint8_t *)buf, n); 110 | try { 111 | IP ip(p.to()); 112 | cout << "IP Packet: " << ip.src_addr() << " -> " << ip.dst_addr() << std::endl; 113 | 114 | // save source addr info 115 | AddrPort srcaddr, dstaddr; 116 | if (ip.protocol() == IPPROTO_TCP) { 117 | TCP& tcp = ip.rfind_pdu(); 118 | srcaddr = std::make_pair(ip.src_addr(), tcp.sport()); 119 | dstaddr = std::make_pair(ip.dst_addr(), tcp.dport()); 120 | snat_map[dstaddr] = srcaddr; 121 | } 122 | if (ip.protocol() == IPPROTO_UDP) { 123 | UDP& udp = ip.rfind_pdu(); 124 | srcaddr = std::make_pair(ip.src_addr(), udp.sport()); 125 | dstaddr = std::make_pair(ip.dst_addr(), udp.dport()); 126 | snat_map[dstaddr] = srcaddr; 127 | } 128 | // notice that ICMP dont have a port. 129 | 130 | // sNAT 131 | ip.src_addr(IPv4Address(tun_v4addr)); // src_addr = tun ip 132 | // no port modify now 133 | 134 | // write to tun device (to send packet) 135 | PDU::serialization_type serval = ip.serialize(); 136 | write(tunfd, serval.data(), serval.size()); 137 | printf("[Cli-TUN] [Srv-TUN] >>>[Remote] : Sent %d bytes from servertun\n", serval.size()); 138 | 139 | } catch (...) { 140 | continue; 141 | } 142 | } 143 | } 144 | } 145 | 146 | int main(int argc, char** argv) { 147 | 148 | int listenfd; 149 | pid_t childpid; 150 | socklen_t clilen; 151 | 152 | process_arguments(argc, argv); 153 | 154 | // dgram 155 | listenfd = Socket(AF_INET, SOCK_DGRAM, 0); 156 | bzero(&srvaddr, sizeof(srvaddr)); 157 | srvaddr.sin_family = AF_INET; 158 | srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); 159 | srvaddr.sin_port = htons(SERV_PORT); 160 | 161 | bind(listenfd, (SA*) &srvaddr, sizeof(srvaddr)); 162 | 163 | fputs("Server now running in UDP mode.\n", stdout); 164 | 165 | // server tun 166 | tunfd = tun_open("servertun"); 167 | system("ip addr add 192.168.61.0/24 dev servertun"); 168 | 169 | mainloop(listenfd, (SA *) &cliaddr, sizeof(cliaddr)); 170 | } 171 | -------------------------------------------------------------------------------- /socketwrapper.h: -------------------------------------------------------------------------------- 1 | // From UNP 2 | 3 | #ifndef __UNP_WRAPPER 4 | #define __UNP_WRAPPER 5 | 6 | #include 7 | #include 8 | #include /* ioctl() */ 9 | /* includes for struct ifreq, etc */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | /* networking */ 15 | #include 16 | #include 17 | 18 | #define SERV_PORT 9877 19 | #define MAXLINE 4096 20 | #define LISTENQ SOMAXCONN /* defined in linux kernel */ 21 | 22 | typedef struct sockaddr SA; 23 | 24 | typedef unsigned char byte; 25 | 26 | void hex_dump(const char *buf, int len) { 27 | const char* addr = buf; 28 | int i,j,k; 29 | char binstr[80]; 30 | 31 | for (i=0;i 0) { 96 | if (ch == '\r') { // CR LF -> LF, CR -> LF 97 | received = recv(socketfd, &ch, 1, MSG_PEEK); 98 | if (received > 0 && ch == '\n') recv(socketfd, &ch, 1, 0); 99 | else ch = '\n'; 100 | } 101 | buffer[i] = ch; 102 | i++; 103 | } else { 104 | break; 105 | } 106 | } 107 | 108 | buffer[i] = '\0'; 109 | return i; 110 | } 111 | 112 | int set_nonblocking(int fd) { 113 | int flags; 114 | if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 115 | flags = 0; 116 | return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 117 | } 118 | 119 | /* TUN device/interface utils */ 120 | 121 | int tun_open(const char *devname) { 122 | struct ifreq ifr; 123 | int fd, err; 124 | 125 | if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) { 126 | perror("open /dev/net/tun");exit(1); 127 | } 128 | memset(&ifr, 0, sizeof(ifr)); 129 | ifr.ifr_flags = IFF_TUN | IFF_NO_PI | IFF_UP | IFF_RUNNING; 130 | strncpy(ifr.ifr_name, devname, IFNAMSIZ); 131 | 132 | /* ioctl will use if_name as the name of TUN 133 | * interface to open: "tun0", etc. */ 134 | if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) { 135 | perror("ioctl TUNSETIFF");close(fd);exit(1); 136 | } 137 | 138 | if ( (err = ioctl(socket(PF_INET, SOCK_DGRAM, 0), SIOCSIFFLAGS, (void *) &ifr)) == -1 ) { 139 | perror("ioctl SIOCSIFFLAGS");close(fd);exit(1); 140 | } 141 | 142 | /* After the ioctl call the fd is "connected" to tun device specified 143 | * by devname */ 144 | printf("Device %s opened\n", ifr.ifr_name); 145 | 146 | return fd; 147 | } 148 | 149 | #endif /* __UNP_WRAPPER */ 150 | --------------------------------------------------------------------------------