Skip to content

Commit

Permalink
Add simple TPROXY example
Browse files Browse the repository at this point in the history
Signed-off-by: Yutaro Hayakawa <yhayakawa3720@gmail.com>
  • Loading branch information
YutaroHayakawa committed Jan 18, 2022
1 parent 2a00f70 commit 9cc3144
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 0 deletions.
9 changes: 9 additions & 0 deletions examples/basic_tproxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM debian:stretch-slim

RUN apt-get update
RUN apt-get install -y gcc iproute2 iptables

ADD tproxy.c /tmp
RUN gcc -o /usr/local/bin/tproxy /tmp/tproxy.c

CMD tproxy
17 changes: 17 additions & 0 deletions examples/basic_tproxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Simple TPROXY example

![](./topo.png)

This example demonstrates the basic cocept of TPROXY (a.k.a. transparent proxy). The very simple proxy server (tproxy.c) transparently intercepts the HTTP traffic between C0 and C1 and dumps the request/response to stdout.

Build `tproxy:latest` docker image

```
tinet build | sudo bash
```

Run demo

```
tinet test | sudo bash
```
84 changes: 84 additions & 0 deletions examples/basic_tproxy/spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
nodes:
- name: C0
image: nicolaka/netshoot
interfaces:
- name: net0
type: direct
args: R0#net0
- name: R0
image: tproxy:latest
buildfile: Dockerfile
buildcontext: .
interfaces:
- name: net0
type: direct
args: C0#net0
- name: net1
type: direct
args: R1#net1
- name: R1
image: nicolaka/netshoot
interfaces:
- name: net0
type: direct
args: C1#net0
- name: net1
type: direct
args: R0#net1
- name: C1
image: nicolaka/netshoot
interfaces:
- name: net0
type: direct
args: R1#net0
node_configs:
- name: C0
cmds:
- cmd: ip link set net0 up
- cmd: ip addr add 10.0.0.2/24 dev net0
- cmd: ip route add default via 10.0.0.1
- name: R0
cmds:
- cmd: ip link set net0 up
- cmd: ip link set net1 up
- cmd: ip addr add 10.0.0.1/24 dev net0
- cmd: ip addr add 192.168.0.1/24 dev net1
- cmd: ip route add 10.0.1.0/24 via 192.168.0.2
- cmd: ip rule add fwmark 0x1 table 100
- cmd: ip route add local 0.0.0.0/0 dev lo table 100
- cmd: iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j MARK --set-mark 0x1
- cmd: iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --on-port 80 --tproxy-mark 0x1
- name: R1
cmds:
- cmd: ip link set net0 up
- cmd: ip link set net1 up
- cmd: ip addr add 10.0.1.1/24 dev net0
- cmd: ip addr add 192.168.0.2/24 dev net1
- cmd: ip route add 10.0.0.0/24 via 192.168.0.1
- name: C1
cmds:
- cmd: ip link set net0 up
- cmd: ip addr add 10.0.1.2/24 dev net0
- cmd: ip route add default via 10.0.1.1
test:
- cmds:
- cmd: echo "==============================================="
- cmd: echo "Starting HTTP server on C1"
- cmd: echo "==============================================="
- cmd: docker exec C1 python3 -m http.server 80 &
- cmd: sleep 10
- cmd: echo "==============================================="
- cmd: echo "curl'ing from C0 to C1"
- cmd: echo "==============================================="
- cmd: docker exec C0 curl -s http://10.0.1.2
- cmd: echo "==============================================="
- cmd: echo "Stopping HTTP server on C1"
- cmd: echo "==============================================="
- cmd: docker exec C1 pkill python3
- cmd: echo "==============================================="
- cmd: echo "Below shows the log of the proxy server on R0"
- cmd: echo "==============================================="
- cmd: docker logs R0
- cmd: echo "==============================================="
- cmd: echo "You should see the proxy surely intercepts"
- cmd: echo "==============================================="
Binary file added examples/basic_tproxy/topo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
178 changes: 178 additions & 0 deletions examples/basic_tproxy/tproxy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

int
create_listen_sock(struct sockaddr_in *addr)
{
int error, sock;

sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("socket");
return -1;
}

error = bind(sock, (struct sockaddr *)addr, sizeof(*addr));
if (error == -1) {
perror("bind");
return -1;
}

error = setsockopt(sock, SOL_IP, IP_TRANSPARENT, &(int){1}, sizeof(int));
if (error == -1) {
perror("setsockopt");
return -1;
}

error = listen(sock, 100);
if (error == -1) {
perror("listen");
return -1;
}

printf("listening...\n");

return sock;
}

#define BUF_LEN 0xffff

void
serve(int lsock)
{
int error;

while (true) {
int local_sock;
struct sockaddr_in local_addr;
socklen_t local_len = sizeof(local_addr);

local_sock = accept(lsock, (struct sockaddr *)&local_addr, &local_len);
if (local_sock == -1) {
perror("accept");
return;
}

printf("Local address %s:%u\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port));

int remote_sock;
struct sockaddr_in remote_addr;
socklen_t remote_len = sizeof(remote_addr);

error = getsockname(local_sock, (struct sockaddr *)&remote_addr, &remote_len);
if (error == -1) {
perror("getpeername");
return;
}

printf("Remote address %s:%u\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));

remote_sock = socket(AF_INET, SOCK_STREAM, 0);
if (remote_sock == -1) {
perror("socket");
return;
}

error = setsockopt(remote_sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
if (error == -1) {
perror("setsockopt");
return;
}

error = setsockopt(remote_sock, SOL_IP, IP_TRANSPARENT, &(int){1}, sizeof(int));
if (error == -1) {
perror("setsockopt");
return;
}

error = bind(remote_sock, (struct sockaddr *)&local_addr, local_len);
if (error == -1) {
perror("bind");
return;
}

error = connect(remote_sock, (struct sockaddr *)&remote_addr, remote_len);
if (error == -1) {
perror("connect");
return;
}

printf("Connected to %s:%u\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));

uint8_t buf[BUF_LEN];
ssize_t rlen, wlen, totlen = 0, ofs = 0;

memset(buf, 0, BUF_LEN);

rlen = read(local_sock, buf, BUF_LEN);
if (rlen == -1) {
perror("read");
return;
}

printf("Forwarding request\n\n%s\n", buf);

wlen = write(remote_sock, buf, rlen);
if (wlen == -1) {
perror("write");
return;
}

memset(buf, 0, BUF_LEN);

while (totlen < BUF_LEN) {
rlen = read(remote_sock, buf + totlen, BUF_LEN - totlen);
if (rlen == -1) {
perror("read");
return;
} else if (rlen == 0) {
break;
}

totlen += rlen;
}

printf("Forwarding reply\n\n%s\n", buf);

ofs = 0;
while (ofs < totlen) {
wlen = write(local_sock, buf + ofs, totlen - ofs);
if (wlen == -1) {
perror("write");
return;
}

ofs += wlen;
}

close(remote_sock);
close(local_sock);
}
}

int
main(void)
{
int lsock;

lsock = create_listen_sock(&(struct sockaddr_in){
.sin_family = AF_INET,
.sin_addr.s_addr = inet_addr("0.0.0.0"),
.sin_port = htons(80),
});
if (lsock == -1) {
fprintf(stderr, "sock_create failed\n");
return EXIT_FAILURE;
}

serve(lsock);

return EXIT_SUCCESS;
}

0 comments on commit 9cc3144

Please sign in to comment.