了解本文则需要参考本人提供的以下的文献内容:
1、轻松修改 LwIP-TCP/IP-Stack-2.13-trunk 网络协议栈令其 tcp_listen accept 任何地址的 TCP_PCB 连接。_liulilittle的博客-CSDN博客
2、LwIP C TCP/IP Stack 正确的TCP连接数据发送姿态_liulilittle的博客-CSDN博客
大概在国内网上关于 “网络游戏加速器” 相关的文章,上面两项根本文提供的实现有一定相关性,可能就我写的内容比较多,相对详细,这个东西有点敏感是一方面,另外也是会损坏 “既得利益群体” 的利润,这个东西目前来说由于各种原因把,文献/知识非常少,懂这套东西的人,都懂,不懂这套东西的人,那是真的很难懂。
今天这篇文章就大致介绍一下实现的原理,如题目所示是基于 LwIP 协议栈的,而不基于 LwIP 协议栈,自主实现的 tun2sys-socket 的半开源,虚拟网络处理工程框架,目前应该只有我们提供的 VEthernet .NET 4.0 Framework x86 一个选项,寻求可稳定工作的 tun2socks by C# 例程;可以检索本人博客或到 github 上面搜索 VEthernet。
基于 LwIP 协议栈实现 tun2sys-socket,技术关键点只需要实现以下两个东西
1、LwIP 协议栈监听的TCP_LISTEN,允许接受来自任何IP地址 TCP_SYN(连接建立)
2、本地环路转发到 sys-socket 本地代理服务器
本文代码从我们的一个强大工程代码之中,来源为 ***-netstack 子网络堆栈实现,不过修改了一下命名空间 ,它实现了上面提到的两个东西,但本地环路代理服务器,需要各位童靴们自行实现。
使用代码可能的法务问题?不存在的,只要说明使用了我们的代码就可以,除非那个公司不要脸剽窃,不过也就仅此而已,我们几乎也不会用这个东西,只是兼容模式下可能会开启它(LwIP 子网络堆栈)因为TCP/IP吞吐速度是个硬伤,网络吞吐速度跑不到 500Mbps 以上就真的挺废的,当然这是因为只有一个线程核在跑 LwIP 协议堆栈。
LwIP 想要实现非常大的网络I/O带宽吞吐量,并非是不可以,但需要实现多进程处理架构(MPA)即一个主控进程从 tun 网卡里面收发IP帧报文,子进程来跑 LwIP 协议堆栈,一个子进程负责多少TCP_PCB process,主控进程负责调度那些 IP+TCP报文分发到那个子进程上面处理,但它无法解决单点吞吐速度不高的问题,走我们的专用主堆栈可以跑几百兆单连接,而通过基于 LwIP 协议实现的 netstack 子网络堆栈只有一百多兆单连接吞吐速度表现力。
补充:如果你不需要中转到本地环路代理服务器上面,那么就 netstack 内的系统套接字就直接连接目标服务器就可以,本实现走本地环路代理服务器这块主要是为了让IO跑的更高,毕竟就一个线程核在处理还跑协议栈,负担太重吞吐性能是个不小得问题。
打开 netstack(LwIP协议堆栈初始化及网络栈就绪)
bool netstack::open(const std::shared_ptr
本地环路代理服务器 accept 到 sys-socket 的时候,通过 “key” 查找当前的 sys-socket 在 lwip/tun 上面想要的IP/PORT链路信息。
key = 被接受的 sys-socket 的 peername 的端口号,getpeername(connect_sockfd, ...)
bool netstack::link(int key, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort);
关闭 netstack 及释放持有的托管与非托管资源
void netstack::close()
1#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace My {
namespace Net {
namespace LwIP {
struct netstack_tcp_socket {
typedef struct {
std::shared_ptr p;
int sz;
} buffer_chunk;
typedef struct {
buffer_chunk buf;
std::function cb;
} send_context;
typedef std::shared_ptr send_context_ptr;
typedef enum {
ENETSTACK_TCP_SENT_LWIP,
ENETSTACK_TCP_SENT_SOCK,
ENETSTACK_TCP_SENT_MAX
} ENETSTACK_TCP_SENT_BUFS;
std::list sents[ENETSTACK_TCP_SENT_MAX];
std::shared_ptr socket;
bool open;
struct tcp_pcb* pcb;
u16_t pnat;
ip_addr_t local_ip;
u16_t local_port;
ip_addr_t remote_ip;
u16_t remote_port;
u8_t buf[1400];
};
typedef std::shared_ptr NetstackSocket;
typedef std::unordered_map Port2Socket;
typedef std::unordered_map Ptr2Socket;
typedef std::recursive_mutex NetstackMutex;
typedef std::lock_guard NetstackMutexScope;
static boost::asio::io_context context_;
static boost::asio::deadline_timer timeout_(context_);
static std::shared_ptr tap_;
static struct netif* netif_ = NULL;
static struct tcp_pcb* pcb_ = NULL;
static Port2Socket n2ss_;
static Ptr2Socket p2ss_;
static NetstackMutex lockobj_;
inline static bool
netstack_tcp_linksocket(int port, const std::shared_ptr& socket) {
if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
return false;
}
if (!socket) {
return false;
}
else {
NetstackMutexScope scope_(lockobj_);
std::pair r_ = n2ss_.insert(std::make_pair(port, socket));
if (!r_.second) {
return false;
}
}
socket->pnat = port;
return true;
}
inline static void*
netstack_tcp_linksocket(struct tcp_pcb* pcb, const std::shared_ptr& socket) {
if (!pcb || !socket) {
return NULL;
}
NetstackMutexScope scope_(lockobj_);
std::pair r_ = p2ss_.insert(std::make_pair(pcb, socket));
return r_.second ? pcb : NULL;
}
inline static std::shared_ptr
netstack_tcp_getsocket(int port) {
if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
return NULL;
}
NetstackMutexScope scope_(lockobj_);
Port2Socket::iterator tail_ = n2ss_.find(port);
Port2Socket::iterator endl_ = n2ss_.end();
return tail_ != endl_ ? tail_->second : NULL;
}
inline static std::shared_ptr
netstack_tcp_getsocket(void* p) {
if (!p) {
return NULL;
}
NetstackMutexScope scope_(lockobj_);
Ptr2Socket::iterator tail_ = p2ss_.find(p);
Ptr2Socket::iterator endl_ = p2ss_.end();
return tail_ != endl_ ? tail_->second : NULL;
}
inline static std::shared_ptr
netstack_tcp_releasesocket(int port) {
if (port <= My::Net::IPEndPoint::MinPort || port > My::Net::IPEndPoint::MaxPort) {
return NULL;
}
std::shared_ptr socket;
do {
NetstackMutexScope scope_(lockobj_);
Port2Socket::iterator tail_ = n2ss_.find(port);
Port2Socket::iterator endl_ = n2ss_.end();
if (tail_ != endl_) {
socket = std::move(tail_->second);
n2ss_.erase(tail_);
}
} while (0);
return std::move(socket);
}
inline static std::shared_ptr
netstack_tcp_releasesocket(void* p) {
if (!p) {
return NULL;
}
std::shared_ptr socket;
do {
NetstackMutexScope scope_(lockobj_);
Ptr2Socket::iterator tail_ = p2ss_.find(p);
Ptr2Socket::iterator endl_ = p2ss_.end();
if (tail_ != endl_) {
socket = std::move(tail_->second);
p2ss_.erase(tail_);
}
} while (0);
return std::move(socket);
}
inline static err_t
netstack_tcp_closesocket(struct tcp_pcb* pcb);
inline static bool
netstack_tcp_closesocket(const std::shared_ptr& socket_);
inline static err_t
netstack_tcp_send(struct tcp_pcb* pcb, void* data, u16_t len, const std::function& callback) {
if (!pcb) {
return ERR_ARG;
}
std::shared_ptr socket_ = netstack_tcp_getsocket(pcb->callback_arg);
if (!socket_) {
return ERR_ABRT;
}
if (!data || !len) {
return ERR_ARG;
}
static auto tcp_enqueue_ =
[](netstack_tcp_socket* socket_, struct tcp_pcb* pcb, void* data, u16_t len, const std::function& callback) {
std::shared_ptr chunk_ = My::make_shared_alloc(len);
memcpy(chunk_.get(), data, len);
netstack_tcp_socket::send_context_ptr context_ =
My::make_shared_object();
context_->buf.p = std::move(chunk_);
context_->buf.sz = len;
context_->cb = callback;
socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].push_back(std::move(context_));
return ERR_OK;
};
if (!socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].empty()) {
return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
}
err_t err = tcp_write(pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err == ERR_OK) {
tcp_output(pcb);
if (callback) {
callback(pcb);
}
return err;
}
else if (err == ERR_MEM) {
return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
}
return err;
}
inline static void
netstack_tcp_arg(struct tcp_pcb* pcb, void* arg) {
if (pcb) {
tcp_arg(pcb, arg);
}
}
inline static void
netstack_tcp_event(struct tcp_pcb* pcb, tcp_recv_fn recv, tcp_sent_fn sent, tcp_err_fn errf, tcp_poll_fn poll) {
if (pcb) {
tcp_recv(pcb, recv ? recv : tcp_recv_null);
tcp_sent(pcb, sent);
tcp_err(pcb, errf);
tcp_poll(pcb, poll, poll ? 8 : 0);
}
}
inline static bool
netstack_tcp_closesocket(const std::shared_ptr& socket_) {
if (!socket_) {
return false;
}
My::Net::Socket::Closesocket(std::move(socket_->socket));
for (int i = netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP; i < netstack_tcp_socket::ENETSTACK_TCP_SENT_MAX; i++) {
socket_->sents[i].clear();
}
struct tcp_pcb* pcb = socket_->pcb;
if (pcb) {
socket_->pcb = NULL;
netstack_tcp_releasesocket(pcb->callback_arg);
}
netstack_tcp_closesocket(pcb);
netstack_tcp_releasesocket(socket_->pnat);
return true;
}
inline static err_t
netstack_tcp_closesocket(struct tcp_pcb* pcb) {
if (!pcb) {
return ERR_ARG;
}
std::shared_ptr socket_ = netstack_tcp_releasesocket(pcb->callback_arg);
netstack_tcp_arg(pcb, NULL);
netstack_tcp_event(pcb, NULL, NULL, NULL, NULL);
if (socket_) {
socket_->pcb = NULL;
netstack_tcp_closesocket(socket_);
}
return tcp_close(pcb);
}
inline static struct pbuf*
netstack_pbuf_alloc(u16_t len) {
if (!len) {
return NULL;
}
return pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
}
inline static void
netstack_pbuf_free(struct pbuf* buf) {
if (buf) {
pbuf_free(buf);
}
}
inline static bool
netstack_tunnel_send(const std::shared_ptr& socket_, void* data, int len, bool unsafe_);
inline static err_t
netstack_tcp_dorecv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) {
LWIP_UNUSED_ARG(arg);
if (p) {
std::shared_ptr socket = netstack_tcp_getsocket(pcb->callback_arg);
if (!socket) {
tcp_abort(pcb);
return ERR_ABRT;
}
for (struct pbuf* q = p; p; p = p->next) {
tcp_recved(pcb, q->len);
netstack_tunnel_send(socket, p->payload, p->len, true);
}
netstack_pbuf_free(p);
}
else if (err == ERR_OK) {
return netstack_tcp_closesocket(pcb);
}
return ERR_OK;
}
inline static err_t
netstack_tcp_dosent(void* arg, struct tcp_pcb* pcb, u16_t len) {
LWIP_UNUSED_ARG(arg);
std::shared_ptr socket_ = netstack_tcp_getsocket(pcb->callback_arg);
if (socket_) {
std::list& sents = socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP];
while (!sents.empty()) { // tcp_sndbuf
err_t err_;
do {
netstack_tcp_socket::send_context_ptr context_ = sents.front();
err_ = tcp_write(pcb,
context_->buf.p.get(),
context_->buf.sz, TCP_WRITE_FLAG_COPY);
if (err_ == ERR_OK) {
tcp_output(pcb);
if (context_->cb) {
context_->cb(pcb);
}
sents.pop_front();
}
} while (0);
if (err_) {
if (err_ == ERR_MEM) {
break;
}
netstack_tcp_closesocket(socket_);
return ERR_ABRT;
}
}
return ERR_OK;
}
else {
tcp_abort(pcb);
return ERR_ABRT;
}
}
inline static void
netstack_tcp_doerrf(void* arg, err_t err) {
std::shared_ptr socket_ = netstack_tcp_getsocket(arg);
if (socket_) {
netstack_tcp_closesocket(socket_);
}
}
inline static err_t
netstack_tcp_dopoll(void* arg, struct tcp_pcb* pcb) {
std::shared_ptr socket = netstack_tcp_getsocket(pcb->callback_arg);
if (socket) {
std::shared_ptr p = socket->socket;
if (p) {
if (p->is_open()) {
return ERR_OK;
}
}
return ERR_ABRT;
}
else {
tcp_abort(pcb);
return ERR_ABRT;
}
}
inline static bool
netstack_tunnel_open(const std::shared_ptr& socket_);
inline static err_t
netstack_tcp_doaccept(void* arg, struct tcp_pcb* pcb, err_t err) {
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
std::shared_ptr socket_ = std::make_shared();
socket_->pnat = 0;
socket_->pcb = pcb;
socket_->open = false;
socket_->socket = std::make_shared(context_);
socket_->local_ip = pcb->remote_ip;
socket_->local_port = pcb->remote_port;
socket_->remote_ip = pcb->local_ip;
socket_->remote_port = pcb->local_port;
void* callback_arg = netstack_tcp_linksocket(pcb, socket_);
netstack_tcp_arg(pcb, callback_arg);
if (callback_arg && netstack_tunnel_open(socket_)) {
netstack_tcp_event(pcb, netstack_tcp_dorecv, netstack_tcp_dosent, netstack_tcp_doerrf, netstack_tcp_dopoll);
return ERR_OK;
}
else {
netstack_tcp_closesocket(socket_);
return ERR_ABRT;
}
}
inline static bool
netstack_tunnel_send(const std::shared_ptr& socket_, void* data, int len, bool unsafe_) {
if (!socket_ || !data || len < 1) {
return false;
}
std::shared_ptr& socket = socket_->socket;
if (!socket || !socket->is_open()) {
return false;
}
if (!socket_->open) {
std::shared_ptr chunk_ = My::make_shared_alloc(len);
memcpy(chunk_.get(), data, len);
netstack_tcp_socket::send_context_ptr context_ =
My::make_shared_object();
context_->buf.p = std::move(chunk_);
context_->buf.sz = len;
socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_SOCK].push_back(std::move(context_));
return true;
}
std::shared_ptr chunk_;
if (unsafe_) {
chunk_ = My::make_shared_alloc(len);
memcpy(chunk_.get(), data, len);
}
else {
chunk_ = *(std::shared_ptr*)data;
}
std::shared_ptr socket__ = socket_;
boost::asio::async_write(*socket, boost::asio::buffer(chunk_.get(), len), [socket__, chunk_](const boost::system::error_code& ec, size_t sz) {
if (ec) {
netstack_tcp_closesocket(socket__);
}
});
return true;
}
inline static bool
netstack_tunnel_dorecv(const std::shared_ptr& socket_) {
if (!socket_) {
return false;
}
std::shared_ptr& socket = socket_->socket;
if (!socket || !socket->is_open()) {
return false;
}
std::shared_ptr socket__ = socket_;
socket->async_read_some(boost::asio::buffer(socket_->buf, sizeof(socket_->buf)), [socket__](const boost::system::error_code& ec, size_t sz) {
int by = std::max(-1, ec ? -1 : sz);
if (by < 1) {
netstack_tcp_closesocket(socket__);
}
else {
netstack_tcp_send(socket__->pcb, socket__->buf, by, [socket__](struct tcp_pcb*) {
netstack_tunnel_dorecv(socket__);
});
}
});
return true;
}
inline static bool
nestack_tunnel_post_all_unsent(const std::shared_ptr& socket_) {
if (!socket_) {
return false;
}
std::list& sents = socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_SOCK];
while (!sents.empty()) {
netstack_tcp_socket::send_context_ptr context_ = sents.front();
sents.pop_front();
netstack_tunnel_send(socket_, std::addressof(context_->buf.p), context_->buf.sz, false);
}
return true;
}
inline static bool
netstack_tunnel_open(const std::shared_ptr& socket_) {
if (!socket_) {
return false;
}
std::shared_ptr taptap = tap_;
if (!taptap) {
return false;
}
std::shared_ptr& socket = socket_->socket;
if (!socket || socket->is_open()) {
return false;
}
boost::system::error_code ec;
try {
if (IP_IS_V4_VAL(socket_->local_ip)) {
socket->open(boost::asio::ip::tcp::v4(), ec);
}
else if (IP_IS_V6_VAL(socket_->local_ip)) {
socket->open(boost::asio::ip::tcp::v6(), ec);
}
else {
return false;
}
if (ec) {
return false;
}
}
catch (std::exception&) {
return false;
}
boost::asio::ip::tcp::endpoint localEP = netstack::localhost();
if (!localEP.port()) {
return false;
}
// 绑定到本地主机网卡上面
int pnat = 0;
try {
boost::asio::ip::tcp::endpoint bindEP(localEP.address(), 0);
socket->bind(bindEP, ec);
if (ec) {
return false;
}
bindEP = socket->local_endpoint(ec);
if (ec) {
return false;
}
pnat = bindEP.port();
}
catch (std::exception&) {
return false;
}
// 建立套接字链路
if (!netstack_tcp_linksocket(pnat, socket_)) {
return false;
}
// 获取文件描述符
int handle = My::Net::Socket::GetHandle(*socket.get());
// 禁用 Nagle
My::Net::Socket::SetNoDelay(handle, taptap->IsNoDelay());
// 禁止 SIGPIPE
My::Net::Socket::SetSignalPipeline(handle, false);
// 允许 IPv4 Fragment
My::Net::Socket::SetDontFragment(handle, false);
// 设置 TypeOfService
My::Net::Socket::SetTypeOfService(handle);
// 链接本地虚拟网络交换机
std::shared_ptr socket__ = socket_;
socket->async_connect(localEP, [socket__](const boost::system::error_code& ec) {
if (ec) {
netstack_tcp_closesocket(socket__);
return;
}
if (socket__->open) {
netstack_tcp_closesocket(socket__);
return;
}
else {
socket__->open = true;
}
bool ok = netstack_tunnel_dorecv(socket__) && nestack_tunnel_post_all_unsent(socket__);
if (!ok) {
netstack_tcp_closesocket(socket__);
return;
}
});
return true;
}
inline static err_t
netstack_ip_output(struct pbuf* p) {
if (!p || !p->len) {
return ERR_BUF;
}
std::shared_ptr packet = My::make_shared_alloc(p->len);
pbuf_copy_partial(p, packet.get(), p->len, 0);
return netstack::output(packet, p->len);
}
inline static err_t
netstack_ip_output_v4(struct netif* netif, struct pbuf* p, const ip4_addr_t* ipaddr) {
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(ipaddr);
return netstack_ip_output(p);
}
inline static err_t
netstack_ip_output_v6(struct netif* netif, struct pbuf* p, const ip6_addr_t* ipaddr) {
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(ipaddr);
return netstack_ip_output(p);
}
inline static bool
netstack_tcp_init() {
struct tcp_pcb* pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 0);
pcb = tcp_listen(pcb);
tcp_arg(pcb, NULL);
tcp_accept(pcb, netstack_tcp_doaccept);
pcb_ = pcb;
return pcb_ != NULL;
}
inline static void
netstack_check_timeouts() {
timeout_.expires_from_now(boost::posix_time::milliseconds(250));
timeout_.async_wait([] (const boost::system::error_code& ec) {
sys_check_timeouts();
netstack_check_timeouts();
});
}
inline static int
nestack_loopback() {
class std_thread_id {
public:
std::thread::native_handle_type _M_thread;
};
std::thread loopback_thread([] {
boost::asio::io_context::work work_(context_);
boost::system::error_code ec_;
SetThreadPriorityToMaxLevel();
context_.restart();
netstack_check_timeouts();
context_.run(ec_);
});
std::thread::id tid = loopback_thread.get_id();
std_thread_id& pid = *(std_thread_id*)&tid;
loopback_thread.detach();
return pid._M_thread;
}
bool
netstack::input(const void* packet, int size) {
if (!packet || size < 1 || !netif_) {
return false;
}
std::shared_ptr taptap = tap_;
if (!taptap) {
return false;
}
struct pbuf* data = netstack_pbuf_alloc(size);
if (!data) {
return false;
}
memcpy(data->payload, packet, size);
context_.post([data, size] {
struct netif* netif = netif_;
if (!netif) {
pbuf_free(data);
return;
}
err_t err = netif->input(data, netif);
if (err != ERR_OK) {
pbuf_free(data);
return;
}
});
My::Net::NetworkStatistics& statistics = taptap->_statistics;
struct ip_hdr* iphdr = (struct ip_hdr*)packet;
int iphdr_hlen = IPH_HL_BYTES(iphdr);
int ip_proto = IPH_PROTO(iphdr);
switch (ip_proto) {
case IP_PROTO_TCP:
{
My::Net::NetworkStatistics::TcpStatistics& tcp_stat = statistics.Tcp;
tcp_stat.OutgoingUnicastPacket++;
tcp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
case IP_PROTO_UDP:
{
My::Net::NetworkStatistics::UdpStatistics& udp_stat = statistics.Udp;
udp_stat.OutgoingUnicastPacket++;
udp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
case IP_PROTO_ICMP:
{
My::Net::NetworkStatistics::Statistics& icmp_stat = statistics.Icmp;
icmp_stat.OutgoingUnicastPacket++;
icmp_stat.OutgoingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
};
My::Net::NetworkStatistics::Statistics& ip_stat = statistics.IPv4;
ip_stat.OutgoingUnicastPacket++;
ip_stat.OutgoingTrafficSize += size;
return true;
}
int
netstack::output(const std::shared_ptr& packet, int size) {
if (!packet || size < 1) {
return ERR_OK;
}
std::shared_ptr taptap = tap_;
if (!taptap) {
return false;
}
std::shared_ptr tap = taptap->Tap;
if (!tap) {
return ERR_IF;
}
if (!tap->Output(packet, size)) {
return ERR_IF;
}
My::Net::NetworkStatistics& statistics = taptap->_statistics;
struct ip_hdr* iphdr = (struct ip_hdr*)packet.get();
int iphdr_hlen = IPH_HL_BYTES(iphdr);
int ip_proto = IPH_PROTO(iphdr);
switch (ip_proto) {
case IP_PROTO_TCP:
{
My::Net::NetworkStatistics::TcpStatistics& tcp_stat = statistics.Tcp;
tcp_stat.IncomingUnicastPacket++;
tcp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
case IP_PROTO_UDP:
{
My::Net::NetworkStatistics::UdpStatistics& udp_stat = statistics.Udp;
udp_stat.IncomingUnicastPacket++;
udp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
case IP_PROTO_ICMP:
{
My::Net::NetworkStatistics::Statistics& icmp_stat = statistics.Icmp;
icmp_stat.IncomingUnicastPacket++;
icmp_stat.IncomingTrafficSize += std::max(0, size - iphdr_hlen);
break;
}
};
My::Net::NetworkStatistics::Statistics& ip_stat = statistics.IPv4;
ip_stat.IncomingUnicastPacket++;
ip_stat.IncomingTrafficSize += size;
return ERR_OK;
}
bool
netstack::open(const std::shared_ptr& tap) {
if (!tap || tap->IsDisposed()) {
return false;
}
std::shared_ptr linux_tap = std::dynamic_pointer_cast(tap->Tap);
if (!linux_tap) {
return false;
}
#ifdef _WIN32
sys_init();
#endif
lwip_init();
struct netif* netif = netif_list;
netif->input = netif->input ? netif->input : ::ip_input;
netif->output = netstack_ip_output_v4; /*netif_loop_output_ipv4*/
netif->output_ip6 = netstack_ip_output_v6; /*netif_loop_output_ipv6*/
ip4_addr_t ips[] = { linux_tap->LocalAddress, linux_tap->NetworkMask, linux_tap->GatewayAddress };
netif_set_ipaddr(netif, ips + 0);
netif_set_netmask(netif, ips + 1);
netif_set_gw(netif, ips + 2);
tap_ = tap;
netif_ = netif;
netif_default = netif;
if (!netstack_tcp_init()) {
return false;
}
return nestack_loopback() != 0;
}
boost::asio::ip::tcp::endpoint
netstack::localhost() {
std::shared_ptr taptap = tap_;
if (!taptap) {
return My::Net::IPEndPoint::WrapAddress(0, 0);
}
if (taptap->IsDisposed()) {
return My::Net::IPEndPoint::WrapAddress(0, 0);
}
std::shared_ptr tun_ = taptap->Tap;
if (!tun_) {
return My::Net::IPEndPoint::WrapAddress(0, 0);
}
My::Net::IPEndPoint localEP(tun_->LocalAddress, taptap->_listenEP.Port);
return My::Net::IPEndPoint::ToEndPoint(localEP);
}
bool
netstack::link(int key, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort) {
key = ntohs(key);
dstAddr = 0;
dstPort = 0;
srcAddr = 0;
srcPort = 0;
std::shared_ptr socket = netstack_tcp_getsocket(key);
if (!socket) {
return false;
}
if (IP_IS_V4_VAL(socket->remote_ip)) {
dstAddr = ip_addr_get_ip4_u32(&socket->remote_ip);
dstPort = socket->remote_port;
}
else {
return false;
}
if (IP_IS_V4_VAL(socket->local_ip)) {
srcAddr = ip_addr_get_ip4_u32(&socket->local_ip);
srcPort = socket->local_port;
return true;
}
else {
return false;
}
}
void
netstack::close() {
context_.post([] {
struct tcp_pcb* pcb = pcb_;
pcb_ = NULL;
netif_ = NULL;
tap_ = NULL;
boost::system::error_code ec_;
try {
timeout_.cancel(ec_);
}
catch (std::exception&) {}
do {
std::unordered_set sockets_;
do {
NetstackMutexScope scope_(lockobj_);
Port2Socket::iterator n2ss_tail_ = n2ss_.begin();
Port2Socket::iterator n2ss_endl_ = n2ss_.end();
for (; n2ss_tail_ != n2ss_endl_; ++n2ss_tail_) {
sockets_.insert(std::move(n2ss_tail_->second));
}
Ptr2Socket::iterator p2ss_tail_ = p2ss_.begin();
Ptr2Socket::iterator p2ss_endl_ = p2ss_.end();
for (; p2ss_tail_ != p2ss_endl_; ++p2ss_tail_) {
sockets_.insert(std::move(p2ss_tail_->second));
}
n2ss_.clear();
p2ss_.clear();
} while (0);
sockets_.clear();
}
while (0);
if (pcb) {
tcp_close(pcb);
}
context_.stop();
});
}
}
}
}