Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Dec 2008 10:20:00 +0200
From:      Alexander Motin <mav@mavhome.dp.ua>
To:        Nikos Vassiliadis <nvass@teledomenet.gr>
Cc:        freebsd-net@freebsd.org
Subject:   Re: ng_bridge + ng_ksocket
Message-ID:  <49421EB0.7040205@mavhome.dp.ua>
In-Reply-To: <1229005383.00046904.1228994401@10.7.7.3>
References:  <1229005383.00046904.1228994401@10.7.7.3>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------060705090100070300010900
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

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

--------------060705090100070300010900
Content-Type: text/plain;
 name="main.cc"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
 filename="main.cc"

#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;
}

--------------060705090100070300010900--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?49421EB0.7040205>