终于找到了NAT检测源码,大家快来看

铖邑 2006-05-24 10:41:32
记得上回有位同志询问P2P通信方面的问题,想做NAT穿透的编程。我曾答应找到检测代码之后,一定公布给大家。今天总算找到了,不敢自专,给大家共享,作为大家支持偶当版主的回报吧。

这个代码分成2部分:server.c部分是运行在国外的某些机器上,配合我们本机程序检测NAT穿透的服务程序;natcheck.c是运行在本机的检测程序。

本人也没有仔细研究这份代码,但是运行了一下,可以得到正确结果。忘记原来是在哪个网站上下载的,好象那个网站上面还有一些英文资料。

下面就给出这2段代码。
...全文
1137 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
meikeer 2006-06-04
  • 打赏
  • 举报
回复
学习一下,没有现在的BCB的代码吗?
iec 2006-05-26
  • 打赏
  • 举报
回复
mark 代码比较复杂,我已做了,代码没有楼主那么复杂.
constantine 2006-05-26
  • 打赏
  • 举报
回复
支持一下
constantine 2006-05-26
  • 打赏
  • 举报
回复
台湾delphi.ktop好像也有一个
daydayup234 2006-05-26
  • 打赏
  • 举报
回复
虽然不懂,还是收藏并致谢
Malacca 2006-05-26
  • 打赏
  • 举报
回复
稍微看了一下,好象同时支持TCP和UDP呢,不错啊,收藏
happyct 2006-05-26
  • 打赏
  • 举报
回复
能否把工程文件给我?QQ@35238246.com
lbg 2006-05-26
  • 打赏
  • 举报
回复
iec(冰冰凉) ,能给些代码研究研究吗?lubangguo@hotmail.com
zsl6658 2006-05-25
  • 打赏
  • 举报
回复
mark
铖邑 2006-05-25
  • 打赏
  • 举报
回复
大家好象都没有兴趣?

代码比较长,看起来很累,我找到网站了,有兴趣自己去看看http://midcom-p2p.sourceforge.net/
truelove7283159 2006-05-25
  • 打赏
  • 举报
回复
强烈支持!!
pp616 2006-05-25
  • 打赏
  • 举报
回复
强烈支持!!
Wyi23 2006-05-25
  • 打赏
  • 举报
回复
太好了LZ,狂顶!!
cbdxl 2006-05-25
  • 打赏
  • 举报
回复
下来看看!谢谢LZ
chenhu_doc 2006-05-25
  • 打赏
  • 举报
回复

强烈支持xpdavis!!!

这份代码值得一看。。。
铖邑 2006-05-24
  • 打赏
  • 举报
回复
FD_ZERO(&fds);
FD_SET(dstsock, &fds);

/* Wait a few seconds to make sure the first couple SYNs
have a chance to reach the firewall (and hopefully be dropped)
before signaling the client to initiate a simultaneous
outgoing connection to us. */
tv.tv_sec = 5;
tv.tv_usec = 0;
tfds = fds;
if (select(dstsock+1, 0, &tfds, 0, &tv) < 0)
perrordie("select dstsock");
if (FD_ISSET(dstsock, &tfds)) {
/* The firewall didn't prevent our incoming connection. */
if (verbose)
fprintf(stderr,
"Callback connection finished prematurely\n");
} else {
/* The right thing happened -
the firewall appears to be dropping our SYNs to the client.
So signal server 2 to send its reply to the client,
which will cause the client to initiate its open to us. */
close(clisock);
clisock = -1;

if (verbose)
fprintf(stderr,
"Signaling client to initiate connection\n");

/* Wait until dstsock connects or fails. */
tfds = fds;
if (select(dstsock+1, 0, &tfds, 0, 0) < 0)
perrordie("select dstsock");
assert(FD_ISSET(dstsock, &tfds));

if (verbose)
fprintf(stderr, "Callback connection established\n");
}

/* Now place the callback socket back in blocking mode. */
setblock(dstsock);

/* Push the reply to the client */
rc = write(dstsock, &rp, sizeof(rp));
if (rc < 0)
perrordie("write dstsock");

