├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── client.sh ├── icmp.c ├── icmp.h ├── icmptunnel.c ├── server.sh ├── test_client.c ├── test_server.c ├── tunnel.c └── tunnel.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | test_client 3 | test_server 4 | icmptunnel 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | script: make all 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. -O3 -Wall 3 | DEPS = icmp.h tunnel.h 4 | 5 | %.o: %.c $(DEPS) 6 | $(CC) -c -o $@ $< $(CFLAGS) 7 | 8 | icmptunnel: icmptunnel.o icmp.o tunnel.o 9 | $(CC) -o icmptunnel icmp.o tunnel.o icmptunnel.o $(CFLAGS) 10 | 11 | test_server: icmp.o test_server.o 12 | $(CC) -o test_server icmp.o test_server.o $(CFLAGS) 13 | 14 | test_client: icmp.o test_client.o 15 | $(CC) -o test_client icmp.o test_client.o $(CFLAGS) 16 | 17 | test: test_server test_client 18 | 19 | all: icmptunnel test_server test_client 20 | 21 | clean: 22 | rm -f *.o test_server test_client icmptunnel 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # icmptunnel [![Build Status](https://travis-ci.org/DhavalKapil/icmptunnel.svg?branch=master)](https://travis-ci.org/DhavalKapil/icmptunnel) 2 | 3 | > Transparently tunnel your IP traffic through ICMP echo and reply packets. 4 | 5 | 'icmptunnel' works by encapsulating your IP traffic in ICMP echo packets and sending them to your own proxy server. The proxy server decapsulates the packet and forwards the IP traffic. The incoming IP packets which are destined for the client are again encapsulated in ICMP reply packets and sent back to the client. The IP traffic is sent in the 'data' field of ICMP packets. 6 | 7 | [RFC 792](http://www.ietf.org/rfc/rfc792.txt), which is IETF's rules governing ICMP packets, allows for an arbitrary data length for any type 0 (echo reply) or 8 (echo message) ICMP packets. 8 | 9 | So basically the client machine uses only the ICMP protocol to communicate with the proxy server. Applications running on the client machine are oblivious to this fact and work seamlessly. 10 | 11 | ## Use Cases 12 | 13 | 1. **Bypassing Captive Portals**: Many public Wi-Fi use [Captive Portals](https://en.wikipedia.org/wiki/Captive_portal) to authenticate users, i.e. after connecting to the Wi-Fi the user is redirected to a webpage that requires a login. icmptunnel can be used to bypass such authentications in transport/application layers. 14 | 15 | 2. **Bypassing firewalls**: Firewalls are set up in various networks to block certain type of traffic. icmptunnel can be used to bypass such firewall rules. Obfuscating the data payload can also be helpful to bypass some firewalls. 16 | 17 | 3. **Encrypted Communication Channel**: Adding sufficient encryption to the data, icmptunnel can be used to establish an encrypted communication channel between two host machines. 18 | 19 | ## Requirements 20 | 21 | 1. A POSIX-compliant host with root access that will be communicating with only ICMP protocol. This will be the client. 22 | 23 | 2. A POSIX-compliant host with root access with full access to the internet. This will act as our proxy server. 24 | 25 | 3. The proxy server should be accessible from the client host. 26 | 27 | _Note: Although icmptunnel has been successfully tested on Ubuntu 14.04 LTS, it should work on others as well._ 28 | 29 | ## Step-by-step instructions 30 | 31 | 1. Install `make` on both machines. 32 | 33 | 2. Clone this repository using this command: 34 | 35 | ``` 36 | git clone https://github.com/DhavalKapil/icmptunnel 37 | ``` 38 | 39 | 3. Run `make`: 40 | 41 | ``` 42 | make 43 | ``` 44 | 45 | 4. On the server side run the tunnel with root privileges: 46 | 47 | ``` 48 | [sudo] ./icmptunnel -s 10.0.1.1 49 | ``` 50 | 51 | 5. On the client side, find out your gateway and the corresponding interface: 52 | 53 | ``` 54 | route -n 55 | 56 | Destination Gateway Genmask Flags Metric Ref Use Iface 57 | 58 | 0.0.0.0 172.25.30.1 0.0.0.0 UG 0 0 0 eth0 59 | ``` 60 | 61 | Edit client.sh and replace \ with the IP address of the proxy server. \ with gateway address obtained above and similarly for \. 62 | 63 | 6. Check the DNS server at client side. Make sure it does not use any server not accessible by our proxy server. One suggestion is to use `8.8.8.8`(Google's DNS server) which will be accessible to the proxy server. You would need to edit your DNS settings for this. *You might need to manually delete the route for your local DNS server from your routing table.* 64 | 65 | 7. Run the tunnel on your client with root privileges: 66 | 67 | ``` 68 | [sudo] ./icmptunnel -c 69 | ``` 70 | 71 | The tunnel should run and your client machine should be able to access the internet. All traffic will be tunneled through ICMP. 72 | 73 | ## Architecture 74 | 75 | icmptunnel works by creating a virtual tunnel interface(say `tun0`). All the user traffic on the client host is routed to `tun0`. icmptunnel listens on this interface for IP packets. These packets are encapsulated in an ICMP echo packet(i.e. the payload of the ICMP packet is nothing but the original IP packet). This newly generated ICMP packet is sent outside the client machine, to the proxy server, through the restricted internet connection. 76 | 77 | The proxy server receives these ICMP packets and decapsulates the original IP packet. This is retransmitted onto the Internet after implementing IP masquerading. Hence, the target believes that it's the proxy server making the request. The target then responds back to the proxy server with an IP packet. This is again captured by icmptunnel, encapsulated in an ICMP reply packet and send back to the client. 78 | 79 | On the client side, the IP packet is retrieved from the payload of the ICMP reply packet and injected in `tun0`. The user applications read from this virtual interface and hence get the proper IP packet. 80 | 81 | #### Overall Architecture 82 | 83 | ``` 84 | +--------------+ +------------+ 85 | | | ICMP traffic | | IP traffic 86 | | Client | -------------------> | Proxy | ------------------> 87 | | | <------------------- | Server | <------------------ 88 | | | through restricted | | proper internet 89 | +--------------+ internet +------------+ 90 | ``` 91 | 92 | #### Client Architecture 93 | 94 | ``` 95 | +--------------+ +------------+ 96 | | | IP traffic +------+ IP traffic | | ICMP traffic 97 | | User | ---------> | tun0 | ---------> | icmptunnel | ---------------> 98 | | Applications | <--------- +------+ <--------- | program | <--------------- 99 | | | (Virtual Interface) | | restricted 100 | +--------------+ +------------+ internet 101 | ``` 102 | 103 | #### Proxy Server Architecture 104 | 105 | ``` 106 | +------------+ 107 | ICMP traffic | | IP traffic +------+ NAT/Masquerading 108 | ---------------> | icmptunnel | ------------> | tun0 | ---------------------> 109 | <--------------- | program | <------------ +------+ <--------------------- 110 | restricted | | (Virtual Interface) proper internet 111 | internet +------------+ 112 | ``` 113 | 114 | ## Implementation 115 | 116 | * ICMP is implemented using raw C sockets. 117 | 118 | * The checksum is calculated using the algorithm given in [RFC 1071](https://tools.ietf.org/html/rfc1071). 119 | 120 | * [Tun](https://www.kernel.org/doc/Documentation/networking/tuntap.txt) driver is used for creating a virtual interface and binding to user space programs. 121 | 122 | * The virtual interface is configured through `ifconfig`. 123 | 124 | * `route` is used to change the routing tables of the client so as to route all traffic to the virtual tunnel interface. 125 | 126 | * `dd` is used to temporarily change the setting of IP forwarding and replying back to ICMP requests on the side of the proxy server. 127 | 128 | * `iptables` is used to set up `nat` on the server side. 129 | 130 | ## Demo 131 | 132 | ### Network Setup 133 | 134 | Proxy server is connected to `eth0`. This interface provides full internet connection. 135 | 136 | Both the client and proxy server are connected to `wlan0`(a WiFi hotspot). This hotspot is configured not to provide any internet connection. 137 | 138 | `tun0` will be created in both the client and the proxy server. 139 | 140 | The client will make an HTTP request to [dhavalkapil.com](https://dhavalkapil.com). 141 | 142 | [Wireshark](https://www.wireshark.org/) is used to capture network traffic at both ends on various interface. 143 | 144 | ### Screenshots of network traffic 145 | 146 | 1. `tun0` on client side 147 | 148 | ![tun0 client side](https://i.imgur.com/EnStcDO.png?1) 149 | 150 | The usual HTTP request is visible along with response. 151 | 152 | 2. `wlan0` on client side 153 | 154 | ![wlan0 client side](https://i.imgur.com/EKEqCGv.png?1) 155 | 156 | All traffic is ICMP. The HTTP/IP packet can be seen as part of the payload of the ICMP packet. 157 | 158 | 3. `wlan0` on proxy server side 159 | 160 | ![wlan0 proxy server side](https://i.imgur.com/6OhsUyZ.png?1) 161 | 162 | The ICMP packets sent by the client can be seen. 163 | 164 | 4. `tun0` on proxy server side 165 | 166 | ![tun0 proxy server side](https://i.imgur.com/OCq9aZe.png?1) 167 | 168 | The HTTP/IP packets are decapsulated and sent through `tun0`. 169 | 170 | 5. `eth0` on proxy server side 171 | 172 | ![eth0 proxy server side](https://i.imgur.com/HQigUea.png?1) 173 | 174 | The HTTP/IP packets are forwarded to the internet. Notice how the source IP has been masqueraded because of `nat`. 175 | 176 | ## Contribution 177 | 178 | Feel free to [file issues](https://github.com/DhavalKapil/icmptunnel/issues) and submit [pull requests](https://github.com/DhavalKapil/icmptunnel/pulls) – contributions are welcome. 179 | 180 | ## License 181 | 182 | icmptunnel is licensed under the [MIT license](http://dhaval.mit-license.org/). 183 | -------------------------------------------------------------------------------- /client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Assigining an IP address and mask to 'tun0' interface 4 | ifconfig tun0 mtu 1472 up 10.0.1.2 netmask 255.255.255.0 5 | 6 | # Modifying IP routing tables 7 | route del default 8 | # 'server' is the IP address of the proxy server 9 | # 'gateway' and 'interface' can be obtained by usint the command: 'route -n' 10 | route add -host gw dev 11 | route add default gw 10.0.1.1 tun0 12 | -------------------------------------------------------------------------------- /icmp.c: -------------------------------------------------------------------------------- 1 | /** 2 | * icmp.c 3 | */ 4 | 5 | #include "icmp.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * Function to calculate checksum 17 | */ 18 | uint16_t in_cksum(uint16_t *addr, int len); 19 | 20 | /** 21 | * Function to fill up common headers for IP and ICMP 22 | */ 23 | void prepare_headers(struct iphdr *ip, struct icmphdr *icmp); 24 | 25 | /** 26 | * Function to set packet type as ECHO 27 | */ 28 | void set_echo_type(struct icmp_packet *packet) 29 | { 30 | packet->type = ICMP_ECHO; 31 | } 32 | 33 | /** 34 | * Function to set packet type as REPLY 35 | */ 36 | void set_reply_type(struct icmp_packet *packet) 37 | { 38 | packet->type = ICMP_ECHOREPLY; 39 | } 40 | 41 | /** 42 | * Function to open a socket for icmp 43 | */ 44 | int open_icmp_socket() 45 | { 46 | int sock_fd, on = 1; 47 | 48 | sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 49 | 50 | if (sock_fd == -1) { 51 | perror("Unable to open ICMP socket\n"); 52 | exit(EXIT_FAILURE); 53 | } 54 | 55 | // Providing IP Headers 56 | if (setsockopt(sock_fd, IPPROTO_IP, IP_HDRINCL, (const char *)&on, sizeof(on)) == -1) { 57 | perror("Unable to set IP_HDRINCL socket option\n"); 58 | exit(EXIT_FAILURE); 59 | } 60 | 61 | return sock_fd; 62 | } 63 | 64 | /** 65 | * Function to bind the socket to INADDR_ANY 66 | */ 67 | void bind_icmp_socket(int sock_fd) 68 | { 69 | struct sockaddr_in servaddr; 70 | 71 | // Initializing servaddr to bind to all interfaces 72 | memset(&servaddr, 0, sizeof(struct sockaddr_in)); 73 | servaddr.sin_family = AF_INET; 74 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 75 | 76 | // binding the socket 77 | if (bind(sock_fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == -1) { 78 | perror("Unable to bind\n"); 79 | exit(EXIT_FAILURE); 80 | } 81 | } 82 | 83 | /** 84 | * Function to send ICMP Packet 85 | */ 86 | void send_icmp_packet(int sock_fd, struct icmp_packet *packet_details) 87 | { 88 | // Source and destination IPs 89 | struct in_addr src_addr; 90 | struct in_addr dest_addr; 91 | 92 | struct iphdr *ip; 93 | struct icmphdr *icmp; 94 | char *icmp_payload; 95 | 96 | int packet_size; 97 | char *packet; 98 | 99 | struct sockaddr_in servaddr; 100 | 101 | inet_pton(AF_INET, packet_details->src_addr, &src_addr); 102 | inet_pton(AF_INET, packet_details->dest_addr, &dest_addr); 103 | 104 | packet_size = sizeof(struct iphdr) + sizeof(struct icmphdr) + packet_details->payload_size; 105 | packet = calloc(packet_size, sizeof(uint8_t)); 106 | if (packet == NULL) { 107 | perror("No memory available\n"); 108 | close_icmp_socket(sock_fd); 109 | exit(EXIT_FAILURE); 110 | } 111 | 112 | // Initializing header and payload pointers 113 | ip = (struct iphdr *)packet; 114 | icmp = (struct icmphdr *)(packet + sizeof(struct iphdr)); 115 | icmp_payload = (char *)(packet + sizeof(struct iphdr) + sizeof(struct icmphdr)); 116 | 117 | prepare_headers(ip, icmp); 118 | 119 | ip->tot_len = htons(packet_size); 120 | ip->saddr = src_addr.s_addr; 121 | ip->daddr = dest_addr.s_addr; 122 | 123 | memcpy(icmp_payload, packet_details->payload, packet_details->payload_size); 124 | 125 | icmp->type = packet_details->type; 126 | icmp->checksum = 0; 127 | icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr) + packet_details->payload_size); 128 | 129 | memset(&servaddr, 0, sizeof(struct sockaddr_in)); 130 | servaddr.sin_family = AF_INET; 131 | servaddr.sin_addr.s_addr = dest_addr.s_addr; 132 | 133 | // Sending the packet 134 | sendto(sock_fd, packet, packet_size, 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)); 135 | 136 | free(packet); 137 | } 138 | 139 | /** 140 | * Function to receive an ICMP packet 141 | */ 142 | void receive_icmp_packet(int sock_fd, struct icmp_packet *packet_details) 143 | { 144 | struct sockaddr_in src_addr; 145 | //struct sockaddr_in dest_addr; 146 | 147 | struct iphdr *ip; 148 | struct icmphdr *icmp; 149 | char *icmp_payload; 150 | 151 | int packet_size; 152 | char *packet; 153 | 154 | socklen_t src_addr_size; 155 | int enc_MTU; //encapsulated MTU 156 | 157 | enc_MTU = MTU + sizeof(struct iphdr) + sizeof(struct icmphdr); 158 | 159 | packet = calloc(enc_MTU, sizeof(uint8_t)); 160 | if (packet == NULL) { 161 | perror("No memory available\n"); 162 | close_icmp_socket(sock_fd); 163 | exit(-1); 164 | } 165 | 166 | src_addr_size = sizeof(struct sockaddr_in); 167 | 168 | // Receiving packet 169 | packet_size = recvfrom(sock_fd, packet, enc_MTU, 0, (struct sockaddr *)&(src_addr), &src_addr_size); 170 | 171 | ip = (struct iphdr *)packet; 172 | icmp = (struct icmphdr *)(packet + sizeof(struct iphdr)); 173 | icmp_payload = (char *)(packet + sizeof(struct iphdr) + sizeof(struct icmphdr)); 174 | 175 | // Filling up packet_details 176 | inet_ntop(AF_INET, &(ip->saddr), packet_details->src_addr, INET_ADDRSTRLEN); 177 | inet_ntop(AF_INET, &(ip->daddr), packet_details->dest_addr, INET_ADDRSTRLEN); 178 | packet_details->type = icmp->type; 179 | packet_details->payload_size = packet_size - sizeof(struct iphdr) - sizeof(struct icmphdr); 180 | packet_details->payload = calloc(packet_details->payload_size, sizeof(uint8_t)); 181 | if (packet_details->payload == NULL) { 182 | perror("No memory available\n"); 183 | close_icmp_socket(sock_fd); 184 | exit(-1); 185 | } 186 | 187 | memcpy(packet_details->payload, icmp_payload, packet_details->payload_size); 188 | 189 | free(packet); 190 | } 191 | 192 | /** 193 | * Function to close the icmp socket 194 | */ 195 | void close_icmp_socket(int sock_fd) 196 | { 197 | close(sock_fd); 198 | } 199 | 200 | /** 201 | * Function to calculate checksum 202 | */ 203 | uint16_t in_cksum(uint16_t *addr, int len) 204 | { 205 | int nleft = len; 206 | uint32_t sum = 0; 207 | uint16_t *w = addr; 208 | uint16_t answer = 0; 209 | 210 | // Adding 16 bits sequentially in sum 211 | while (nleft > 1) { 212 | sum += *w; 213 | nleft -= 2; 214 | w++; 215 | } 216 | 217 | // If an odd byte is left 218 | if (nleft == 1) { 219 | *(unsigned char *) (&answer) = *(unsigned char *) w; 220 | sum += answer; 221 | } 222 | 223 | sum = (sum >> 16) + (sum & 0xffff); 224 | sum += (sum >> 16); 225 | answer = ~sum; 226 | 227 | return answer; 228 | } 229 | 230 | /** 231 | * Function to fill up common headers for IP and ICMP 232 | */ 233 | void prepare_headers(struct iphdr *ip, struct icmphdr *icmp) 234 | { 235 | ip->version = 4; 236 | ip->ihl = 5; 237 | ip->tos = 0; 238 | ip->id = rand(); 239 | ip->frag_off = 0; 240 | ip->ttl = 255; 241 | ip->protocol = IPPROTO_ICMP; 242 | 243 | icmp->code = 0; 244 | icmp->un.echo.sequence = rand(); 245 | icmp->un.echo.id = rand(); 246 | icmp->checksum = 0; 247 | } 248 | -------------------------------------------------------------------------------- /icmp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * icmp.h 3 | */ 4 | 5 | #ifndef icmp_guard 6 | #define icmp_guard 7 | 8 | // Maximum transmission unit 9 | #define MTU 1472 10 | 11 | struct icmp_packet 12 | { 13 | char src_addr[100]; 14 | char dest_addr[100]; 15 | int type; 16 | char *payload; 17 | int payload_size; 18 | }; 19 | 20 | /** 21 | * Function to set packet type as ECHO 22 | */ 23 | void set_echo_type(struct icmp_packet *packet); 24 | 25 | /** 26 | * Function to set packet type as REPLY 27 | */ 28 | void set_reply_type(struct icmp_packet *packet); 29 | 30 | /** 31 | * Function to open a socket for icmp 32 | */ 33 | int open_icmp_socket(); 34 | 35 | /** 36 | * Function to bind the socket to INADDR_ANY 37 | */ 38 | void bind_icmp_socket(int sock_fd); 39 | 40 | /** 41 | * Function to send ICMP Packet 42 | */ 43 | void send_icmp_packet(int sock_fd, struct icmp_packet *packet_details); 44 | 45 | /** 46 | * Function to receive ICMP Packet 47 | */ 48 | void receive_icmp_packet(int sock_fd, struct icmp_packet *packet_details); 49 | 50 | /** 51 | * Function to close the icmp socket 52 | */ 53 | void close_icmp_socket(int sock_fd); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /icmptunnel.c: -------------------------------------------------------------------------------- 1 | /** 2 | * icmp_tunnel.c 3 | */ 4 | 5 | #include "tunnel.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define ARG_SERVER_MODE "-s" 12 | #define ARG_CLIENT_MODE "-c" 13 | 14 | void usage() 15 | { 16 | printf("Wrong argument\n"); 17 | fprintf(stdout, "usage: icmptunnel [-s serverip] | [-c clientip]\n"); 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | char ip_addr[100] = {0,}; 23 | if ((argc < 3) || ((strlen(argv[2]) + 1) > sizeof(ip_addr))) { 24 | usage(); 25 | exit(EXIT_FAILURE); 26 | } 27 | memcpy(ip_addr, argv[2], strlen(argv[2]) + 1); 28 | 29 | if (strncmp(argv[1], ARG_SERVER_MODE, strlen(argv[1])) == 0) { 30 | run_tunnel(ip_addr, 1); 31 | } 32 | else if (strncmp(argv[1], ARG_CLIENT_MODE, strlen(argv[1])) == 0) { 33 | run_tunnel(ip_addr, 0); 34 | } 35 | else { 36 | usage(); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | return EXIT_SUCCESS; 41 | } 42 | -------------------------------------------------------------------------------- /server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Assigining an IP address and mask to 'tun0' interface 4 | ifconfig tun0 mtu 1472 up 10.0.1.1 netmask 255.255.255.0 5 | 6 | # Preventing the kernel to reply to any ICMP pings 7 | echo 1 | dd of=/proc/sys/net/ipv4/icmp_echo_ignore_all 8 | 9 | # Enabling IP forwarding 10 | echo 1 | dd of=/proc/sys/net/ipv4/ip_forward 11 | 12 | # Adding an iptables rule to masquerade for 10.0.0.0/8 13 | iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -j MASQUERADE 14 | -------------------------------------------------------------------------------- /test_client.c: -------------------------------------------------------------------------------- 1 | #include "icmp.h" 2 | #include 3 | 4 | int main() 5 | { 6 | struct icmp_packet packet; 7 | char *src_ip; 8 | char *dest_ip; 9 | int sock_fd; 10 | 11 | src_ip = "127.0.0.2"; 12 | dest_ip = "127.0.0.1"; 13 | 14 | strncpy(packet.src_addr, src_ip, strlen(src_ip) + 1); 15 | strncpy(packet.dest_addr, dest_ip, strlen(dest_ip) + 1); 16 | set_reply_type(&packet); 17 | packet.payload = "ZZZZZZ"; 18 | packet.payload_size = strlen(packet.payload); 19 | 20 | sock_fd = open_icmp_socket(); 21 | 22 | send_icmp_packet(sock_fd, &packet); 23 | 24 | close_icmp_socket(sock_fd); 25 | } 26 | -------------------------------------------------------------------------------- /test_server.c: -------------------------------------------------------------------------------- 1 | #include "icmp.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | int main() 8 | { 9 | struct icmp_packet packet; 10 | int sock_fd; 11 | 12 | sock_fd = open_icmp_socket(); 13 | bind_icmp_socket(sock_fd); 14 | 15 | printf("server initialized\n"); 16 | while(1) 17 | { 18 | receive_icmp_packet(sock_fd, &packet); 19 | printf("%s\n", packet.src_addr); 20 | printf("%s\n", packet.dest_addr); 21 | printf("%d\n", packet.type); 22 | printf("%s\n", packet.payload); 23 | } 24 | 25 | close_icmp_socket(sock_fd); 26 | } -------------------------------------------------------------------------------- /tunnel.c: -------------------------------------------------------------------------------- 1 | /** 2 | * tunnel.c 3 | */ 4 | 5 | #include "icmp.h" 6 | #include "tunnel.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | #define DEFAULT_ROUTE "0.0.0.0" 27 | 28 | /** 29 | * Function to allocate a tunnel 30 | */ 31 | int tun_alloc(char *dev, int flags) 32 | { 33 | struct ifreq ifr; 34 | int tun_fd, err; 35 | char *clonedev = "/dev/net/tun"; 36 | printf("[DEBUG] Allocating tunnel\n"); 37 | 38 | tun_fd = open(clonedev, O_RDWR); 39 | 40 | if(tun_fd == -1) { 41 | perror("Unable to open clone device\n"); 42 | exit(EXIT_FAILURE); 43 | } 44 | 45 | memset(&ifr, 0, sizeof(ifr)); 46 | 47 | ifr.ifr_flags = flags; 48 | 49 | if (*dev) { 50 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); 51 | } 52 | 53 | if ((err=ioctl(tun_fd, TUNSETIFF, (void *)&ifr)) < 0) { 54 | close(tun_fd); 55 | fprintf(stderr, "Error returned by ioctl(): %s\n", strerror(err)); 56 | perror("Error in tun_alloc()\n"); 57 | exit(EXIT_FAILURE); 58 | } 59 | 60 | printf("[DEBUG] Allocatating tunnel2"); 61 | 62 | printf("[DEBUG] Created tunnel %s\n", dev); 63 | 64 | return tun_fd; 65 | } 66 | 67 | /** 68 | * Function to read from a tunnel 69 | */ 70 | int tun_read(int tun_fd, char *buffer, int length) 71 | { 72 | int bytes_read; 73 | printf("[DEBUG] Reading from tunnel\n"); 74 | bytes_read = read(tun_fd, buffer, length); 75 | 76 | if (bytes_read == -1) { 77 | perror("Unable to read from tunnel\n"); 78 | exit(EXIT_FAILURE); 79 | } 80 | else { 81 | return bytes_read; 82 | } 83 | } 84 | 85 | /** 86 | * Function to write to a tunnel 87 | */ 88 | int tun_write(int tun_fd, char *buffer, int length) 89 | { 90 | int bytes_written; 91 | printf("[DEBUG] Writing to tunnel\n"); 92 | bytes_written = write(tun_fd, buffer, length); 93 | 94 | if (bytes_written == -1) { 95 | perror("Unable to write to tunnel\n"); 96 | exit(EXIT_FAILURE); 97 | } 98 | else { 99 | return bytes_written; 100 | } 101 | } 102 | 103 | /** 104 | * Function to configure the network 105 | */ 106 | void configure_network(int server) 107 | { 108 | int pid, status; 109 | char path[100]; 110 | char *const args[] = {path, NULL}; 111 | 112 | if (server) { 113 | if (sizeof(SERVER_SCRIPT) > sizeof(path)){ 114 | perror("Server script path is too long\n"); 115 | exit(EXIT_FAILURE); 116 | } 117 | strncpy(path, SERVER_SCRIPT, strlen(SERVER_SCRIPT) + 1); 118 | } 119 | else { 120 | if (sizeof(CLIENT_SCRIPT) > sizeof(path)){ 121 | perror("Client script path is too long\n"); 122 | exit(EXIT_FAILURE); 123 | } 124 | strncpy(path, CLIENT_SCRIPT, strlen(CLIENT_SCRIPT) + 1); 125 | } 126 | 127 | pid = fork(); 128 | 129 | if (pid == -1) { 130 | perror("Unable to fork\n"); 131 | exit(EXIT_FAILURE); 132 | } 133 | 134 | if (pid==0) { 135 | // Child process, run the script 136 | exit(execv(path, args)); 137 | } 138 | else { 139 | // Parent process 140 | waitpid(pid, &status, 0); 141 | if (WEXITSTATUS(status) == 0) { 142 | // Script executed correctly 143 | printf("[DEBUG] Script ran successfully\n"); 144 | } 145 | else { 146 | // Some error 147 | printf("[DEBUG] Error in running script\n"); 148 | } 149 | } 150 | } 151 | 152 | 153 | /** 154 | * Function to run the tunnel 155 | */ 156 | void run_tunnel(char *dest, int server) 157 | { 158 | struct icmp_packet packet; 159 | int tun_fd, sock_fd; 160 | 161 | fd_set fs; 162 | 163 | tun_fd = tun_alloc("tun0", IFF_TUN | IFF_NO_PI); 164 | 165 | printf("[DEBUG] Starting tunnel - Dest: %s, Server: %d\n", dest, server); 166 | printf("[DEBUG] Opening ICMP socket\n"); 167 | sock_fd = open_icmp_socket(); 168 | 169 | if (server) { 170 | printf("[DEBUG] Binding ICMP socket\n"); 171 | bind_icmp_socket(sock_fd); 172 | } 173 | 174 | configure_network(server); 175 | 176 | while (1) { 177 | FD_ZERO(&fs); 178 | FD_SET(tun_fd, &fs); 179 | FD_SET(sock_fd, &fs); 180 | 181 | select(tun_fd>sock_fd?tun_fd+1:sock_fd+1, &fs, NULL, NULL, NULL); 182 | 183 | if (FD_ISSET(tun_fd, &fs)) { 184 | printf("[DEBUG] Data needs to be readed from tun device\n"); 185 | // Reading data from tun device and sending ICMP packet 186 | 187 | printf("[DEBUG] Preparing ICMP packet to be sent\n"); 188 | // Preparing ICMP packet to be sent 189 | memset(&packet, 0, sizeof(struct icmp_packet)); 190 | printf("[DEBUG] Destination address: %s\n", dest); 191 | 192 | if (sizeof(DEFAULT_ROUTE) > sizeof(packet.src_addr)){ 193 | perror("Lack of space: size of DEFAULT_ROUTE > size of src_addr\n"); 194 | close(tun_fd); 195 | close(sock_fd); 196 | exit(EXIT_FAILURE); 197 | } 198 | strncpy(packet.src_addr, DEFAULT_ROUTE, strlen(DEFAULT_ROUTE) + 1); 199 | 200 | if ((strlen(dest) + 1) > sizeof(packet.dest_addr)){ 201 | perror("Lack of space for copy size of DEFAULT_ROUTE > size of dest_addr\n"); 202 | close(sock_fd); 203 | exit(EXIT_FAILURE); 204 | } 205 | strncpy(packet.dest_addr, dest, strlen(dest) + 1); 206 | 207 | if(server) { 208 | set_reply_type(&packet); 209 | } 210 | else { 211 | set_echo_type(&packet); 212 | } 213 | packet.payload = calloc(MTU, sizeof(uint8_t)); 214 | if (packet.payload == NULL){ 215 | perror("No memory available\n"); 216 | exit(EXIT_FAILURE); 217 | } 218 | 219 | packet.payload_size = tun_read(tun_fd, packet.payload, MTU); 220 | if(packet.payload_size == -1) { 221 | perror("Error while reading from tun device\n"); 222 | exit(EXIT_FAILURE); 223 | } 224 | 225 | printf("[DEBUG] Sending ICMP packet with payload_size: %d, payload: %s\n", packet.payload_size, packet.payload); 226 | // Sending ICMP packet 227 | send_icmp_packet(sock_fd, &packet); 228 | 229 | free(packet.payload); 230 | } 231 | 232 | if (FD_ISSET(sock_fd, &fs)) { 233 | printf("[DEBUG] Received ICMP packet\n"); 234 | // Reading data from remote socket and sending to tun device 235 | 236 | // Getting ICMP packet 237 | memset(&packet, 0, sizeof(struct icmp_packet)); 238 | receive_icmp_packet(sock_fd, &packet); 239 | 240 | printf("[DEBUG] Read ICMP packet with src: %s, dest: %s, payload_size: %d, payload: %s\n", packet.src_addr, packet.dest_addr, packet.payload_size, packet.payload); 241 | // Writing out to tun device 242 | tun_write(tun_fd, packet.payload, packet.payload_size); 243 | 244 | printf("[DEBUG] Src address being copied: %s\n", packet.src_addr); 245 | strncpy(dest, packet.src_addr, strlen(packet.src_addr) + 1); 246 | free(packet.payload); 247 | } 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /tunnel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tunnel.h 3 | */ 4 | 5 | #ifndef tunnel_gaurd 6 | #define tunnel_gaurd 7 | 8 | #define SERVER_SCRIPT "server.sh" 9 | #define CLIENT_SCRIPT "client.sh" 10 | 11 | /** 12 | * Function to allocate a tunnel 13 | */ 14 | int tun_alloc(char *dev, int flags); 15 | 16 | /** 17 | * Function to read from a tunnel 18 | */ 19 | int tun_read(int tun_fd, char *buffer, int length); 20 | 21 | /** 22 | * Function to write to a tunnel 23 | */ 24 | int tun_write(int tun_fd, char *buffer, int length); 25 | 26 | /** 27 | * Function to run the tunnel 28 | */ 29 | void run_tunnel(char *dest, int server); 30 | 31 | #endif 32 | --------------------------------------------------------------------------------