I wrote this little program to deal with the situation where there are a number of workgroups on a number of subnets with no WINS server [actually I couldn't get this configuration to run with a WINS server - but that's another story] You run this program on machines bridging your subnets and it listens for netbios nameserver packets and forwards them. [Broadcast packets are sent on to other nets as broadcast packets, the unicast replies are returned as unicast replies] It also sends a copy of any netbios traffic it sees to the local nmbd which will be running on a different port. So I have a machine running samba bridging eth0 192.168.42.0/24 eth1 192.168.48.0/24 I start nmbd with nmbd -D -p 138 and this program nbnsfw 138 eth0 eth1 then my windows machines on each side can resolve names without a WINS server and across multiple workgroups. take care, J. -------------- next part -------------- /* * nbnsfw.c: * * Copyright (c) 2003 James McKenzie <james@fishsoup.dhs.org>, * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ static char rcsid[] "$Id: nbnsfw.c,v 1.2 2003/02/20 22:00:46 root Exp root $"; /* * $Log: nbnsfw.c,v $ * Revision 1.2 2003/02/20 22:00:46 root * # * * Revision 1.1 2003/02/20 21:54:22 root * Initial revision * */ #include <syslog.h> #include <stdio.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <strings.h> #include <malloc.h> #include <net/if.h> #include <arpa/inet.h> #define NETBIOSPORT 137 typedef struct iface_struct { struct iface_struct *next; char *name; int fd; struct sockaddr_in me; struct sockaddr_in nmbd; struct sockaddr_in bcast; struct sockaddr_in addr_cache[0x10000]; } *iface; iface ifs; void open_if (char *name, int nb_port, int dm_port) { struct sockaddr_in me = { 0 }; iface i = (iface) malloc (sizeof (struct iface_struct)); int fd; int one = 1; int j; struct ifreq ifr = { 0 }; bzero (i, sizeof (struct iface_struct)); i->name = strdup (name); i->fd = socket (AF_INET, SOCK_DGRAM, 0); if (i->fd < 0) { syslog (LOG_ERR, "Can't open socket: %m"); exit (1); } strcpy (&ifr.ifr_name[0], name); if (setsockopt (i->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr))) { syslog (LOG_ERR, "Can't bind to interface %s: %m", name); exit (1); } bzero (&ifr, sizeof (ifr)); strcpy (&ifr.ifr_name[0], name); if (ioctl (i->fd, SIOCGIFADDR, &ifr)) { syslog (LOG_ERR, "Can't get ip address for interface %s: %m", name); exit (1); } bcopy (&ifr.ifr_addr, &i->me, sizeof (struct sockaddr_in)); i->me.sin_port = htons (nb_port); bzero (&ifr, sizeof (ifr)); strcpy (&ifr.ifr_name[0], name); if (ioctl (i->fd, SIOCGIFBRDADDR, &ifr)) { syslog (LOG_ERR, "Can't get broadcast address for interface %s: %m", name); exit (1); } bcopy (&ifr.ifr_addr, &i->bcast, sizeof (struct sockaddr_in)); i->bcast.sin_port = htons (nb_port); me.sin_addr.s_addr = INADDR_ANY; me.sin_port = htons (nb_port); if (bind (i->fd, (struct sockaddr *) &me, sizeof (struct sockaddr_in)) < 00) { syslog (LOG_ERR, "Can't bind to port %d on interface %s: %m", nb_port, name); exit (1); } if (setsockopt (i->fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof (one))) { syslog (LOG_ERR, "Can't enable broadcasts on interface %s: %m", name); exit (1); } i->nmbd = i->me; i->nmbd.sin_port = htons (dm_port); for (j = 0; j < 0x10000; ++j) { i->addr_cache[j].sin_addr.s_addr = INADDR_BROADCAST; i->addr_cache[j].sin_port = htons (nb_port); } { char buf[1024], *ptr = buf; ptr + sprintf (ptr, "Initialized %s ip %s", name, inet_ntoa (i->me.sin_addr)); ptr += sprintf (ptr, " bcast %s", inet_ntoa (i->bcast.sin_addr)); syslog (LOG_ERR, ptr); } i->next = ifs; ifs = i; } int main (int argc, char **argv) { unsigned char buf[8192]; int w = getdtablesize (); int len; int fromlen; iface i, j; struct sockaddr_in from; fd_set rfds; int tid; int bcast; int dmport; if (argc < 3) { fprintf (stderr, "Usage:\n"); fprintf (stderr, "%s nmbdport interface [interface] [interface] ...\n"); exit (1); } openlog ("nbnsfw", LOG_CONS, LOG_DAEMON); daemon (0, 0); setsid (); argc--; argv++; dmport = atoi (*(argv++)); argc--; while (argc--) { open_if (*(argv++), NETBIOSPORT, dmport); } syslog (LOG_ERR, "Local nmbd port is %d", dmport); for (;;) { FD_ZERO (&rfds); for (i = ifs; i; i = i->next) FD_SET (i->fd, &rfds); select (w, &rfds, 0, 0, NULL); for (i = ifs; i; i = i->next) { if (FD_ISSET (i->fd, &rfds)) { int me = 0; bzero (&from, fromlen = sizeof (from)); len recvfrom (i->fd, buf, sizeof (buf), 0, (struct sockaddr *) &from, &fromlen); if (!len) continue; if (fromlen != sizeof (struct sockaddr_in)) continue; for (j = ifs; j; j = j->next) if (from.sin_addr.s_addr == j->me.sin_addr.s_addr) me++; if (me) continue; tid = (buf[0] << 8) + buf[1]; bcast = buf[3] & 0x10; i->addr_cache[tid] = from; #if 0 printf ("%s %s.%d T%04x %s ->\n", i->name, inet_ntoa (from.sin_addr), ntohs (from.sin_port), tid, bcast ? "(BROAD)" : " "); #endif for (j = ifs; j; j = j->next) { struct sockaddr_in to; if (j == i) continue; if (bcast) { /*It's a broadcast packet send it out */ /*on the bcast address */ to = j->bcast; } else { /*It's unicast, look up the tid and send */ /*it to a responsible citizen */ to = j->addr_cache[tid]; } #if 0 printf ("\t\t\t\t\t\t%s %s.%d\n", j->name, inet_ntoa (to.sin_addr), ntohs (to.sin_port)); #endif sendto (j->fd, buf, len, 0, (struct sockaddr *) &to, sizeof (struct sockaddr_in)); } /*Copy any packets we se to our poor belegured NMB */ /*Deamon running on port whatever on the interface */ /*the packet entered on */ sendto (i->fd, buf, len, 0, (struct sockaddr *) &i->nmbd, sizeof (struct sockaddr_in)); } } } }