Current patch for DHCP discovery of WINS servers
Andrew Bartlett
abartlet at pcug.org.au
Sun Jan 13 18:20:03 GMT 2002
Andrew Bartlett wrote:
>
> Andrew Bartlett wrote:
> >
> > Tridge:
> > I've regenerated (bug not tested) this against current HEAD. Probably
> > best to make it use the generic cache you were talking about on IRC.
> > I've #if 0'ed out the dhcp-discover version. Its probably fine, but I
> > had reservations at the time I was looking at this.
> >
> > Shirish:
> > Have you updated this patch since you first proposed it? Its starting
> > to get the serious attention it deserves, so it may yet see the light of
> > day :-)
> >
> > Andrew Bartlett
>
> OK, so I forgot to include the new file in the patch :-)
>
> Attached is the whole patch...
OK, so its really the whole patch this time...
Andrew Bartlett
--
Andrew Bartlett abartlet at pcug.org.au
Manager, Authentication Subsystems, Samba Team abartlet at samba.org
Student Network Administrator, Hawker College abartlet at hawkerc.net
http://samba.org http://build.samba.org http://hawkerc.net
-------------- next part --------------
? include/nmbd_dhcp_for_wins.h
? nmbd/nmbd_dhcp_for_wins.c
? nsswitch/.libs
Index: Makefile.in
===================================================================
RCS file: /data/cvs/samba/source/Makefile.in,v
retrieving revision 1.433
diff -u -r1.433 Makefile.in
--- Makefile.in 12 Jan 2002 23:57:09 -0000 1.433
+++ Makefile.in 13 Jan 2002 13:19:18 -0000
@@ -249,7 +249,8 @@
nmbd/nmbd_processlogon.o nmbd/nmbd_responserecordsdb.o \
nmbd/nmbd_sendannounce.o nmbd/nmbd_serverlistdb.o \
nmbd/nmbd_subnetdb.o nmbd/nmbd_winsproxy.o nmbd/nmbd_winsserver.o \
- nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o
+ nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o \
+ nmbd/nmbd_dhcp_for_wins.o
NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
$(PROFILE_OBJ) $(LIB_OBJ)
Index: nmbd/nmbd.c
===================================================================
RCS file: /data/cvs/samba/source/nmbd/nmbd.c,v
retrieving revision 1.129
diff -u -r1.129 nmbd.c
--- nmbd/nmbd.c 30 Dec 2001 01:46:37 -0000 1.129
+++ nmbd/nmbd.c 13 Jan 2002 13:19:22 -0000
@@ -261,6 +261,8 @@
static BOOL reload_nmbd_services(BOOL test)
{
BOOL ret;
+ struct in_addr wins_server;
+
extern fstring remote_machine;
fstrcpy( remote_machine, "nmbd" );
@@ -288,6 +290,17 @@
reload_nmbd_services( True );
}
+ /* Here, we discover wins servers using dhcp if asked to */
+ if (lp_dhcp_for_wins()) {
+ if(discover_wins_server(&wins_server)) {
+ set_wins_server(wins_server);
+ DEBUG(3, ("reload_nmbd_services: Configured WINS server as %s using DHCP.\n", inet_ntoa(wins_server)) );
+
+ } else {
+ DEBUG(0, ("reload_nmbd_services: Failed to configure WINS server setting using DHCP.\n") );
+ }
+ }
+
/* Do a sanity check for a misconfigured nmbd */
if( lp_wins_support() && wins_srv_count() )
{
@@ -773,8 +786,21 @@
DEBUG( 1, ( "Netbios nameserver version %s started.\n", VERSION ) );
DEBUGADD( 1, ( "Copyright Andrew Tridgell 1994-1998\n" ) );
+ if (!is_daemon && !is_a_socket(0))
+ {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon && !opt_interactive)
+ {
+ DEBUG( 2, ( "Becoming a daemon.\n" ) );
+ become_daemon();
+ }
+
if ( !reload_nmbd_services(False) )
return(-1);
+ return True;
if(!init_structs())
return -1;
@@ -790,18 +816,6 @@
}
set_samba_nb_type();
-
- if (!is_daemon && !is_a_socket(0))
- {
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
- is_daemon = True;
- }
-
- if (is_daemon && !opt_interactive)
- {
- DEBUG( 2, ( "Becoming a daemon.\n" ) );
- become_daemon();
- }
#if HAVE_SETPGID
/*
Index: param/loadparm.c
===================================================================
RCS file: /data/cvs/samba/source/param/loadparm.c,v
retrieving revision 1.371
diff -u -r1.371 loadparm.c
--- param/loadparm.c 9 Jan 2002 04:17:24 -0000 1.371
+++ param/loadparm.c 13 Jan 2002 13:19:31 -0000
@@ -2525,15 +2525,46 @@
/***************************************************************************
Handle the WINS SERVER list
***************************************************************************/
+static struct in_addr wins_server = { 0 };
+static BOOL dhcp_for_wins_flag = False;
+
static BOOL handle_wins_server_list( char *pszParmValue, char **ptr )
- {
- if( !wins_srv_load_list( pszParmValue ) )
- return( False ); /* Parse failed. */
-
- string_set( ptr, pszParmValue );
- return( True );
- }
+{
+ if (strncmp(pszParmValue, "dhcp", 5)) {
+ if( !wins_srv_load_list( pszParmValue ) )
+ return( False ); /* Parse failed. */
+
+ string_set( ptr, pszParmValue );
+ return True;
+ }
+
+ /* Discover the WINS server using DHCP if we haven't done it
+ one already
+ */
+ if (wins_server.s_addr != 0) {
+ string_set(ptr, inet_ntoa(wins_server));
+ return True;
+ }
+
+ dhcp_for_wins_flag = True;
+
+ string_set(ptr, "");
+ return True;
+}
+
+BOOL lp_dhcp_for_wins()
+{
+ return dhcp_for_wins_flag;
+}
+void set_wins_server(struct in_addr srv)
+{
+ if (!wins_srv_load_list(inet_ntoa(srv)))
+ return False;
+
+ wins_server.s_addr = srv.s_addr;
+ string_set(&Globals.szWINSserver, inet_ntoa(srv));
+}
/***************************************************************************
Handle the DEBUG level list
--- /dev/null Thu Aug 24 19:00:32 2000
+++ nmbd/nmbd_dhcp_for_wins.c Wed Aug 15 18:25:36 2001
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.0
+ Discover the network WINS server using DHCP.
+
+ Copyright (C) Shirish Kalele 2001.
+
+ 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.
+
+*/
+#ident "@(#) $RCSfile$$Revision$$Date$"
+
+#include "includes.h"
+#include "nmbd_dhcp_for_wins.h"
+
+extern int DEBUGLEVEL;
+
+static unsigned int xid = 92830;
+
+int timed_out = 0;
+
+static void timeout_fn(int arg)
+{
+ timed_out = 1;
+}
+
+static int init_my_addr(struct sockaddr_in *my_addr)
+{
+ struct hostent *myhostentp;
+ char myhostname[256];
+
+ if (!my_addr)
+ return 0;
+
+ bzero((unsigned char *) my_addr, sizeof(struct sockaddr_in));
+ my_addr->sin_family = AF_INET;
+ my_addr->sin_port = htons(DHCP_CLIPORT);
+
+ gethostname(myhostname, 256);
+ myhostentp = gethostbyname(myhostname);
+
+ /* Use the first address */
+
+ memcpy(&my_addr->sin_addr.s_addr, *(myhostentp->h_addr_list),
+ sizeof(my_addr->sin_addr.s_addr));
+
+ return 1;
+}
+
+static int init_bcast_addr(struct sockaddr_in *bcast_addr)
+{
+ if (!bcast_addr)
+ return 0;
+
+ bzero((unsigned char *) bcast_addr, sizeof(struct sockaddr_in));
+ bcast_addr->sin_family = AF_INET;
+ bcast_addr->sin_port = htons(DHCP_SRVPORT);
+ bcast_addr->sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ return 1;
+}
+
+static int creat_dhcp_clisock(struct sockaddr_in cli_addr)
+{
+ int bcast_flag = 1;
+ struct timeval tv;
+
+ int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock == -1) {
+ DEBUG(3, ("creat_dhcp_clisock: socket open failed: %s\n",
+ strerror(errno)) );
+ return -1;
+ }
+
+ /* These two options are needed for Linux */
+ setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &bcast_flag,
+ sizeof (bcast_flag));
+
+ tv.tv_sec = DHCP_WAIT_TIME+1;
+ tv.tv_usec = 0;
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv,
+ sizeof (tv));
+
+ if (bind(sock, (struct sockaddr *) &cli_addr, sizeof(cli_addr))
+ < 0) {
+ DEBUG(3, ("creat_dhcp_clisock: bind udp socket to %s:%d failed: %s\n",
+ inet_ntoa(cli_addr.sin_addr),
+ ntohs(cli_addr.sin_port),
+ strerror(errno)) );
+ return -1;
+ }
+
+ return sock;
+}
+
+static int do_dhcp_request(int sockd, unsigned char dhcp_type,
+ struct sockaddr_in my_addr,
+ struct sockaddr_in bcast_addr)
+{
+ struct dhcp_pkt_t *dhcp_reqp;
+ int dhcp_req_sz;
+
+ /* Our requests have two options: msg-type & param list req
+ for NBNS
+ */
+ dhcp_req_sz = sizeof(struct dhcp_pkt_t) + 7;
+
+ dhcp_reqp = (struct dhcp_pkt_t *) malloc(dhcp_req_sz);
+
+ if (dhcp_reqp == NULL) {
+ DEBUG(0, ("do_dhcp_request: malloc failed: %s",
+ strerror(errno)) );
+ return -1;
+ }
+
+ bzero((char *) dhcp_reqp, dhcp_req_sz);
+ dhcp_reqp->op = 1; /* BOOTP request */
+ dhcp_reqp->htype = 1; /* 10Mb Ethernet */
+ dhcp_reqp->hlen = 6; /* MAC address size */
+ dhcp_reqp->hops = 0;
+ dhcp_reqp->xid = htonl(xid);
+ dhcp_reqp->secs = 0;
+ dhcp_reqp->flags = 0;
+ dhcp_reqp->ciaddr = my_addr.sin_addr.s_addr;
+ dhcp_reqp->yiaddr = 0;
+ dhcp_reqp->siaddr = 0;
+ dhcp_reqp->giaddr = 0;
+ memset(dhcp_reqp->chaddr, 0, 16);
+ memset(dhcp_reqp->sname, 0, 64);
+ memset(dhcp_reqp->file, 0, 128);
+ dhcp_reqp->magic_cookie = inet_addr("99.130.83.99");
+ dhcp_reqp->option[0] = DHCPOP_MSG_TYPE;
+ dhcp_reqp->option[1] = 1;
+ dhcp_reqp->option[2] = dhcp_type;
+
+ dhcp_reqp->option[3] = DHCPOP_PARAM_LIST;
+ dhcp_reqp->option[4] = 1;
+ dhcp_reqp->option[5] = DHCPOP_NETBIOS_NAME_SERVERS;
+ dhcp_reqp->option[6] = DHCPOP_PAD;
+
+ dhcp_reqp->option[7] = DHCPOP_END;
+
+ if (sendto(sockd, (char *) dhcp_reqp, dhcp_req_sz, 0,
+ (struct sockaddr *) &bcast_addr, sizeof(bcast_addr)) < 0) {
+ DEBUG(0,("do_dhcp_request: Broadcast of DHCP query failed.\n"));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int get_dhcp_reply(int sockd, struct in_addr **pptr,
+ int *cnt, struct in_addr *dhcp_server)
+{
+ struct sockaddr_in from_addr;
+ size_t from_len;
+
+ unsigned char buf[1024];
+ int bufsz = sizeof (buf);
+ int nrecv;
+ struct dhcp_pkt_t *pkt = (struct dhcp_pkt_t *) buf;
+
+ struct in_addr srv_id_addr = { 0 };
+ unsigned char *options;
+ int i = 0, j = 0, data_ndx = 0;
+
+ char srv_addr_str[20];
+
+ struct in_addr *nbns_servers = NULL;
+ int nbns_servers_cnt = 0;
+
+ from_len = sizeof(from_addr);
+
+ *pptr = NULL;
+ *cnt = 0;
+
+ do {
+ nrecv = recvfrom(sockd, (char *) buf, bufsz, 0,
+ (struct sockaddr *) &from_addr,
+ (int *) &from_len);
+ if (nrecv < 0) {
+ if (errno == EINTR && timed_out) {
+ timed_out = 0;
+ signal(SIGALRM, timeout_fn);
+ xid++;
+ DEBUG(5, ("get_dhcp_reply: No reply to DHCP request. recvfrom interrupted by alarm.\n"));
+ return 0;
+ } else if (errno == EAGAIN) {
+ xid++;
+ DEBUG(5, ("get_dhcp_reply: No reply to DHCP request. recvfrom timed out..\n"));
+ return 0;
+ } else {
+ DEBUG(5, ("get_dhcp_reply: Error receiving: %s\n",
+ strerror(errno)) );
+ return 0;
+ }
+ }
+
+ DEBUG(8,("get_dhcp_reply: got %d bytes from host %s:%d\n",
+ nrecv, inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port)) );
+
+ } while (ntohl(pkt->xid) != xid ||
+ ntohs(from_addr.sin_port) != DHCP_SRVPORT);
+
+ DEBUG(5, ("get_dhcp_reply: valid DHCP reply from server %s\n",
+ inet_ntoa(from_addr.sin_addr)) );
+
+ strncpy(srv_addr_str, inet_ntoa(from_addr.sin_addr), 20);
+
+ /* Jump to the options */
+ options = &pkt->option[0];
+
+ /* Parse the options */
+ while (options[i] != DHCPOP_END && i < bufsz) {
+
+ struct dhcp_option_t *opt =
+ (struct dhcp_option_t *) &options[i];
+
+ switch (opt->type) {
+
+ case DHCPOP_PAD:
+ i += 1;
+ break;
+
+ case DHCPOP_SERVER_IDENTIFIER:
+
+ if (opt->len != 4) {
+ DEBUG(8, ("get_dhcp_reply: Invalid data for Server Identifier option in DHCP reply from %s.\n",
+ srv_addr_str) );
+ return 0;
+ }
+
+ memcpy(&srv_id_addr.s_addr, &opt->data[0],
+ sizeof(srv_id_addr.s_addr));
+ i += 6;
+ break;
+
+ case DHCPOP_NETBIOS_NAME_SERVERS:
+
+ if (opt->len == 0 || opt->len % 4 != 0) {
+ DEBUG(8, ("get_dhcp_reply: Invalid data for Netbios Name Server option in DHCP reply from %s.\n",
+ srv_addr_str) );
+ return 0;
+ }
+
+ nbns_servers_cnt = opt->len / 4;
+
+ nbns_servers = (struct in_addr *) malloc(sizeof (struct in_addr) * nbns_servers_cnt);
+
+ if (nbns_servers == NULL) {
+ DEBUG(0, ("get_dhcp_reply: malloc failed: %s\n",
+ strerror(errno)) );
+ return 0;
+ }
+
+ for (j = 0, data_ndx = 0;
+ j < nbns_servers_cnt && data_ndx < opt->len;
+ j++, data_ndx += 4) {
+ memcpy(&nbns_servers[j].s_addr,
+ &opt->data[data_ndx],
+ sizeof (nbns_servers[0].s_addr));
+ }
+
+ i += 2 + opt->len;
+ break;
+ default:
+ i += 2 + opt->len;
+ }
+ }
+
+ *pptr = nbns_servers;
+ *cnt = nbns_servers_cnt;
+ if (dhcp_server)
+ dhcp_server->s_addr = from_addr.sin_addr.s_addr;
+
+ return 1;
+}
+
+int discover_wins_server(struct in_addr *wins_server)
+{
+ struct in_addr dhcp_server;
+ struct in_addr *nbns_servers;
+ int nbns_servers_cnt;
+
+ if (!get_wins_servers(&nbns_servers, &nbns_servers_cnt,
+ &dhcp_server))
+ return 0;
+
+ if (nbns_servers != NULL) {
+ char dhcp_server_str[20];
+ strncpy(dhcp_server_str, inet_ntoa(dhcp_server), 20);
+
+ DEBUG(5, ("discover_wins_server: DHCP server %s returned WINS server: %s\n",
+ dhcp_server_str,
+ inet_ntoa(nbns_servers[0])) );
+ wins_server->s_addr = nbns_servers[0].s_addr;
+ return 1;
+ } else {
+ DEBUG(3,("discover_wins_server: The DHCP server (%s) returned no NetBIOS Name Servers in its response.\n",
+ inet_ntoa(dhcp_server)));
+ return 0;
+ }
+}
+
+int get_wins_servers(struct in_addr **wins_servers, int *wins_servers_cnt,
+ struct in_addr *dhcp_server)
+{
+ int sockd;
+ int ret = 0;
+
+ struct sockaddr_in bcast_addr;
+ struct in_addr srv_addr;
+ struct sockaddr_in my_addr;
+
+ init_my_addr(&my_addr);
+
+ if((sockd = creat_dhcp_clisock(my_addr)) < 0)
+ return 0;
+
+ init_bcast_addr(&bcast_addr);
+
+ signal(SIGALRM, timeout_fn);
+
+ DEBUG(5,("get_wins_servers: Broadcasting a DHCPinform request for list of WINS servers\n"));
+ if (do_dhcp_request(sockd, DHCPINFORM, my_addr, bcast_addr) < 0) {
+ ret = 0;
+ goto done;
+ }
+
+ alarm(DHCP_WAIT_TIME);
+
+ if (get_dhcp_reply(sockd, wins_servers, wins_servers_cnt,
+ dhcp_server)) {
+ ret = 1;
+ goto done;
+ }
+
+#if 0
+ DEBUG(5,("get_wins_servers: No replies to DHCPinform. Broadcasting DHCPdiscover..\n"));
+ if (do_dhcp_request(sockd, DHCPDISCOVER, my_addr, bcast_addr) < 0) {
+ ret = 0;
+ goto done;
+ }
+
+ alarm(DHCP_WAIT_TIME);
+
+ if (get_dhcp_reply(sockd, wins_servers, wins_servers_cnt,
+ dhcp_server)) {
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ DEBUG(5,("get_wins_servers: No DHCP server replied to our pleas.\n"));
+ done:
+ sigrelse(SIGALRM);
+ close(sockd);
+ return ret;
+}
--- /dev/null Thu Aug 24 19:00:32 2000
+++ include/nmbd_dhcp_for_wins.h Wed Aug 15 18:24:52 2001
@@ -0,0 +1,86 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.0
+ Discover the WINS server using DHCP.
+
+ Copyright (C) Shirish Kalele 2001.
+
+ 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.
+
+*/
+
+#ident "@(#) $RCSfile$$Revision$$Date$"
+
+#ifndef _DHCP_DISCOVER_WINS_H
+
+#define _DHCP_DISCOVER_WINS_H
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#define DHCP_CLIPORT 68
+#define DHCP_SRVPORT 67
+
+/* DHCP message types */
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+/* DHCP option codes */
+#define DHCPOP_PAD 0x00
+#define DHCPOP_NETBIOS_NAME_SERVERS 0x2C
+#define DHCPOP_MSG_TYPE 0x35
+#define DHCPOP_SERVER_IDENTIFIER 0x36
+#define DHCPOP_PARAM_LIST 0x37
+#define DHCPOP_END 0xFF
+
+#define DHCP_WAIT_TIME 5 /* seconds */
+
+struct dhcp_pkt_t {
+ unsigned char op;
+ unsigned char htype;
+ unsigned char hlen;
+ unsigned char hops;
+
+ unsigned int xid;
+
+ unsigned short secs;
+ unsigned short flags;
+
+ unsigned int ciaddr;
+ unsigned int yiaddr;
+ unsigned int siaddr;
+ unsigned int giaddr;
+ unsigned char chaddr[16];
+ unsigned char sname[64];
+ unsigned char file[128];
+ unsigned int magic_cookie;
+
+ unsigned char option[1];
+};
+
+struct dhcp_option_t {
+ unsigned char type;
+ unsigned char len;
+ unsigned char data[1];
+};
+
+#endif
More information about the samba-technical
mailing list