if (verbose)
fprintf(stderr, "Callback connection to %s:%d complete\n",
inet_ntoa(rp.pubaddr), ntohs(rp.pubport));

/* If the connection completed prematurely,
wait five more seconds before uncorking server 2's reply
to ensure that the client has time to notice
that the connection got through too early. */
if (clisock >= 0) {
sleep(5);
close(clisock);
}

close(dstsock);
exit(0);
}

/* Serve a UDP request if we're a bounce server (3) */
void bounceudp(int udpsock, int uprivsock)
{
struct sockaddr_in sin;
socklen_t sinlen;
struct reply rp;
int rc;

sinlen = sizeof(sin);
rc = recvfrom(uprivsock, &rp, sizeof(rp), 0,
(struct sockaddr*)&sin, &sinlen);
if (rc < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN)
perrordie("recvmsg");
return;
}
if (rc < sizeof(rp)) {
if (verbose)
fprintf(stderr, "Runt UDP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
return; /* drop */
}
if (rp.magic != htonl(REQMAGIC)) {
if (verbose)
fprintf(stderr, "Invalid UDP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
return; /* drop */
}

if (verbose) {
fprintf(stderr, "UDP bounce request from %s:%d ",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
fprintf(stderr, "to %s:%d\n",
inet_ntoa(rp.pubaddr), ntohs(rp.pubport));
}

/* Turn it into a reply */
rp.magic = htonl(REPLMAGIC);

/* Echo the reply to the client */
sin.sin_family = AF_INET;
sin.sin_addr = rp.pubaddr;
sin.sin_port = rp.pubport;
if (sendto(udpsock, &rp, sizeof(rp), 0,
(struct sockaddr*)&sin, sizeof(sin)) < 0)
perror("sendto");
}

void bouncemain()
{
int udpsock, tprivsock, uprivsock;
struct sockaddr_in sin;
int rc;

/* Only bind a UDP socket to SERVSOCK */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
udpsock = mksock(SOCK_DGRAM);
sin.sin_port = htons(SERVPORT);
if (bind(udpsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind udpsock");

/* Bind both TCP and UDP sockets to PRIVSOCK */
tprivsock = mksock(SOCK_STREAM);
uprivsock = mksock(SOCK_DGRAM);
sin.sin_port = htons(PRIVPORT);
if (bind(tprivsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind tprivsock");
if (bind(uprivsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind uprivsock");

/* Make the sockets nonblocking */
setnonblock(udpsock);
setnonblock(tprivsock);
setnonblock(uprivsock);

/* Listen on the TCP private socket. */
if (listen(tprivsock, 0) < 0)
perrordie("listen");

/* Become a daemon */
rc = fork();
if (rc < 0)
perrordie("fork");
if (rc != 0)
exit(0);

/* Loop forever receiving messages and sending pings */
while (1) {
int maxsock = 0;
fd_set fds;

FD_ZERO(&fds);
FD_SET(tprivsock, &fds); maxsock = max(maxsock, tprivsock);
FD_SET(uprivsock, &fds); maxsock = max(maxsock, uprivsock);
rc = select(maxsock+1, &fds, 0, 0, 0);
if (rc < 0)
perrordie("select");

bouncetcp(tprivsock);
bounceudp(udpsock, uprivsock);

/* Collect any zombie children */
while (waitpid(-1, 0, WNOHANG) >= 0);
}
}

int main(int argc, char **argv)
{
if (argc >= 2 && strcmp(argv[1], "-v") == 0) {
verbose = 1;
argc--, argv++;
}
if (argc != 2) {
usage:
fprintf(stderr, "Usage: natserver {1,2,3}\n");
exit(1);
}
server = atoi(argv[1]);
if (server < 1 || server > 3)
goto usage;

/* Now run the appropriate server code */
if (server < 3)
servemain();
else
bouncemain();

return 0;
}
铖邑 2006-05-24
  • 打赏
  • 举报
回复
/* Serve a UDP request if we're a regular server (1-2) */
void serveudp(int udpsock)
{
struct sockaddr_in sin;
socklen_t sinlen;
struct request rq;
struct reply rp;
int rc;

sinlen = sizeof(sin);
rc = recvfrom(udpsock, &rq, sizeof(rq), 0,
(struct sockaddr*)&sin, &sinlen);
if (rc < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN)
perror("recvmsg");
return;
}
if (rc < sizeof(rq)) {
if (verbose)
fprintf(stderr, "Runt UDP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
return; /* drop */
}
if (rq.magic != htonl(REQMAGIC)) {
if (verbose)
fprintf(stderr, "Invalid UDP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
return; /* drop */
}

if (verbose)
fprintf(stderr, "UDP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));

/* Build the reply and send it to the client */
rp.magic = htonl(REPLMAGIC);
rp.pubaddr = sin.sin_addr;
rp.pubport = sin.sin_port;
if (sendto(udpsock, &rp, sizeof(rp), 0,
(struct sockaddr*)&sin, sizeof(sin)) < 0)
perror("sendto");

/* If we're server 2,
then also send it as a "bounce request" to server 3 */
if (server == 2) {
if (verbose)
fprintf(stderr, "Forwarding bounce request to %s:%d\n",
inet_ntoa(sin3.sin_addr), ntohs(sin3.sin_port));
rp.magic = htonl(REQMAGIC);
if (sendto(udpsock, &rp, sizeof(rp), 0,
(struct sockaddr*)&sin3, sizeof(sin3)) < 0)
perror("sendto");
}
}

void servemain()
{
int tcpsock, udpsock;
struct sockaddr_in sin;
int rc;

/* Lookup our special "bounce" server */
sin3.sin_family = AF_INET;
getaddr(SERV3, &sin3.sin_addr);
sin3.sin_port = htons(PRIVPORT);
if (verbose)
fprintf(stderr, "bounce server %s at %s\n",
SERV3, inet_ntoa(sin3.sin_addr));

/* Make the sockets we need */
tcpsock = mksock(SOCK_STREAM);
udpsock = mksock(SOCK_DGRAM);

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVPORT);
if (bind(tcpsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind tcpsock");
if (bind(udpsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind udpsock");

/* Make the sockets nonblocking */
setnonblock(tcpsock);
setnonblock(udpsock);

/* Listen on the TCP socket. */
if (listen(tcpsock, 0) < 0)
perrordie("listen");

/* Become a daemon */
rc = fork();
if (rc < 0)
perrordie("fork");
if (rc != 0)
exit(0);

/* Loop forever receiving messages and sending pings */
while (1) {
int maxsock = 0;
fd_set fds;

FD_ZERO(&fds);
FD_SET(tcpsock, &fds); maxsock = max(maxsock, tcpsock);
FD_SET(udpsock, &fds); maxsock = max(maxsock, udpsock);
rc = select(maxsock+1, &fds, 0, 0, 0);
if (rc < 0)
perrordie("select");

servetcp(tcpsock);
serveudp(udpsock);

/* Collect any zombie children */
while (waitpid(-1, 0, WNOHANG) >= 0);
}
}

/* Serve a TCP request if we're a bounce server (3) */
void bouncetcp(int tprivsock)
{
struct sockaddr_in sin;
socklen_t sinlen;
int clisock, dstsock;
struct reply rp;
fd_set fds, tfds;
struct timeval tv;
int rc;

sinlen = sizeof(sin);
clisock = accept(tprivsock, (struct sockaddr*)&sin, &sinlen);
if (clisock < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN)
perrordie("accept");
return;
}

/* Fork off a child to handle this connection */
rc = fork();
if (rc < 0)
perrordie("fork");
if (rc == 0) {
/* In the parent - close clisock and go back for more */
close(clisock);
return;
}

/* In the child */

/* Put the socket in blocking mode */
setblock(clisock);

/* Make sure we don't linger a long time if the other end disappears */
settimeouts(clisock, 20);

/* Read the request */
rc = read(clisock, &rp, sizeof(rp));
if (rc < sizeof(rp)) {
if (verbose)
fprintf(stderr, "Runt TCP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
exit(0); /* drop */
}
if (rp.magic != htonl(REQMAGIC)) {
if (verbose)
fprintf(stderr, "Invalid TCP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
exit(0); /* drop */
}

if (verbose) {
fprintf(stderr, "TCP bounce request from %s:%d ",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
fprintf(stderr, "to %s:%d\n",
inet_ntoa(rp.pubaddr), ntohs(rp.pubport));
}

/* Turn the request into a reply */
rp.magic = htonl(REPLMAGIC);

/* Create a new socket to perform the requested bounce-callback */
dstsock = socket(AF_INET, SOCK_STREAM, 0);
if (dstsock < 0)
perrordie("socket");

/* Make sure it comes from our regular server port */
setreuse(dstsock);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVPORT);
if (bind(dstsock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrordie("bind dstsock");

/* Start a nonclocking connection attempt to the client */
setnonblock(dstsock);
sin.sin_addr = rp.pubaddr;
sin.sin_port = rp.pubport;
if (connect(dstsock, (const struct sockaddr*)&sin, sizeof(sin)) < 0) {
if (errno != EINPROGRESS)
perrordie("connect dstsock");
}
铖邑 2006-05-24
  • 打赏
  • 举报
回复
/* 下面是natserver.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <assert.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif

#define HOST_NAME_MAX 256

#define NTRIES 5

#define SERV1 "pdos.lcs.mit.edu"
#define SERV2 "tears.lcs.mit.edu"
#define SERV3 "sure.lcs.mit.edu"

#define SERVPORT 9856 /* Public port for requests from clients */
#define PRIVPORT 9857 /* Private port for bounce requests only */

#define REQMAGIC 0x76849268
#define REPLMAGIC 0x01967293

struct request {
uint32_t magic;
};

struct reply {
uint32_t magic;
struct in_addr pubaddr;
uint16_t pubport;
};

int server;
int verbose = 0;

/* Internet addresses of server 3 */
struct sockaddr_in sin3;

void perrordie(const char *msg) {
perror(msg);
exit(1);
}

void getaddr(const char *hostname, struct in_addr *addr)
{
struct hostent *h;

h = gethostbyname(hostname);
if (h == 0)
perrordie(hostname);
if (h->h_addrtype != AF_INET) {
fprintf(stderr, "%s: unexpected address type %d\n",
hostname, h->h_addrtype);
}
*addr = *(struct in_addr*)(h->h_addr);
}

int mksock(int type)
{
int sock = socket(AF_INET, type, 0);
if (sock < 0)
perrordie("socket");
return sock;
}

void setblock(int sock)
{
int fl = fcntl(sock, F_GETFL);
if (fl < 0)
perrordie("fcntl");
if (fcntl(sock, F_SETFL, fl & ~O_NONBLOCK) < 0)
perrordie("fcntl");
}

void setnonblock(int sock)
{
int fl = fcntl(sock, F_GETFL);
if (fl < 0)
perrordie("fcntl");
if (fcntl(sock, F_SETFL, fl | O_NONBLOCK) < 0)
perrordie("fcntl");
}

void setreuse(int sock)
{
const int one = 1;

#ifdef SO_REUSEADDR
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
perrordie("setsockopt(SO_REUSEADDR)");
#endif
#ifdef SO_REUSEPORT
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
perrordie("setsockopt(SO_REUSEPORT)");
#endif
}

void settimeouts(int sock, int secs)
{
struct timeval tv;

tv.tv_sec = secs;
tv.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
perrordie("setsockopt(SO_SNDTIMEO)");
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
perrordie("setsockopt(SO_RCVTIMEO)");
}


/* Serve a TCP request if we're a regular server (1-2) */
void servetcp(int tcpsock)
{
struct sockaddr_in sin;
socklen_t sinlen;
int clisock;
struct request rq;
struct reply rp;
int rc;

sinlen = sizeof(sin);
clisock = accept(tcpsock, (struct sockaddr*)&sin, &sinlen);
if (clisock < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN)
perrordie("accept");
return;
}

/* Fork off a child to handle this connection */
rc = fork();
if (rc < 0)
perrordie("fork");
if (rc == 0) {
/* In the parent - close clisock and go back for more */
close(clisock);
return;
}

/* In the child */

/* Put the socket in blocking mode */
setblock(clisock);

/* Make sure we don't linger a long time if the other end disappears */
settimeouts(clisock, 20);

/* Read the request */
rc = read(clisock, &rq, sizeof(rq));
assert(rc <= sizeof(rq));
if (rc < sizeof(rq)) {
if (verbose)
fprintf(stderr, "Runt TCP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
exit(0); /* drop */
}
if (rq.magic != htonl(REQMAGIC)) {
if (verbose)
fprintf(stderr,
"Invalid TCP request %08x from %s:%d\n",
rq.magic,
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
exit(0); /* drop */
}

if (verbose)
fprintf(stderr, "TCP request from %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));

/* If we're server 2,
then first send a "bounce request" to server 3 */
if (server == 2) {
int s3sock;

s3sock = socket(AF_INET, SOCK_STREAM, 0);
if (s3sock < 0)
perrordie("socket s3sock");

settimeouts(s3sock, 20);

if (connect(s3sock, (const struct sockaddr*)&sin3,
sizeof(sin3)) < 0)
perrordie("connect s3sock");

/* Send the bounce request */
rp.magic = htonl(REQMAGIC);
rp.pubaddr = sin.sin_addr;
rp.pubport = sin.sin_port;
if (write(s3sock, &rp, sizeof(rp)) < 0)
perrordie("write s3sock");

/* Wait for server 3's reply,
signaling that we should go ahead and reply to the client.
We don't expect any data, just a clean socket close. */
if (read(s3sock, &rp, 1) < 0)
perrordie("read s3sock");

close(s3sock);
}

/* Build the reply and send it back to the client */
rp.magic = htonl(REPLMAGIC);
rp.pubaddr = sin.sin_addr;
rp.pubport = sin.sin_port;
if (write(clisock, &rp, sizeof(rp)) < 0)
perrordie("sendto");

close(clisock);
exit(0);
}
铖邑 2006-05-24
  • 打赏
  • 举报
回复
/* Make me bunch more TCP and UDP sockets */
tcp1 = mksock(SOCK_STREAM);
tcp2 = mksock(SOCK_STREAM);
tcp3 = mksock(SOCK_STREAM);
tcp4 = mksock(SOCK_STREAM);
udp2 = mksock(SOCK_DGRAM);

/* Enable address and port reuse on the TCP sockets
that we will have to bind to the same port. */
setreuse(tcp0);
setreuse(tcp1);
setreuse(tcp2);
setreuse(tcp3);

/* Place all of our sockets in nonblocking mode */
setnonblock(tcp0);
setnonblock(tcp1);
setnonblock(tcp2);
setnonblock(tcp3);
setnonblock(tcp4);
setnonblock(udp1);
setnonblock(udp2);

/* Bind TCP sockets 1, 2, and 3 to the same name as tcp0. */
if (bind(tcp1, (struct sockaddr*)&tsin, sizeof(tsin)) < 0)
perrdie("bind tcp1 - port reuse not supported?");
if (bind(tcp2, (struct sockaddr*)&tsin, sizeof(tsin)) < 0)
perrdie("bind tcp2");
if (bind(tcp3, (struct sockaddr*)&tsin, sizeof(tsin)) < 0)
perrdie("bind tcp3");

/* TCP socket 0 is our listen socket for incoming TCP connections. */
if (listen(tcp0, 0) < 0)
perrdie("listen");

/* Bind the secondary UDP socket to any port number */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
if (bind(udp2, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrdie("bind");

/* Clear the variables in which we collect
* our various NATted public addresses
* as we discover them. */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
myt1 = sin;
myt2 = sin;
myt3 = sin;
myu1 = sin;
myu2 = sin;
myu3 = sin;

/* Set up our fdsets for select */
maxsock = 0;
FD_ZERO(&rfds); FD_ZERO(&wfds);
FD_SET(tcp0, &rfds); maxsock = max(maxsock, tcp0);
FD_SET(udp1, &rfds); maxsock = max(maxsock, udp1);

/* If our OS eagerly accepts server 3's incoming callback
via our listen socket (as Linux typically does for examlpe),
instead of connecting it to our outgoing tcp3 socket (as BSD does),
then the accepted incoming socket will be saved in incb.
Any other incoming callback we assume to be our own loopback,
and is saved as inloop. */
incb = inloop = -1;

/* Attempt nonblocking TCP connections to server 1 and 2. */
rc = connect(tcp1, (const struct sockaddr*)&sin1, sizeof(sin1));
if (rc < 0 && !econnblock())
perrdie("connect tcp1");
FD_SET(tcp1, &wfds); maxsock = max(maxsock, tcp1);
rc = connect(tcp2, (const struct sockaddr*)&sin2, sizeof(sin2));
if (rc < 0 && !econnblock())
perrdie("connect tcp2");
FD_SET(tcp2, &wfds); maxsock = max(maxsock, tcp2);

/* Ping the servers 10 times */
for (i = 1; i <= NTRIES; i++) {

int timeout;

fprintf(stderr, "Request %d of %d...\n", i, NTRIES);

/* Send ping datagrams from our primary UDP socket
to servers 1 and 2. */
rq.magic = htonl(REQMAGIC);
if (sendto(udp1, (const char*)&rq, sizeof(rq), 0,
(struct sockaddr*)&sin1, sizeof(sin1)) < 0)
perrdie("sendto");
if (sendto(udp1, (const char*)&rq, sizeof(rq), 0,
(struct sockaddr*)&sin2, sizeof(sin2)) < 0)
perrdie("sendto");

/* If we know our primary UDP socket's public address
as seen by server 2 yet,
then also send a ping datagram to that public address
in order to test for loopback translation support. */
rq.magic = htonl(LOOPMAGIC);
if (myu2.sin_addr.s_addr != INADDR_ANY &&
sendto(udp2, (const char*)&rq, sizeof(rq), 0,
(struct sockaddr*)&myu2, sizeof(myu2)) < 0)
perrdie("sendto");

timeout = 0;
while (!timeout) {
struct timeval tv;
fd_set trfds, twfds;

tv.tv_sec = 1; /* wait 1 sec between retries */
tv.tv_usec = 0;
trfds = rfds;
twfds = wfds;
rc = select(maxsock+1, &trfds, &twfds, 0, &tv);
if (rc < 0)
perrdie("select");
if (rc == 0) /* timeout */
timeout = 1;

/* Accept any new incoming TCP connection */
listentcp();

/* Check for available TCP responses */
checktcp(1, &tcp1, &sin1, &myt1);
checktcp(2, &tcp2, &sin2, &myt2);
checktcp(3, &tcp3, &sin3, &myt3);
checktcp(3, &incb, NULL, &myt3);

/* If we get a callback from server 3
before we get a response from server 2,
it means our firewall isn't filtering
incoming connections as aggressively as it could. */
if (myt3.sin_port != 0 && myt2.sin_port == 0)
t3toosoon = 1;

/* Handle TCP loopback stuff */
checkloopback();

/* Receive all available incoming UDP datagrams */
recvudp();
}
}

if (myt1.sin_addr.s_addr == INADDR_ANY) {
fprintf(stderr, "Could not contact TCP server 1 (%s at %s)\n",
SERV1, inet_ntoa(sin1.sin_addr));
die(1);
}
if (myt2.sin_addr.s_addr == INADDR_ANY) {
fprintf(stderr, "Could not contact TCP server 2 (%s at %s)\n",
SERV2, inet_ntoa(sin2.sin_addr));
die(1);
}

if (myu1.sin_addr.s_addr == INADDR_ANY) {
fprintf(stderr, "Could not contact UDP server 1 (%s at %s)\n",
SERV1, inet_ntoa(sin1.sin_addr));
die(1);
}
if (myu2.sin_addr.s_addr == INADDR_ANY) {
fprintf(stderr, "Could not contact UDP server 2 (%s at %s)\n",
SERV2, inet_ntoa(sin2.sin_addr));
die(1);
}

printf("\nTCP RESULTS:\n");

/* Check for public address/port number consistency */
if (myt1.sin_addr.s_addr == myt2.sin_addr.s_addr &&
myt1.sin_port == myt2.sin_port) {
printf("TCP consistent translation: YES "
"(GOOD for peer-to-peer)\n");
} else {
printf("TCP consistent translation: NO "
"(BAD for peer-to-peer)\n");
}

/* See if our simultaneous open with server 3 succeeded */
if (myt3.sin_port != 0) {
printf("TCP simultaneous open: YES "
"(GOOD for peer-to-peer)\n");
} else {
printf("TCP simultaneous open: NO "
"(BAD for peer-to-peer)\n");
}

/* See if loopback messages got through */
if (tcploop) {
printf("TCP loopback translation: YES "
"(GOOD for peer-to-peer)\n");
} else {
printf("TCP loopback translation: NO "
"(BAD for P2P over Twice-NAT)\n");
}

/* See if messages from SERV3 ("attacker") got through */
if (t3toosoon) {
printf("TCP unsolicited connections filtered: NO "
"(BAD for security)\n");
} else {
printf("TCP unsolicited connections filtered: YES "
"(GOOD for security)\n");
}

printf("\nUDP RESULTS:\n");

/* Check for public address/port number consistency */
if (myu1.sin_addr.s_addr == myu2.sin_addr.s_addr &&
myu1.sin_port == myu2.sin_port) {
printf("UDP consistent translation: YES "
"(GOOD for peer-to-peer)\n");
} else {
printf("UDP consistent translation: NO "
"(BAD for peer-to-peer)\n");
}

/* See if loopback messages got through */
if (udploop) {
printf("UDP loopback translation: YES "
"(GOOD for peer-to-peer)\n");
} else {
printf("UDP loopback translation: NO "
"(BAD for P2P over Twice-NAT)\n");
}

/* See if messages from SERV3 ("attacker") got through */
if (myu3.sin_addr.s_addr != INADDR_ANY) {
printf("UDP unsolicited messages filtered: NO "
"(BAD for security)\n");
} else {
printf("UDP unsolicited messages filtered: YES "
"(GOOD for security)\n");
}

return die(0);
}
铖邑 2006-05-24
  • 打赏
  • 举报
回复
int checkudp(int servn, struct reply *rp, struct sockaddr_in *sin,
struct sockaddr_in *servsin, struct sockaddr_in *mysin)
{
if (sin->sin_addr.s_addr != servsin->sin_addr.s_addr ||
sin->sin_port != servsin->sin_port)
return 0;

if (verbose)
fprintf(stderr, "Server %d reports my UDP address as %s:%d\n",
servn, inet_ntoa(rp->pubaddr),
ntohs(rp->pubport));

if (mysin->sin_addr.s_addr != INADDR_ANY) {
/* We already received a response from this server */

if (mysin->sin_addr.s_addr != rp->pubaddr.s_addr ||
mysin->sin_port != rp->pubport) {
fprintf(stderr, "Server %d reports my address "
"INCONSISTENTLY as %s:%d and %s:%d\n",
servn,
inet_ntoa(mysin->sin_addr),
ntohs(mysin->sin_port),
inet_ntoa(rp->pubaddr),
ntohs(rp->pubport));
}

return 1;
}

/* record the address reported by the server */
mysin->sin_family = AF_INET;
mysin->sin_addr = rp->pubaddr;
mysin->sin_port = rp->pubport;

return 1;
}

void recvudp()
{
struct sockaddr_in sin;
socklen_t sinlen;
struct request rq;
struct reply rp;
int rc;

for (;;) {
sinlen = sizeof(sin);
rc = recvfrom(udp1, (char*)&rp, sizeof(rp), 0,
(struct sockaddr*)&sin, &sinlen);
if (rc < 0 && eblock())
break;

if (rc == sizeof(rq) &&
rp.magic == htonl(LOOPMAGIC)) {
if (verbose)
fprintf(stderr,
"Loopback packet from %s port %d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
udploop = 1;
continue;
}

if (rc < sizeof(rp)) {
if (verbose)
fprintf(stderr,
"Received runt packet\n");
continue;
}
if (rp.magic != htonl(REPLMAGIC)) {
if (verbose)
fprintf(stderr,
"Reply with bad magic value\n");
continue;
}

/* Check the source of the datagram */
if (!checkudp(1, &rp, &sin, &sin1, &myu1) &&
!checkudp(2, &rp, &sin, &sin2, &myu2) &&
!checkudp(3, &rp, &sin, &sin3, &myu3)) {
if (verbose)
fprintf(stderr,
"Stray packet from %s\n",
inet_ntoa(sin.sin_addr));
continue;
}
}
}

void checkloopback()
{
struct request rq;
int rc;

/* See if our outgoing loopback connection attempt needs attention. */
if (tcp4 >= 0 && FD_ISSET(tcp4, &wfds)) {

/* Retry the connection attempt. */
rc = connect(tcp4, (const struct sockaddr*)&myt2, sizeof(myt2));
if (rc < 0 && econnblock())
goto notdone; /* still not done */
if (rc < 0 && !econndone())
perrdie("checkloopback connect");

/* Send the loopback request message */
rq.magic = htonl(LOOPMAGIC);
rc = send(tcp4, (const char*)&rq, sizeof(rq), 0);
if (rc < 0 && eblock()) {
goto notdone; /* not yet - just try again later */
} else {
/* success or hard failure -
either way, we're done with this socket. */
FD_CLR(tcp4, &wfds);
close(tcp4);
tcp4 = -1;
}
}
notdone:

/* Check the incoming TCP loopback connection */
if (inloop >= 0 &&
(rc = recv(inloop, (void*)&rq,
sizeof(rq), 0)) >= 0) {
if (verbose)
fprintf(stderr, "Loopback received\n");
if (rc == sizeof(rq) &&
rq.magic == htonl(LOOPMAGIC)) {
tcploop = 1;
}
FD_CLR(inloop, &rfds);
close(inloop);
inloop = -1;
}
}

int main(int argc, char **argv)
{
struct sockaddr_in sin;
socklen_t sinlen;
struct request rq;
int i, rc;
#ifdef WIN32
WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
perrdie("Windows sockets 2.2 startup");
if (verbose) {
fprintf(stderr, "Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
fprintf(stderr, "with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
#endif

/* Dummy uses, for unused parameters */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0)
verbose = 1;
else {
fprintf(stderr, "Usage: natcheck [-v]\n"
"Options:\n"
" -v verbose\n");
exit(1);
}
}

/* Lookup the three well-known servers */
lookup(1, SERV1, &sin1);
lookup(2, SERV2, &sin2);
lookup(3, SERV3, &sin3);

/* Make a TCP socket and bind it to an OS-selected port */
tcp0 = mksock(SOCK_STREAM);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
if (bind(tcp0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrdie("bind tcp0");

/* Find the TCP socket name actually bound (tsin) */
sinlen = sizeof(tsin);
if (getsockname(tcp0, (struct sockaddr*)&tsin, &sinlen) < 0)
perrdie("getsockname tcp0");
assert(tsin.sin_port != 0);
if (verbose)
fprintf(stderr, "Local TCP port: %d\n", ntohs(tsin.sin_port));

/* Make a UDP socket and bind it to an OS-selected port.
Make sure the TCP and UDP ports are different
because some NATs bind the TCP and UDP port namespaces,
which could make the tests interfere with each other. */
do {
udp1 = mksock(SOCK_DGRAM);
if (bind(udp1, (struct sockaddr*)&sin, sizeof(sin)) < 0)
perrdie("bind udp1");

/* Find the TCP socket name actually bound (tsin) */
sinlen = sizeof(usin);
if (getsockname(udp1, (struct sockaddr*)&usin, &sinlen) < 0)
perrdie("getsockname udp1");
assert(usin.sin_port != 0);

} while (usin.sin_port == tsin.sin_port);
if (verbose)
fprintf(stderr, "Local UDP port: %d\n", ntohs(usin.sin_port));
加载更多回复(2)

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