⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bootpd.c

📁 linux下远程启动服务/bootp服务器源代码
💻 C
字号:
/* * *   bootpd_nis: simple BOOTP server with NIS maps support *   Copyright (C) 2005 <bfleisch@users.sourceforge.net> * *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * *  $Id: bootpd.c,v 1.4 2005/03/02 21:03:40 bfleisch Exp $ * */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/ioctl.h>#include <net/if.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#include <net/if_arp.h>#include <signal.h>#include <fcntl.h>#include <sys/stat.h>#ifdef __linux__#  include <netinet/ether.h>#else# include <netinet/if_ether.h># include <sys/sockio.h>#endif#ifdef _NISPLUS# include "nisplus.h"#endif#ifdef _NIS# include "nis.h"#endif#include "bootpd.h"#include "conf.h"#define BOOTPD_PORT 67#define BOOTP_REQUEST 1#define BOOTP_REPLY 2/* * define this to send RFC-1048 information in vendor field  * in BOOTPREPLY packet. */ #define SEND_RFC1048_INFO 1/* * PID file, may be declared in Makefiles * */#ifndef PIDFILE# define PIDFILE "/var/run/bootpd.pid"#endif/* * global variables */ struct in_addr g_serv_addr   ;struct in_addr g_netmask     ;struct in_addr g_nameserv    ;struct in_addr g_gw_addr     ;struct in_addr g_broadcast   ;int            g_flags       ;char*          g_ifname      ;char*          g_logfile     ;char*          g_bootfile    ;/* rfc1048 cookie value */static unsigned char  g_rfc1048_cookie[] = {0x63,0x82,0x53,0x63};static intadd_rfc1048_field (char *buf, unsigned char opt, unsigned char optlen,       char *optval, int maxlen){  if ( (optlen + 1 + 1) > maxlen)  {    log_msg(LOG_NOTICE, "BOOTP response packet too short (want %i bytes, only %i available) ! ", optlen+1+1, maxlen);    return;  }      buf[0] = opt;  if (optlen)    {      buf[1] = (unsigned char) optlen;      memcpy (buf + 2, optval, optlen);    }  else    memcpy (buf + 1, optval, optlen);  return optlen ? (1 + 1 + optlen) : 1;}/* max BOOTP packet size */#define MAX_MSG_LEN 1024 static voidhandle_request (int sock){  char re_buf[MAX_MSG_LEN];  struct sockaddr_in re_from;  size_t re_from_len;  ssize_t msglen;  struct in_addr ci_addr;  host_info* hinfo;  int idx;  int clt_sock;  int on=1;  re_from_len = sizeof (struct sockaddr_in);  memset (&re_from, 0, re_from_len);  memset (re_buf, 0, MAX_MSG_LEN);  if ((msglen=recvfrom (sock, re_buf, MAX_MSG_LEN, 0, (struct sockaddr *) &re_from, &re_from_len)) <= 0)  {    log_perror (LOG_NOTICE, "recv()");    return;  }    /*   * returns if this is not a BOOTREQUEST packet   */     if (re_buf[0] != BOOTP_REQUEST)    return;#if 0  if ( g_flags & F_DEBUG)#endif     {    struct ether_addr a;        memcpy ( &(a.ether_addr_octet), re_buf + 28, 6 );    log_msg(LOG_INFO, "BOOTPREQUEST packet from %s for %s", inet_ntoa(re_from.sin_addr), ether_ntoa(&a));  }  memcpy(&ci_addr, re_buf + 12, sizeof (struct in_addr));  #ifdef _NISPLUS	hinfo = get_host_info_nisplus(re_buf + 28);#else      hinfo = get_host_info_nis(re_buf + 28);#endif      if (!hinfo)    return; /* no such hw address in our database */          /*   * fill in the response packet    */      re_buf[0] = BOOTP_REPLY;  re_buf[1] = 1; /* Ethernet */  re_buf[2] = 6; /* 6 bytes for ethernet */    /* yiaddr*/  memcpy (re_buf + 16, &hinfo->addr, sizeof(struct in_addr));    /* siaddr*/  memcpy (re_buf + 20, &g_serv_addr, sizeof(struct in_addr));  /* boot image filename (i.e.:/tftpboot/pxelinux.0) */  if (g_bootfile)    memcpy(re_buf+108, g_bootfile, MIN( (strlen(g_bootfile)+1), 128));  #ifdef SEND_RFC1048_INFO    /* cookie: 0x63 0x82 0x53 0x63 */      memcpy (re_buf + 236, g_rfc1048_cookie, 4);        idx=236 + 4;        /* subnet field*/    idx += add_rfc1048_field (re_buf + idx, 1, 4, (char*) &g_netmask, MAX_MSG_LEN - idx);      /* gateway field*/    if ( g_gw_addr.s_addr)          idx += add_rfc1048_field (re_buf + idx, 3, 4, (char *) &g_gw_addr, MAX_MSG_LEN - idx);                /* client name */    idx += add_rfc1048_field (re_buf + idx , 12, strlen(hinfo->hostname),hinfo->hostname, MAX_MSG_LEN - idx);    /* DNS server */    if (g_nameserv.s_addr)      idx += add_rfc1048_field (re_buf + idx, 6, 4, (char*) &g_nameserv, MAX_MSG_LEN - idx);    /* end field*/    idx += add_rfc1048_field (re_buf + idx , 255, 0, NULL, MAX_MSG_LEN - idx);      #endif /* SEND_RFC1048_INFO */  /* * accordng to RFC 951: * *  4. Chicken / Egg Issues *  *    How can the server send an IP datagram to the client, if the client *    doesnt know its own IP address (yet)?  Whenever a bootreply is being *    sent, the transmitting machine performs the following operations: *  *       1. If the client knows its own IP address ('ciaddr' field is *       nonzero), then the IP can be sent 'as normal', since the client *       will respond to ARPs [5]. *  *       2. If the client does not yet know its IP address (ciaddr zero), *       then the client cannot respond to ARPs sent by the transmitter of *       the bootreply.  There are two options: *  *          a. If the transmitter has the necessary kernel or driver hooks *          to 'manually' construct an ARP address cache entry, then it can *          fill in an entry using the 'chaddr' and 'yiaddr' fields.  Of *          course, this entry should have a timeout on it, just like any *          other entry made by the normal ARP code itself.  The *          transmitter of the bootreply can then simply send the bootreply *          to the client's IP address.  UNIX (4.2 BSD) has this *          capability. *  *          b. If the transmitter lacks these kernel hooks, it can simply *          send the bootreply to the IP broadcast address on the *          appropriate interface.  This is only one additional broadcast *          over the previous case.  * *  */      if (  ci_addr.s_addr) /* client knows its IP address */  {    memcpy (&(re_from.sin_addr), &ci_addr, sizeof(struct in_addr));    clt_sock = sock;  }  else  {    /*     * setup ARP entry      *     */     #ifdef SIOCSARP  struct arpreq areq;    int s;        memset (&areq, 0, sizeof(struct arpreq));        /*     * ip address     */            ((struct sockaddr_in*)&areq.arp_pa)->sin_addr.s_addr = hinfo->addr.s_addr;           areq.arp_pa.sa_family = AF_INET;        /*     * hw address      */         memcpy ( &areq.arp_ha.sa_data, re_buf + 28, 6 );    areq.arp_ha.sa_family = ARPHRD_ETHER;        areq.arp_flags=ATF_COM;#ifdef __linux__        strcpy(areq.arp_dev, g_ifname); #endif                s = socket(AF_INET, SOCK_DGRAM, 0);    if (ioctl(s,SIOCSARP, &areq) != 0)      log_perror(LOG_NOTICE, "ioctl(SIOCSARP)");           close(s);    clt_sock = socket(AF_INET, SOCK_DGRAM, 0);    setsockopt (clt_sock,SOL_SOCKET,SO_BROADCAST, &on,4);        memcpy( &(re_from.sin_addr), &hinfo->addr, sizeof (struct in_addr));#else    /* SIOCSARP */      /*   * run /sbin/arp  to update our ARP cache   */   #error "TO BE IMPLEMENTED !"    #endif /* SIOCSARP */      }  if (sendto (clt_sock, &re_buf, msglen, 0, (struct sockaddr *) &re_from, re_from_len) <= 0)    log_perror (LOG_NOTICE, "sendto() failed:");    if ( clt_sock != sock && (clt_sock))    close(clt_sock);}static voidusage(const char* pg){printf("\n""\n""%s: BOOTP server (v%s), with %s support - \n""\n""Usage:\n""\t%s -i <inteface> [<options>] \n""\n""Required switches: \n""\t-i <interface>   : interface name (eth0, hme0, ...)\n""\n""Optional switches: \n""\t-g <gateway>     : gateway address (IP or hostname)\n""\t-m <netmask>     : netmask address \n""\t-n <name server> : name server address (IP or hostname)\n""\t-s <server>      : Our address (IP or hostname)\n""\t-b <broadcast>   : network broadcast address\n""\t-l <logfile>     : redirect logs to <logfile>\n""\t-B <bootfile>    : boot file name\n""\t-x               : run from {x,}inetd\n""\t-d               : debug mode\n""\n\n\n",  pg,  BOOTPDNIS_RELEASE,#if defined(_NIS)  "NIS" ,#elif defined(_NISPLUS)  "NIS+" ,#else  "" ,#endif        pg);      exit(0);}voidresolve_addr(const char* host, struct in_addr* addr){  struct hostent *he;  memset(addr, 0, sizeof (struct in_addr));    he = gethostbyname(host);  if (!he)  {    perror(host);    return;  }    if ( he->h_addrtype != AF_INET)  {    log_msg(LOG_ERR, "%s is not an INET address\n", host);    return;  }    memcpy(addr, he->h_addr, sizeof (struct in_addr));}intmain(int argc, char **argv){  struct sockaddr_in server_addr;  char opt;  int server_socket;  struct if_info *if_info;      memset(&g_gw_addr,   0, sizeof(struct in_addr));  memset(&g_nameserv,  0, sizeof(struct in_addr));  memset(&g_netmask,   0, sizeof(struct in_addr));  memset(&g_serv_addr, 0, sizeof(struct in_addr));      memset(&g_broadcast, 0, sizeof(struct in_addr));        g_ifname  = NULL;  g_logfile = NULL;  g_flags   =0;  g_bootfile= NULL;     while ( (opt=getopt(argc, argv, "hdg:i:n:m:s:b:xl:fB:c:")) != EOF)  {      switch (opt)    {          case 'c':        if (conf_parse_file(optarg) == 0)          break;                  log_msg(LOG_NOTICE, "Exiting due to previous errors.");        exit(1);        break;      case 'g':              resolve_addr(optarg, &g_gw_addr);        break;              case 'n':              resolve_addr(optarg, &g_nameserv);        break;              case 'm':              resolve_addr(optarg, &g_netmask);        break;              case 'b':              resolve_addr(optarg, &g_broadcast);        break;      case 'i':        g_ifname = strdup(optarg);        break;              case 's':        resolve_addr(optarg, &g_serv_addr);                     break;              case 'x':        g_flags |=F_INETD;        break;              case 'd':        g_flags |=F_DEBUG;         break;           case 'l':        g_logfile = strdup(optarg);        break;              case 'f':        g_flags |=F_FOREGROUND;         break;      case 'B':        g_bootfile = strdup(optarg);        break;      case 'h':      default:        usage(argv[0]);        break;                }  }    if (g_logfile) {        log_set_logfile(g_logfile);        } else {            if ( g_flags & F_FOREGROUND)        log_set_stderr();      else        log_set_syslog("bootpd_nis", LOG_PID, LOG_USER);    }          /*   * guess if we are a child of {x,}inetd   */        if ( !(g_flags & F_INETD))  {    struct sockaddr saddr;    socklen_t saddr_len;            saddr_len = sizeof(struct sockaddr);          if (getsockname(0, &saddr, &saddr_len)==0)            g_flags |= F_INETD;      }  /*   * become a daemon if not started by inetd    *    */         if ( ! (g_flags & F_INETD))   {      int pid;      int i;                            if (! (g_flags & F_FOREGROUND))      {        switch ( (pid=fork()))        {          case -1:            log_perror(LOG_ERR, "fork()");            exit (1);            break;          case 0:            break;           default: /* parent */             exit(0);                  }       /*       * close standard files descriptors       */        //close(0); close(1); close(2);        if (setsid() == (pid_t) -1)          log_perror(LOG_ERR, "setsid() error:");        /* i=open("/dev/null",O_RDWR); dup2(i,0); dup2(i,1);  */        umask(777);         chdir("/");         signal(SIGCHLD,SIG_IGN); /* ignore child */        signal(SIGTSTP,SIG_IGN); /* ignore tty signals */        signal(SIGTTOU,SIG_IGN);        signal(SIGTTIN,SIG_IGN);      }                 /*      * test lock & run file      */     #ifdef PIDFILE           i = open(PIDFILE,  O_WRONLY | O_CREAT, 0644);     if (i< 0)     {       log_perror(LOG_ERR, "Could not create lock file %s:", PIDFILE);       exit(1);     }          if (lockf (i, F_TLOCK, 0) != 0)     {       log_perror(LOG_ERR, "Could not lock %s. Another instance already running ? ", PIDFILE);       exit(1);     }          {       char buf[16];              snprintf(buf, 16,  "%i\n", getpid());       write(i, buf, strlen(buf));            }#endif /* PIDFILE */       }       if ( ! g_ifname)    if ( ! (g_flags & F_INETD))    {      log_msg(LOG_ERR, "Interface name is mandatory. Exiting.");      exit(1);    }           /*   * lookup interface(s) info    */    if_info = get_if_info (g_ifname);  if ( ! if_info)  {    log_msg(LOG_ERR, "%s: no such interface.\n", g_ifname);    exit(1);  }      memcpy ( &g_serv_addr, &(if_info->if_addr), sizeof(struct in_addr));    if (! g_netmask.s_addr)    memcpy ( &g_netmask, &(if_info->if_netmask), sizeof(struct in_addr));      if (! g_broadcast.s_addr)    memcpy ( &g_broadcast, &(if_info->if_broadcast), sizeof(struct in_addr));  if (g_flags & F_DEBUG)  {      log_msg(LOG_DEBUG, "Starting %s (iface=%s, myip=%s, broadcast=%s, netmask=%s, gateway=%s)",      argv[0],      g_ifname,       strdup (inet_ntoa (g_serv_addr)),      strdup (inet_ntoa (g_broadcast)),      strdup (inet_ntoa (g_netmask)),      g_gw_addr.s_addr ? strdup( inet_ntoa(g_gw_addr)) : "(none)");  }    if ( g_flags & F_INETD)      server_socket = 0;  else  {      /*     * prepare server socket     */      server_socket = socket (PF_INET, SOCK_DGRAM, 0);    if (server_socket < 0)      {        log_perror (LOG_ERR, "socket(): ");        exit (1);      }      memset (&server_addr, 0, sizeof (struct sockaddr_in));    server_addr.sin_port = htons (BOOTPD_PORT);    server_addr.sin_addr.s_addr = g_broadcast.s_addr;      if (bind (server_socket, (struct sockaddr *) &server_addr, sizeof (struct sockaddr_in)) < 0)    {      log_perror (LOG_ERR, "bind(): ");      exit (1);    }  }         do  {    handle_request (server_socket);  } while (! (g_flags & F_INETD));  if (server_socket)      close (server_socket);  return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -