From owner-freebsd-i386@FreeBSD.ORG Wed Apr 14 03:40:09 2004 Return-Path: Delivered-To: freebsd-i386@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D45CD16A4CE for ; Wed, 14 Apr 2004 03:40:09 -0700 (PDT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id CA73843D5A for ; Wed, 14 Apr 2004 03:40:09 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) i3EAe9bv061672 for ; Wed, 14 Apr 2004 03:40:09 -0700 (PDT) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.10/8.12.10/Submit) id i3EAe99A061671; Wed, 14 Apr 2004 03:40:09 -0700 (PDT) (envelope-from gnats) Resent-Date: Wed, 14 Apr 2004 03:40:09 -0700 (PDT) Resent-Message-Id: <200404141040.i3EAe99A061671@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-i386@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Ralf Wenk Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1EC7E16A4CE for ; Wed, 14 Apr 2004 03:34:28 -0700 (PDT) Received: from rz06.fh-karlsruhe.de (rz06.FH-Karlsruhe.DE [193.196.64.6]) by mx1.FreeBSD.org (Postfix) with ESMTP id 2B19443D45 for ; Wed, 14 Apr 2004 03:34:27 -0700 (PDT) (envelope-from root@fh-karlsruhe.de) Received: from rz-tp600e.fh-karlsruhe.de ([193.196.65.138] helo=localhost) by rz06.fh-karlsruhe.de with esmtp (Exim 4.24) id 1BDhir-000ME6-EE; Wed, 14 Apr 2004 12:34:25 +0200 Received: from root by localhost with local (Exim 4.31; FreeBSD) id 1BDhiq-0004zJ-Lq; Wed, 14 Apr 2004 12:34:24 +0200 Message-Id: Date: Wed, 14 Apr 2004 12:34:24 +0200 From: Ralf Wenk To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 cc: RZ-FreeBSD0404@fh-karlsruhe.de Subject: i386/65523: [patch] PXE loader malfunction in multiple PXE server environment X-BeenThere: freebsd-i386@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Ralf Wenk List-Id: I386-specific issues for FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Apr 2004 10:40:09 -0000 >Number: 65523 >Category: i386 >Synopsis: [patch] PXE loader malfunction in multiple PXE server environment >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-i386 >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Apr 14 03:40:09 PDT 2004 >Closed-Date: >Last-Modified: >Originator: Ralf Wenk >Release: FreeBSD 5.2.1-RELEASE-p4 i386 >Organization: FH Karlsruhe, University of Applied Sciences >Environment: System: FreeBSD RZ-TP600E 5.2.1-RELEASE-p4 FreeBSD 5.2.1-RELEASE-p4 #10: Wed Apr 7 17:02:55 CEST 2004 root@RZ-TP600E:/usr/src/sys/i386/compile/tp600e i386 >Description: In an environment with multiple PXE servers the assumption that the first answer to an request is the one choosen by PXE may be wrong. PXE looks into the answers and uses a finite state machine to decide which answer to use and how to react. So simple extracting needed information by doing an additional DHCP cycle could lead to unexpected results. Extracting that information from PXE is a much better way. >How-To-Repeat: Set up a multi DHCP and PXE server environment with a DHCP proxy. Try to use the reply data provided by the proxy instead of the one of a server in the broadcast domain. The current code will always choose the first (fastest) answer. >Fix: --- pxe.c.udiff begins here --- --- pxe.c.ori Tue Aug 26 01:28:31 2003 +++ pxe.c Wed Apr 14 11:33:26 2004 @@ -133,6 +133,76 @@ }; /* + * This is ugly: + * libstand/bootp.c contains a similar RFC 1048 parser function named + * vend_rfc1048(), but the function is local to bootp.c and also uses + * a variable local to bootp.c if compiled with SUPPORT_DHCP defined. + * While the first problem could easily be fixed the second one would + * need an additional function in bootp.c to set the local variable. + */ +static int +pxe_vend_rfc1048(void) +{ + char vm_rfc1048[4] = VM_RFC1048; + u_char *cp, *ep; + int size; + u_char tag; + + if (bcmp(bootplayer.vendor.v.magic, vm_rfc1048, sizeof(vm_rfc1048)) == 0) + { + cp = (u_char *)bootplayer.vendor.d; + +#ifdef PXE_DEBUG + if (pxe_debug) + printf("pxe_vend_rfc1048 dhcp info. len=%d\n", len); +#endif + ep = cp + sizeof(bootplayer.vendor.d); + + /* Step over magic cookie */ + cp += sizeof(int); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: GATEWAY %s\n", intoa(gateip.s_addr)); +#endif + } + if (tag == TAG_SWAPSERVER) { + /* let it override bp_siaddr */ + bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: SWAPSERVER %s\n", intoa(rootip.s_addr)); +#endif + } + if (tag == TAG_ROOTPATH) { + strncpy(rootpath, (char *)cp, sizeof(rootpath)); + rootpath[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: ROOTPATH %s\n", rootpath); +#endif + } + if (tag == TAG_HOSTNAME) { + strncpy(hostname, (char *)cp, sizeof(hostname)); + hostname[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: HOSTNAME %s\n", hostname); +#endif + } + cp += size; + } + return(0); + } + else + return(-1); +} + +/* * This function is called by the loader to enable PXE support if we * are booted by PXE. The passed in pointer is a pointer to the * PXENV+ structure. @@ -274,12 +344,40 @@ } if (rootip.s_addr == 0) { /* - * Do a bootp/dhcp request to find out where our - * NFS/TFTP server is. Even if we dont get back - * the proper information, fall back to the server - * which brought us to life and a default rootpath. + * PXE looks into the content of all answers to its request + * and uses a finite state machine to select one of them. + * It is even possible that there are several requests + * generated and the information collected is combined. + * E.g. in the case of several PXE servers it is possible + * that not the answer of the fastest one is selected. This + * breaks the simple way of just using the first answer. + * But fortunately PXE stores the selected information + * in the bootplayer structure for us to use. */ - bootp(pxe_sock, BOOTP_PXE); +#ifdef PXE_DEBUG + printf("pxe_open: bootplayer.cip: %s\n", intoa( bootplayer.cip)); + printf("pxe_open: bootplayer.yip: %s\n", intoa( bootplayer.yip)); + printf("pxe_open: bootplayer.sip: %s\n", intoa( bootplayer.sip)); + printf("pxe_open: bootplayer.gip: %s\n", intoa( bootplayer.gip)); + sprintf(temp, "%6D", bootplayer.CAddr, ":"); + printf("pxe_open: bootplayer.CAddr: %s\n", temp); + printf("pxe_open: bootplayer.Sname: %s\n", bootplayer.Sname); + printf("pxe_open: bootplayer.bootfile: %s\n", bootplayer.bootfile); +#endif + if (pxe_vend_rfc1048() != 0) { + /* + * We are not happy with the information found in the + * bootplayer structure. As some last resort + * do a bootp/dhcp request to find out where our + * NFS/TFTP server is. Even if we dont get back + * the proper information, fall back to the server + * which brought us to life and a default rootpath. + */ + bootp(pxe_sock, BOOTP_PXE); + } +#ifdef PXE_DEBUG + printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); +#endif if (rootip.s_addr == 0) rootip.s_addr = bootplayer.sip; if (!rootpath[1]) --- pxe.c.udiff ends here --- >Release-Note: >Audit-Trail: >Unformatted: