linux – IP_TRANSPARENT用法
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了linux – IP_TRANSPARENT用法,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4078字,纯文字阅读大概需要6分钟。
内容图文
![linux – IP_TRANSPARENT用法](/upload/InfoBanner/zyjiaocheng/966/fcf34baef57d4da3a818321bda5f05ec.jpg)
我正在为LAN上的Raspberry Pi上的所有端口(1-65535)实现透明的TCP / UDP代理.我目前正在测试将具有目标端口80的TCP数据包路由到Raspberry Pi.我们的想法是,一个接口(cf“proxy ip”)捕获传入流量,另一个接口(cf“server ip”)将其发送到互联网并在原始响应发送到客户端之前对其进行处理.路由器上的必要路由是通过
iptables -t mangle -A PREROUTING -p tcp -s SERVER_IP -j ACCEPT
iptables -t mangle -A PREROUTING -p tcp -s SOME_TEST_CLIENT_IP --dport 80 -j MARK --set-mark 3
ip rule add fwmark 3 table 2
ip route add default via PROXY_IP dev br0 table 2
灵感来自this page.这种架构意味着外部IP地址和Raspberry PI代理接口之间的一对一端口映射.数据包以Raspberry Pi上的正确端口和目标到达(使用tcpdump验证),但是代理不接受连接:没有为传入的SYN发送SYN-ACK.代理监听套接字主要配置为
const char PROXY_IP_ADDR[] = "192.168.1....";
const char SERVER_IP_ADDR[] = "192.168.1....";
...
struct sockaddr_in saProxy = {0};
saProxy.sin_family = AF_INET;
saProxy.sin_port = htons(80);
inet_pton(AF_INET, PROXY_IP_ADDR, &(saProxy.sin_addr.s_addr));
int enable = 1;
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, (const char*)&enable, sizeof(enable)) /*error processing*/;
if(-1 == bind(sockfd, (sockaddr*)&saProxy, sizeof(saProxy))) /* error processing*/;
if(-1 == listen(sockfd, 1)) /* error processing*/;
接下来是epoll_ctl()和epoll_wait().代理已经过测试,可以直接向PROXY_IP发送HTTP请求和NBNS流量,而无需上述路由,并且正在正确接收和处理这些连接.
不幸的是,我发现很少有与IP_TRANSPARENT相关的文档或示例.我之前的original Windows-related question可以在Linux上进行任何测试.内核版本是4.1.13-v7.我怎样才能实现这种代理?
编辑:我相信我可能会错过Raspberry Pi上的一些路由设置,例如可能描述的here,但我对iptables的经验很少,所以我不太明白那里描述的规则,虽然我已经读过非本地流量被内核拒绝,除非设置了一些特定的路由,因为它不知道套接字.
我还测试了直接绑定到外部IP地址并尝试侦听具有此目标地址的数据包,但症状保持不变.
解决方法:
实际上解决方案非常简单.为了将IP_TRANSPARENT用于此目的,您需要将一个侦听套接字绑定到某个端口X.然后,您需要设置以下规则,假设您要重定向通过任何(我相信)接口的所有流量,不包括流量由代理本身生成的.这里代理的IP是192.168.1.100,我们将TCP重定向到端口82,UDP重定向到端口83.
iptables -t mangle -A PREROUTING ! -d 192.168.1.100 -p tcp -j TPROXY --on-port 82 --on-ip 0.0.0.0 --tproxy-mark 0x1/0x1
iptables -t mangle -A PREROUTING ! -d 192.168.1.100 -p udp -j TPROXY --on-port 83 --on-ip 0.0.0.0 --tproxy-mark 0x1/0x1
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
Linux有一个名为tproxy的特殊机制.
对于TCP
从这里开始,accept返回的套接字自动绑定到原始目标并连接到源,因此使用它进行透明代理不需要在代理的这一侧进行更多工作.
为了将套接字的原始目标作为sockaddr_in结构,请像往常一样在accept()返回的套接字上调用getsockname().
对于UDP
要在UDP套接字上获取原始目标,请在绑定之前设置此选项:
int enable = 1;
setsockopt(sockfd, SOL_IP, IP_RECVORIGDSTADDR, (const char*)&enable, sizeof(enable));
然后,接收数据并获取原始目的地
char cmbuf[100];
unsigned char bytes[16*1024];
sockaddr_in srcIpAddr, dstIpAddr;
int dstPort;
iovec iov;
iov.iov_base = bytes;
iov.iov_len = sizeof(bytes)-1;
msghdr mh;
mh.msg_name = &srcIpAddr;
mh.msg_namelen = sizeof(sockaddr_in);
mh.msg_control = cmbuf;
mh.msg_controllen = 100;
mh.msg_iovlen = 1;
mh.msg_iov = &iov;
int res = recvmsg(sock, &mh, 0);
sem_post(&udpSem); //I use a semaphore to indicate when incoming data is read and socket is ready for new datagram to be processed
for(cmsghdr *cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL; cmsg = CMSG_NXTHDR(&mh, cmsg))
{
if(cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_ORIGDSTADDR) continue; //normally we use IP_PKTINFO if not using tproxy, but this would yield 192.168.1.100:83 in the example
std::memcpy(&dstIpAddr, CMSG_DATA(cmsg), sizeof(sockaddr_in));
dstPort = ntohs(dstIpAddr.sin_port);
}
然后,如果我们想要回复数据报,我们需要创建一个新的UDP套接字(因为UDP是无连接的)并将其绑定到数据报的原始目标,存储在dstIpAddr中.我在第一次尝试使用IP_FREEBIND时遇到了一些麻烦,但是这个选项似乎不适用于通过UDP发送数据,我认为它只适用于TCP侦听套接字,所以我们在绑定之前再次使用IP_TRANSPARENT才能绑定到非本地地址.
内容总结
以上是互联网集市为您收集整理的linux – IP_TRANSPARENT用法全部内容,希望文章能够帮你解决linux – IP_TRANSPARENT用法所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。