Skip to content

Instantly share code, notes, and snippets.

@FH0
Created November 28, 2020 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FH0/9abdd7b73d2c20ee6f3572c1096872f7 to your computer and use it in GitHub Desktop.
Save FH0/9abdd7b73d2c20ee6f3572c1096872f7 to your computer and use it in GitHub Desktop.
/*
allow_ip="0.0.0.0/8,100.64.0.0/10,127.0.0.0/8,169.254.0.0/16,192.0.0.0/24,192.0.2.0/24,192.88.99.0/24,198.18.0.0/15,198.51.100.0/24,203.0.113.0/24,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,224.0.0.0/3"
iptables -t mangle -I OUTPUT -d 1.2.0.0/16 -j MARK --set-mark 0x1100
iptables -t mangle -I PREROUTING -i lo -p tcp -j TPROXY --on-port 555 --tproxy-mark 0x1100
iptables -t mangle -I PREROUTING -i lo -p udp -j TPROXY --on-port 555 --tproxy-mark 0x1100
iptables -t mangle -I PREROUTING -d $allow_ip -j ACCEPT
ip route add local default dev lo table 1100
ip rule add fwmark 0x1100 lookup 1100
*/
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/socket.h>
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif
#ifndef IP_ORIGADDRS
#define IP_ORIGADDRS 20
#endif
#ifndef IP_RECVORIGADDRS
#define IP_RECVORIGADDRS IP_ORIGADDRS
#endif
void test_tcp() {
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_fd != -1);
int enable = 1;
assert(setsockopt(listen_fd, SOL_IP, IP_TRANSPARENT, &enable, sizeof(enable)) != -1);
assert(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) != -1);
struct sockaddr_in bind_addr;
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(555);
inet_pton(AF_INET, "0.0.0.0", &bind_addr.sin_addr);
assert(bind(listen_fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != -1);
assert(listen(listen_fd, 128) == 0);
while (true) {
struct sockaddr_in accept_addr;
socklen_t accept_addr_len = sizeof(accept_addr);
int accept_fd = accept(listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
assert(accept_fd != -1);
assert(getsockname(accept_fd, (struct sockaddr *)&accept_addr, &accept_addr_len) != -1);
char addr_str[INET_ADDRSTRLEN];
assert(inet_ntop(AF_INET, &accept_addr.sin_addr, addr_str, INET_ADDRSTRLEN) != NULL);
printf("%s %u\n", addr_str, ntohs(accept_addr.sin_port));
}
}
void test_udp() {
int listen_fd = socket(AF_INET, SOCK_DGRAM, 0);
assert(listen_fd != -1);
int enable = 1;
assert(setsockopt(listen_fd, SOL_IP, IP_TRANSPARENT, &enable, sizeof(enable)) != -1);
assert(setsockopt(listen_fd, SOL_IP, IP_ORIGADDRS, &enable, sizeof(enable)) != -1);
assert(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) != -1);
struct sockaddr_in bind_addr;
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(555);
inet_pton(AF_INET, "0.0.0.0", &bind_addr.sin_addr);
assert(bind(listen_fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != -1);
char control_buf[64], buf[65535];
struct sockaddr_in src_addr;
struct iovec iov = {
.iov_base = buf,
.iov_len = sizeof(buf)};
struct msghdr msg = {
.msg_name = &src_addr,
.msg_namelen = sizeof(src_addr),
.msg_control = control_buf,
.msg_controllen = sizeof(control_buf),
.msg_iov = &iov,
.msg_iovlen = 1};
while (true) {
int nrecv = recvmsg(listen_fd, &msg, 0);
assert(nrecv != -1);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
for (; cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_RECVORIGADDRS) {
puts("here");
continue;
}
struct sockaddr_in dst_addr = *(struct sockaddr_in *)CMSG_DATA(cmsg);
dst_addr.sin_family = AF_INET;
char addr_str[INET_ADDRSTRLEN];
assert(inet_ntop(AF_INET, &dst_addr.sin_addr, addr_str, INET_ADDRSTRLEN) != NULL);
printf("%s %u\n", addr_str, ntohs(dst_addr.sin_port));
break;
}
assert(cmsg != NULL);
}
}
int main(int argc, char const *argv[]) {
// test_tcp();
test_udp();
return 0;
}
@FH0
Copy link
Author

FH0 commented Nov 28, 2020

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment