ipaddress_ioctl.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:15k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  *  Interface MIB architecture support
  3.  *
  4.  * $Id: ipaddress_ioctl.c,v 1.8.2.1 2005/02/09 21:02:14 nba Exp $
  5.  */
  6. #include <net-snmp/net-snmp-config.h>
  7. #include <net-snmp/net-snmp-includes.h>
  8. #include "mibII/mibII_common.h"
  9. #include <net-snmp/agent/net-snmp-agent-includes.h>
  10. #include <net-snmp/data_access/ipaddress.h>
  11. #include <net-snmp/data_access/interface.h>
  12. #include "ip-mib/ipAddressTable/ipAddressTable_constants.h"
  13. #include "if-mib/data_access/interface_ioctl.h"
  14. #include <errno.h>
  15. #include <net/if.h>
  16. #include <sys/ioctl.h>
  17. #include "ipaddress_ioctl.h"
  18. static int _get_interface_count(int sd, struct ifconf * ifc);
  19. static void _print_flags(short flags);
  20. #define LIST_TOKEN "ioctl_extras"
  21. /*
  22.  * get extra structure
  23.  *
  24.  * @returns the extras structure from the entry
  25.  */
  26. _ioctl_extras *
  27. netsnmp_ioctl_ipaddress_extras_get(netsnmp_ipaddress_entry *entry)
  28. {
  29.     if ((NULL == entry) || (NULL == entry->arch_data))
  30.         return NULL;
  31.     return netsnmp_get_list_data(entry->arch_data, LIST_TOKEN);
  32. }
  33. /**
  34.  * initialize ioctl extras
  35.  *
  36.  * @returns _ioctl_extras pointer, or NULL on error
  37.  */
  38. _ioctl_extras *
  39. netsnmp_ioctl_ipaddress_entry_init(netsnmp_ipaddress_entry *entry)
  40. {
  41.     netsnmp_data_list *node;
  42.     _ioctl_extras     *extras;
  43.     if (NULL == entry)
  44.         return NULL;
  45.     extras = SNMP_MALLOC_TYPEDEF(_ioctl_extras);
  46.     if (NULL == extras)
  47.         return NULL;
  48.     node = netsnmp_create_data_list(LIST_TOKEN, extras, free);
  49.     if (NULL == node) {
  50.         free(extras);
  51.         return NULL;
  52.     }
  53.     netsnmp_data_list_add_node( &entry->arch_data, node );
  54.     
  55.     return extras;
  56. }
  57. /**
  58.  * cleanup ioctl extras
  59.  */
  60. void
  61. netsnmp_ioctl_ipaddress_entry_cleanup(netsnmp_ipaddress_entry *entry)
  62. {
  63.     if (NULL == entry) {
  64.         netsnmp_assert(NULL != entry);
  65.         return;
  66.     }
  67.     if (NULL == entry->arch_data) {
  68.         netsnmp_assert(NULL != entry->arch_data);
  69.         return;
  70.     }
  71.     netsnmp_remove_list_node(&entry->arch_data, LIST_TOKEN);
  72. }
  73. /**
  74.  * copy ioctl extras
  75.  *
  76.  * @retval  0: success
  77.  * @retval <0: error
  78.  */
  79. int
  80. netsnmp_ioctl_ipaddress_entry_copy(netsnmp_ipaddress_entry *lhs,
  81.                                    netsnmp_ipaddress_entry *rhs)
  82. {
  83.     _ioctl_extras *lhs_extras, *rhs_extras;
  84.     int            rc = SNMP_ERR_NOERROR;
  85.     if ((NULL == lhs) || (NULL == rhs)) {
  86.         netsnmp_assert((NULL != lhs) && (NULL != rhs));
  87.         return -1;
  88.     }
  89.     rhs_extras = netsnmp_ioctl_ipaddress_extras_get(rhs);
  90.     lhs_extras = netsnmp_ioctl_ipaddress_extras_get(lhs);
  91.     if (NULL == rhs_extras) {
  92.         if (NULL != lhs_extras)
  93.             netsnmp_ioctl_ipaddress_entry_cleanup(lhs);
  94.     }
  95.     else {
  96.         if (NULL == lhs_extras)
  97.             lhs_extras = netsnmp_ioctl_ipaddress_entry_init(lhs);
  98.         
  99.         if (NULL != lhs_extras)
  100.             memcpy(lhs_extras, rhs_extras, sizeof(_ioctl_extras));
  101.         else
  102.             rc = -1;
  103.     }
  104.     return rc;
  105. }
  106. /**
  107.  * load ipv4 address via ioctl
  108.  */
  109. int
  110. _netsnmp_ioctl_ipaddress_container_load_v4(netsnmp_container *container,
  111.                                                   int idx_offset)
  112. {
  113.     int             i, sd, rc = 0, interfaces = 0;
  114.     struct ifconf   ifc;
  115.     struct ifreq   *ifrp;
  116.     struct sockaddr save_addr;
  117.     netsnmp_ipaddress_entry *entry;
  118.     _ioctl_extras           *extras;
  119.     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  120.         snmp_log(LOG_ERR, "could not create socketn");
  121.         return -1;
  122.     }
  123.     interfaces = _get_interface_count(sd, &ifc);
  124.     if(interfaces < 0) {
  125.         close(sd);
  126.         return -2;
  127.     }
  128.     netsnmp_assert(NULL != ifc.ifc_buf);
  129.     DEBUGMSGTL(("access:ipaddress:container", "processing %d interfacesn", interfaces));
  130.     ifrp = ifc.ifc_req;
  131.     for(i=0; i < interfaces; ++i, ++ifrp) {
  132.         DEBUGMSGTL(("access:ipaddress:container",
  133.                     " interface %d, %sn", i, ifrp->ifr_name));
  134.         /*
  135.          */
  136.         entry = netsnmp_access_ipaddress_entry_create();
  137.         if(NULL == entry) {
  138.             rc = -3;
  139.             break;
  140.         }
  141.         entry->ns_ia_index = ++idx_offset;
  142.         /*
  143.          * save if name
  144.          */
  145.         extras = netsnmp_ioctl_ipaddress_extras_get(entry);
  146.         memcpy(extras->name, ifrp->ifr_name, sizeof(extras->name));
  147.         /*
  148.          * each time we make an ioctl, we need to specify the address, but
  149.          * it will be overwritten in the call. so we save address here.
  150.          */
  151.         save_addr = ifrp->ifr_addr;
  152.         /*
  153.          * set indexes
  154.          */
  155.         switch(ifrp->ifr_addr.sa_family) {
  156.             case AF_INET: {
  157.                 struct sockaddr_in * si =
  158.                     (struct sockaddr_in *) &ifrp->ifr_addr;
  159.                 entry->ia_address_len = sizeof(si->sin_addr.s_addr);
  160.                 memcpy(entry->ia_address, &si->sin_addr.s_addr,
  161.                        entry->ia_address_len);
  162.             }
  163.                 break;
  164.                 
  165.             case AF_INET6: {
  166.                 struct sockaddr_in6 * si =
  167.                     (struct sockaddr_in6 *) &ifrp->ifr_addr;
  168.                 entry->ia_address_len = sizeof(si->sin6_addr.s6_addr);
  169.                 memcpy(entry->ia_address, &si->sin6_addr.s6_addr,
  170.                        entry->ia_address_len);
  171.             }
  172.                 break;
  173.             default:
  174.                 snmp_log(LOG_ERR,"unknown if family %dn",
  175.                          ifrp->ifr_addr.sa_family);
  176.                 netsnmp_access_ipaddress_entry_free(entry);
  177.                 continue;
  178.         }
  179.         /*
  180.          * get ifindex
  181.          */
  182.         {
  183.             /*
  184.              * I think that Linux and Solaris both use ':' in the
  185.              * interface name for aliases. When a new arch is added
  186.              * that uses some other indicator, a new function, maybe
  187.              * netsnmp_access_ipaddress_entry_name_alias_check(), will
  188.              * need to be written.
  189.              */
  190.             char *ptr = strchr(ifrp->ifr_name, ':');
  191.             if (NULL != ptr) {
  192.                 entry->flags |= NETSNMP_ACCESS_IPADDRESS_ISALIAS;
  193.                 *ptr = 0;
  194.             }
  195.         }
  196.         entry->if_index =
  197.             netsnmp_access_interface_ioctl_ifindex_get(sd, ifrp->ifr_name);
  198.         if (0 == entry->if_index) {
  199.             snmp_log(LOG_ERR,"no ifindex found for interfacen");
  200.             netsnmp_access_ipaddress_entry_free(entry);
  201.             continue;
  202.         }
  203.         /*
  204.          * get flags
  205.          */
  206.         ifrp->ifr_addr = save_addr;
  207.         if (ioctl(sd, SIOCGIFFLAGS, ifrp) < 0) {
  208.             snmp_log(LOG_ERR,
  209.                      "error getting if_flags for interface %dn", i);
  210.             netsnmp_access_ipaddress_entry_free(entry);
  211.             continue;
  212.         }
  213.         extras->flags = ifrp->ifr_flags;
  214.         entry->ia_type = IPADDRESSTYPE_UNICAST; /* assume unicast? */
  215.         /** entry->ia_prefix_oid ? */
  216.         /*
  217.          * per the MIB:
  218.          *   In the absence of other information, an IPv4 address is
  219.          *   always preferred(1).
  220.          */
  221.         entry->ia_status = IPADDRESSSTATUSTC_PREFERRED;
  222.         /*
  223.          * can we figure out if an address is from DHCP?
  224.          * use manual until then...
  225.          */
  226.         entry->ia_origin = IPADDRESSORIGINTC_MANUAL;
  227.         DEBUGIF("access:ipaddress:container") {
  228.             DEBUGMSGT_NC(("access:ipaddress:container",
  229.                           " if %d: addr len %d, index 0x%xn",
  230.                           i, entry->ia_address_len, entry->if_index));
  231.             if (4 == entry->ia_address_len)
  232.                 DEBUGMSGT_NC(("access:ipaddress:container", " address %pn",
  233.                               *((void**)entry->ia_address)));
  234.             DEBUGMSGT_NC(("access:ipaddress:container", "flags 0x%xn",
  235.                           extras->flags));
  236.             _print_flags(extras->flags);
  237.         }
  238.         /*
  239.          * add entry to container
  240.          */
  241.         CONTAINER_INSERT(container, entry);
  242.     }
  243.     /*
  244.      * clean up
  245.      */
  246.     free(ifc.ifc_buf);
  247.     close(sd);
  248.     /*
  249.      * return number of interfaces seen
  250.      */
  251.     if(rc < 0)
  252.         return rc;
  253.     return idx_offset;
  254. }
  255. /**
  256.  * find unused alias number
  257.  */
  258. static int
  259. _next_alias(const char *if_name)
  260. {
  261.     int             i, j, k, sd, interfaces = 0, len;
  262.     struct ifconf   ifc;
  263.     struct ifreq   *ifrp;
  264.     char                    *alias;
  265.     int                     *alias_list;
  266.     if (NULL == if_name)
  267.         return -1;
  268.     len = strlen(if_name);
  269.     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  270.         snmp_log(LOG_ERR, "could not create socketn");
  271.         return -1;
  272.     }
  273.     interfaces = _get_interface_count(sd, &ifc);
  274.     if(interfaces < 0) {
  275.         close(sd);
  276.         return -2;
  277.     }
  278.     netsnmp_assert(NULL != ifc.ifc_buf);
  279.     DEBUGMSGTL(("access:ipaddress:container", "processing %d interfacesn", interfaces));
  280.     alias_list = malloc(interfaces * sizeof(int));
  281.     if (NULL == alias_list) {
  282.         close(sd);
  283.         return -2;
  284.     }
  285.     ifrp = ifc.ifc_req;
  286.     for(i=0,j=0; i < interfaces; ++i, ++ifrp) {
  287.         if (strncmp(ifrp->ifr_name, if_name, len) != 0)
  288.             continue;
  289.         DEBUGMSGTL(("access:ipaddress:container",
  290.                     " interface %d, %sn", i, ifrp->ifr_name));
  291.         alias = strchr(ifrp->ifr_name, ':');
  292.         if (NULL == alias)
  293.             continue;
  294.         ++alias; /* skip ':' */
  295.         alias_list[j++] = atoi(alias);
  296.     }
  297.     /*
  298.      * clean up
  299.      */
  300.     free(ifc.ifc_buf);
  301.     close(sd);
  302.     /*
  303.      * return first unused alias
  304.      */
  305.     for(i=1; i<=interfaces; ++i) {
  306.         for(k=0;k<j;++k)
  307.             if (alias_list[k] == i)
  308.                 break;
  309.         if (k == j)
  310.             return i;
  311.     }
  312.     return interfaces + 1;
  313. }
  314. /**
  315.  *
  316.  * @retval  0 : no error
  317.  * @retval -1 : bad parameter
  318.  * @retval -2 : couldn't create socket
  319.  * @retval -3 : ioctl failed
  320.  */
  321. int
  322. _netsnmp_ioctl_ipaddress_set_v4(netsnmp_ipaddress_entry * entry)
  323. {
  324.     struct ifreq                   ifrq;
  325.     struct sockaddr_in            *sin;
  326.     int                            rc, fd = -1;
  327.     _ioctl_extras                 *extras;
  328.     if (NULL == entry)
  329.         return -1;
  330.     netsnmp_assert(4 == entry->ia_address_len);
  331.     extras = netsnmp_ioctl_ipaddress_extras_get(entry);
  332.     if (NULL == extras)
  333.         return -1;
  334.     fd = socket(AF_INET, SOCK_DGRAM, 0);
  335.     if(fd < 0) {
  336.         snmp_log(LOG_ERR,"couldn't create socketn");
  337.         return -2;
  338.     }
  339.     memset(&ifrq, 0, sizeof(ifrq));
  340.     if ('' == extras->name[0]) {
  341.         const char *name = netsnmp_access_interface_name_find(entry->if_index);
  342.         int   alias_idx;
  343.         if (NULL == name) {
  344.             DEBUGMSGT(("access:ipaddress:set", "cant find name for index %dn",
  345.                        entry->if_index));
  346.             close(fd);
  347.             return -1;
  348.         }
  349.         /*
  350.          * search for unused alias
  351.          */
  352.         alias_idx = _next_alias(name);
  353.         snprintf(ifrq.ifr_name,sizeof(ifrq.ifr_name), "%s:%d",
  354.                  name, alias_idx);
  355.     }
  356.     else
  357.         strncpy(ifrq.ifr_name, extras->name, sizeof(ifrq.ifr_name));
  358.     ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
  359.     sin = (struct sockaddr_in*)&ifrq.ifr_addr;
  360.     sin->sin_family = AF_INET;
  361.     memcpy(&sin->sin_addr.s_addr, entry->ia_address,
  362.            entry->ia_address_len);
  363.     rc = ioctl(fd, SIOCSIFADDR, &ifrq);
  364.     close(fd);
  365.     if(rc < 0) {
  366.         snmp_log(LOG_ERR,"error setting addressn");
  367.         return -3;
  368.     }
  369.     return 0;
  370. }
  371. /**
  372.  *
  373.  * @retval  0 : no error
  374.  * @retval -1 : bad parameter
  375.  * @retval -2 : couldn't create socket
  376.  * @retval -3 : ioctl failed
  377.  */
  378. int
  379. _netsnmp_ioctl_ipaddress_delete_v4(netsnmp_ipaddress_entry * entry)
  380. {
  381.     struct ifreq                   ifrq;
  382.     int                            rc, fd = -1;
  383.     _ioctl_extras                 *extras;
  384.     if (NULL == entry)
  385.         return -1;
  386.     netsnmp_assert(4 == entry->ia_address_len);
  387.     extras = netsnmp_ioctl_ipaddress_extras_get(entry);
  388.     if (NULL == extras)
  389.         return -1;
  390.     fd = socket(AF_INET, SOCK_DGRAM, 0);
  391.     if(fd < 0) {
  392.         snmp_log(LOG_ERR,"couldn't create socketn");
  393.         return -2;
  394.     }
  395.     memset(&ifrq, 0, sizeof(ifrq));
  396.     strncpy(ifrq.ifr_name, extras->name, sizeof(ifrq.ifr_name));
  397.     ifrq.ifr_name[ sizeof(ifrq.ifr_name)-1 ] = 0;
  398.     ifrq.ifr_flags = 0;
  399.     rc = ioctl(fd, SIOCSIFFLAGS, &ifrq);
  400.     close(fd);
  401.     if(rc < 0) {
  402.         snmp_log(LOG_ERR,"error deleting addressn");
  403.         return -3;
  404.     }
  405.     return 0;
  406. }
  407. /**
  408.  *
  409.  * @retval -1 : malloc error
  410.  */
  411. static int
  412. _get_interface_count(int sd, struct ifconf * ifc)
  413. {
  414.     int lastlen = 0, i;
  415.     netsnmp_assert(NULL != ifc);
  416.     /*
  417.      * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF
  418.      * on some platforms; see W. R. Stevens, ``Unix Network Programming
  419.      * Volume I'', p.435.  
  420.      */
  421.     for (i = 8;; i *= 2) {
  422.         ifc->ifc_buf = calloc(i, sizeof(struct ifreq));
  423.         if (NULL == ifc->ifc_buf) {
  424.             snmp_log(LOG_ERR, "could not allocate memory for %d interfacesn",
  425.                      i);
  426.             return -1;
  427.         }
  428.         ifc->ifc_len = i * sizeof(struct ifreq);
  429.         if (ioctl(sd, SIOCGIFCONF, (char *) ifc) < 0) {
  430.             if (errno != EINVAL || lastlen != 0) {
  431.                 /*
  432.                  * Something has gone genuinely wrong.  
  433.                  */
  434.                 snmp_log(LOG_ERR, "bad rc from ioctl, errno %d", errno);
  435.                 SNMP_FREE(ifc->ifc_buf);
  436.                 break;
  437.             }
  438.             /*
  439.              * Otherwise, it could just be that the buffer is too small.  
  440.              */
  441.         } else {
  442.             if (ifc->ifc_len == lastlen) {
  443.                 /*
  444.                  * The length is the same as the last time; we're done.  
  445.                  */
  446.                 break;
  447.             }
  448.             lastlen = ifc->ifc_len;
  449.         }
  450.         free(ifc->ifc_buf); /* no SNMP_FREE, getting ready to reassign */
  451.     }
  452.     return ifc->ifc_len / sizeof(struct ifreq);
  453. }
  454. /**
  455.  */
  456. static void
  457. _print_flags(short flags)
  458. {
  459. /** Standard interface flags. */
  460.     struct {
  461.        short flag;
  462.        const char *name;
  463.     } map[] = {
  464.         { IFF_UP,          "interface is up"},
  465.         { IFF_BROADCAST,   "broadcast address valid"},
  466.         { IFF_DEBUG,       "turn on debugging"},
  467.         { IFF_LOOPBACK,    "is a loopback net"},
  468.         { IFF_POINTOPOINT, "interface is has p-p link"},
  469.         { IFF_NOTRAILERS,  "avoid use of trailers"},
  470.         { IFF_RUNNING,     "resources allocated"},
  471.         { IFF_NOARP,       "no ARP protocol"},
  472.         { IFF_PROMISC,     "receive all packets"},
  473.         { IFF_ALLMULTI,    "receive all multicast packets"},
  474.         { IFF_MASTER,      "master of a load balancer"},
  475.         { IFF_SLAVE,       "slave of a load balancer"},
  476.         { IFF_MULTICAST,   "Supports multicast"},
  477.         { IFF_PORTSEL,     "can set media type"},
  478.         { IFF_AUTOMEDIA,   "auto media select active"},
  479.     };
  480.     short unknown = flags;
  481.     int i;
  482.     for(i = 0; i < sizeof(map)/sizeof(map[0]); ++i)
  483.         if(flags & map[i].flag) {
  484.             DEBUGMSGT_NC(("access:ipaddress:container","  %sn", map[i].name));
  485.             unknown &= ~map[i].flag;
  486.         }
  487.     if(unknown)
  488.         DEBUGMSGT_NC(("access:ipaddress:container","  unknown 0x%xn", unknown));
  489. }