From chris@minotaur.onthe.net.au Sun Dec 10 00:23:19 2000 Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28]) by rt-11.mit.edu (8.9.3/8.9.3) with SMTP id AAA28068 for ; Sun, 10 Dec 2000 00:23:18 -0500 (EST) Received: from minotaur.onthe.net.au by MIT.EDU with SMTP id AA29800; Sat, 9 Dec 00 22:39:40 EST Received: (from chris@localhost) by minotaur.onthe.net.au (8.9.3/8.9.3) id OAA15721; Sun, 10 Dec 2000 14:38:08 +1100 Message-Id: <200012100338.OAA15721@minotaur.onthe.net.au> Date: Sun, 10 Dec 2000 14:38:08 +1100 From: chris@onthe.net.au Reply-To: chris@onthe.net.au To: krb5-bugs@MIT.EDU Cc: kerberos@MIT.EDU Subject: Patch X-Send-Pr-Version: 3.99 >Number: 907 >Category: krb5-libs >Synopsis: Patch: bind to a specific IP address when contacting KDC >Confidential: no >Severity: non-critical >Priority: low >Responsible: krb5-unassigned >State: open >Class: change-request >Submitter-Id: unknown >Arrival-Date: Sun Dec 10 00:24:00 EST 2000 >Last-Modified: >Originator: Chris Dunlop >Organization: OnTheNet Pty Ltd >Release: krb5-1.2.1 >Environment: All System: Linux minotaur.onthe.net.au 2.2.14-6.1.1smp #1 SMP Thu Apr 13 19:55:55 EDT 2000 i686 unknown Architecture: i686 >Description: This patch allows a multi-homed machine to bind to a particular address (and optionally a particular port) when contacting the kerberos domain contoller. This can help with some of the issues associated with configuring Kerberos on multi-homed machines. For more details see: Kerberos FAQ V2.0 1.24. Does Kerberos support multi-homed machines ? http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html#multihomed 2.14. How should I configure my DNS for Kerberos ? http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html#kerbdns The address binding is configured in the krb5.conf file like so: [realms] EXAMPLE.COM = { bind_address = host-name-or-ip-address[:port] } Cheers, Chris Dunlop, OnTheNet Pty Ltd diff -cr krb5-1.2.1.orig/src/lib/krb5/os/locate_kdc.c krb5-1.2.1/src/lib/krb5/os/locate_kdc.c *** krb5-1.2.1.orig/src/lib/krb5/os/locate_kdc.c Fri Jun 30 12:28:13 2000 --- krb5-1.2.1/src/lib/krb5/os/locate_kdc.c Tue Nov 14 17:15:43 2000 *************** *** 325,330 **** --- 325,415 ---- return 0; } + krb5_error_code + krb5_bind_addr(context, realm, addr_pp, addrlen_p) + krb5_context context; + const krb5_data *realm; + struct sockaddr **addr_pp; + socklen_t *addrlen_p; + { + const char *realm_srv_names[4]; + char *host, *port, *cp; + struct sockaddr *addr_p; + struct sockaddr_in *sin_p; + struct hostent *hp; + krb5_error_code code; + char *bind_addr; + #ifdef HAVE_NETINET_IN_H + u_short udpport; + #endif + + bind_addr = NULL; + *addr_pp = NULL; + + if ((host = malloc(realm->length + 1)) == NULL) + return ENOMEM; + + strncpy(host, realm->data, realm->length); + host[realm->length] = '\0'; + + realm_srv_names[0] = "realms"; + realm_srv_names[1] = host; + realm_srv_names[2] = "bind_address"; + realm_srv_names[3] = 0; + + code = profile_get_value(context->profile, realm_srv_names, &bind_addr); + + if (code == 0) { + addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr)); + if (addr_p == NULL) + return ENOMEM; + /* + * Strip off excess whitespace + */ + cp = strchr(bind_addr, ' '); + if (cp) + *cp = 0; + cp = strchr(bind_addr, '\t'); + if (cp) + *cp = 0; + port = strchr(bind_addr, ':'); + if (port) { + *port = 0; + port++; + } + else { + float max = IPPORT_USERRESERVED - IPPORT_RESERVED; + srand(getpid() + time(NULL)); + udpport = IPPORT_RESERVED + 1 + (int) (max * rand() /(RAND_MAX+1.0)); + } + + if ((hp = gethostbyname(bind_addr)) == 0) + return KRB5KRB_AP_ERR_BADADDR; + + switch (hp->h_addrtype) { + + #ifdef HAVE_NETINET_IN_H + case AF_INET: + if (hp->h_addr_list[0]) { + sin_p = (struct sockaddr_in *) addr_p; + memset ((char *)sin_p, 0, sizeof(struct sockaddr)); + sin_p->sin_family = hp->h_addrtype; + sin_p->sin_port = port ? htons(atoi(port)) : htons(udpport); + memcpy((char *)&sin_p->sin_addr, + (char *)hp->h_addr_list[0], + sizeof(struct in_addr)); + *addr_pp = addr_p; + *addrlen_p = sizeof(struct sockaddr_in); + } + break; + #endif + default: + break; + } + } + return 0; + } + #ifdef KRB5_DNS_LOOKUP /* diff -cr krb5-1.2.1.orig/src/lib/krb5/os/os-proto.h krb5-1.2.1/src/lib/krb5/os/os-proto.h *** krb5-1.2.1.orig/src/lib/krb5/os/os-proto.h Fri Jun 30 12:28:13 2000 --- krb5-1.2.1/src/lib/krb5/os/os-proto.h Tue Nov 14 17:16:39 2000 *************** *** 37,42 **** --- 37,48 ---- struct sockaddr **, int *, int)); + + krb5_error_code krb5_bind_addr + PROTOTYPE((krb5_context, + const krb5_data *, + struct sockaddr **, + int *)); #endif #ifdef HAVE_NETINET_IN_H diff -cr krb5-1.2.1.orig/src/lib/krb5/os/sendto_kdc.c krb5-1.2.1/src/lib/krb5/os/sendto_kdc.c *** krb5-1.2.1.orig/src/lib/krb5/os/sendto_kdc.c Fri Jun 30 12:28:13 2000 --- krb5-1.2.1/src/lib/krb5/os/sendto_kdc.c Tue Nov 14 17:17:32 2000 *************** *** 69,74 **** --- 69,76 ---- { register int timeout, host, i; struct sockaddr *addr; + struct sockaddr *bind_addr; + int bind_addr_len; int naddr; int sent, nready; krb5_error_code retval; *************** *** 116,121 **** --- 118,128 ---- } #endif + bind_addr = NULL; + if (retval = krb5_bind_addr (context, realm, &bind_addr, + &bind_addr_len)) + return retval; + /* * do exponential backoff. */ *************** *** 141,147 **** socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0); if (socklist[host] == INVALID_SOCKET) continue; /* try other hosts */ ! /* have a socket to send/recv from */ /* On BSD systems, a connected UDP socket will get connection refused and net unreachable errors while an unconnected socket will time out, so use connect, send, recv instead of --- 148,159 ---- socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0); if (socklist[host] == INVALID_SOCKET) continue; /* try other hosts */ ! /* ! * have a socket to send/recv from: bind to local ! * address if necessary ! */ ! if (bind_addr && bind(socklist[host], bind_addr, bind_addr_len) < 0) ! continue; /* try other hosts */ /* On BSD systems, a connected UDP socket will get connection refused and net unreachable errors while an unconnected socket will time out, so use connect, send, recv instead of *************** *** 222,227 **** --- 234,242 ---- #if 0 SOCKET_CLEANUP(); /* Done with sockets for now */ #endif + if (bind_addr) { + krb5_xfree(bind_addr); + } krb5_xfree(addr); krb5_xfree(socklist); if (retval) { diff -cr krb5-1.2.1.orig/src/lib/krb5/os/t_std_conf.c krb5-1.2.1/src/lib/krb5/os/t_std_conf.c *** krb5-1.2.1.orig/src/lib/krb5/os/t_std_conf.c Fri Jun 30 12:28:13 2000 --- krb5-1.2.1/src/lib/krb5/os/t_std_conf.c Tue Nov 14 17:15:43 2000 *************** *** 119,128 **** retval = krb5_locate_kdc(ctx, &rlm, &addrs, &naddrs, get_masters); if (retval) { ! com_err("krb5_get_krbhst", retval, 0); return; } ! printf("krb_get_krbhst(%s) returned:", realm); for (i=0; i < naddrs; i++) { sin = (struct sockaddr_in *) &addrs[i]; printf(" %s/%d", inet_ntoa(sin->sin_addr), --- 119,128 ---- retval = krb5_locate_kdc(ctx, &rlm, &addrs, &naddrs, get_masters); if (retval) { ! com_err("krb5_locate_kdc", retval, 0); return; } ! printf("krb_locate_kdc(%s) returned:", realm); for (i=0; i < naddrs; i++) { sin = (struct sockaddr_in *) &addrs[i]; printf(" %s/%d", inet_ntoa(sin->sin_addr), *************** *** 132,137 **** --- 132,179 ---- printf("\n"); } + void test_bind_addr (ctx, realm) + krb5_context ctx; + char *realm; + { + struct sockaddr *addr = NULL; + struct sockaddr_in *sin; + int addrlen; + krb5_data rlm; + krb5_error_code retval; + int s; + + rlm.data = realm; + rlm.length = strlen(realm); + retval = krb5_bind_addr (ctx, &rlm, &addr, &addrlen); + if (retval) { + com_err("krb5_bind_addr", retval, 0); + return; + } + sin = (struct sockaddr_in *) addr; + printf("krb_bind_addr(%s) returned:", realm); + if (sin == 0) { + printf(" [null]"); + } + else { + printf(" %s/%d", inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port)); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror(" socket"); + } + else if (bind(s, addr, addrlen) < 0) { + perror(" bind"); + } + else { + printf(" bind succeeded"); + } + free(addr); + } + printf ("\n"); + } + void test_get_host_realm(ctx, host) krb5_context ctx; char *host; *************** *** 181,187 **** void usage(progname) char *progname; { ! fprintf(stderr, "%s: Usage: %s [-dc] [-k realm] [-r host] [-C ccname] [-D realm]\n", progname, progname); exit(1); } --- 223,229 ---- void usage(progname) char *progname; { ! fprintf(stderr, "%s: Usage: %s [-dc] [-k realm] [-r host] [-C ccname] [-D realm] [-l realm] [-b realm]\n", progname, progname); exit(1); } *************** *** 202,209 **** exit(1); } ! while ((c = getopt(argc, argv, "cdk:r:C:D:l:s:")) != -1) { switch (c) { case 'c': /* Get default ccname */ test_get_default_ccname(ctx); break; --- 244,254 ---- exit(1); } ! while ((c = getopt(argc, argv, "b:cdk:r:C:D:l:s:")) != -1) { switch (c) { + case 'b': + test_bind_addr(ctx, optarg); + break; case 'c': /* Get default ccname */ test_get_default_ccname(ctx); break; >How-To-Repeat: >Fix: >Audit-Trail: >Unformatted: