ng_bridge + ng_ksocket
Alexander Motin
mav at mavhome.dp.ua
Fri Dec 12 01:20:04 PST 2008
Nikos Vassiliadis wrote:
> I would like to create an ethernet over UDP tunnel. For my
> purposes, using ng_bridge and ng_ksocket seem fine. The
> problem is that the peer address/port is not known, since
> it will be behind a NAT device and will have a dynamically
> assigned IP address. In userspace I would use something like
> recvfrom() to get the peer address. I don't know what to do
> for ngctl and ng_ksocket. Any suggestions? Is this doable?
> Is there something I can do to circumvent the problem?
Five years ago I had the same problem. In result, I have written a small
program which monitor interface with libpcap and calls script to
reconnect ng_ksocket to the new peer address/port when it changes.
The code is old, dirty and was not used for a long time, but if you wish
to try that way - it is attached.
--
Alexander Motin
-------------- next part --------------
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
extern "C" {
# include <unistd.h>
# include <sys/types.h>
# include <pthread.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <net/if.h>
# include <signal.h>
# include <net/ethernet.h>
# include <pcap.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include <netinet/in_systm.h>
# include <netinet/ip.h>
# include <netinet/udp.h>
# include <errno.h>
};
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <map>
extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;
extern int optreset;
char our_iface[5];
char our_addr[16];
int our_port;
char our_script[128];
unsigned int cur_addr=0;
unsigned int cur_port=0;
void discard(int sig) {
std::cerr << "ÐÏÌÕÞÅÎ ÓÉÇÎÁÌ" << std::endl;
}
void usage() {
std::cout << "program -i iface -a addr -p port -s script" << std::endl;
}
int if_ip(register const u_char *buf, unsigned int size) {
if (size < sizeof(struct ip)) {
std::cerr << "it is too small (" << size << " bytes) to be an ip packet." << std::endl;
return 1;
}
struct ip *ip = (struct ip*) buf;
if (ip->ip_v != IPVERSION) {
std::cerr << "ip ver != "
<< IPVERSION << ": discard " << size
<< "bytes" << std::endl;
return 2;
}
if ((ip->ip_p == IPPROTO_UDP)&&((ntohs(ip->ip_off) & IP_OFFMASK) == 0)) {
u_int hlen = ip->ip_hl * 4;
u_char *cp = (u_char *)ip + hlen;
unsigned int addr=ip->ip_src.s_addr;
struct in_addr in;
in.s_addr=addr;
unsigned int port=ntohs(((struct udphdr *)cp)->uh_sport);
if ((cur_addr!=addr) || (cur_port!=port)) {
std::cerr << "CHANGED to " << inet_ntoa(in)<< ":" << port << std::endl;
cur_addr=addr;
cur_port=port;
switch (fork()) {
case 0:
char tmp[128];
snprintf(tmp,128,"%s:%d",inet_ntoa(in),port);
// std::cerr << our_script<<","<<our_script<<","<<tmp << std::endl;
std::cerr << "execl():" << execl(our_script,our_script,tmp,(char *)0 );
std::cerr << " " << errno << std::endl;
break;
case -1:
std::cerr << "Can't fork()!" << std::endl;
break;
default:
break;
}
}
}
return 0;
}
#undef ETHER_MIN_LEN
#define ETHER_MIN_LEN 14
void if_ether(u_char *user, const struct pcap_pkthdr *h,
register const u_char *buf) {
if (!ETHER_IS_VALID_LEN(h->caplen)) {
// validate Ether packet length
return;
}
struct ether_header *p = (struct ether_header *)buf;
if (ntohs(p->ether_type)==ETHERTYPE_IP) {
if_ip(buf+sizeof(struct ether_header),
h->caplen-sizeof(struct ether_header));
}
return;
}
int main(int argc, char *argv[])
{
int ch;
while ((ch = getopt(argc, argv,"i:a:p:s:"))!=-1) {
switch (ch) {
case 'i':
strncpy(our_iface,optarg,5);
break;
case 'a':
strncpy(our_addr,optarg,16);
break;
case 'p':
our_port = atoi(optarg);
break;
case 's':
strncpy(our_script,optarg,128);
break;
case '?':
default:
usage();
return 1;
}
}
//-------------------------------------------
signal(SIGTERM, discard);
siginterrupt(SIGTERM, 1);
pcap_t *pd;
char ebuf[PCAP_ERRBUF_SIZE];
/* open bpf with required snaplen */
if ((pd = pcap_open_live(our_iface, 100,
0/*no_promisc...*/, 10000, ebuf)) == NULL) {
std::cerr<<"ÏÛÉÂËÁ pcap_open_live " <<std::endl;
std::cerr<< " " << ebuf <<std::endl;
return 1;
}
struct bpf_program fcode;
bpf_u_int32 netmask=0;
int Oflag = 1;
char expr[128];
int num;
snprintf(expr,128,"udp and dst host %s and dst port %d",our_addr,our_port);
/* and compile it */
if (pcap_compile(pd, &fcode, expr,
Oflag, netmask) < 0 ||
pcap_setfilter(pd, &fcode) < 0) {
std::cerr << "FIXME!!! bad filter: "
<< pcap_geterr(pd) << std::endl;
pcap_close(pd);
return 2;
}
while (1) {
num = pcap_dispatch(pd, -1,
if_ether, NULL);
};
return 0;
}
More information about the freebsd-net
mailing list