This patch adds support for configuration profiles, which can be used to
[obnox/wireshark/wip.git] / epan / addr_resolv.c
index d79003eb5e0a8bce0741b4f02aadab6a8375f99e..1fc7c45fc6cb0210d4245579343c4cfaed9abeeb 100644 (file)
  * sites still using NIS rather than DNS for that....)
  */
 
+#ifdef HAVE_GNU_ADNS
+# include <errno.h>
+# include <adns.h>
+# ifdef inet_aton
+#  undef inet_aton
+# endif
+#endif
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 # include "inet_v6defs.h"
 #endif
 
-#ifdef HAVE_GNU_ADNS
-# include <errno.h>
-# include <adns.h>
-# ifdef inet_aton
-#  undef inet_aton
-# endif
-#endif
-
 #if defined(_WIN32) && defined(INET6)
 # include <ws2tcpip.h>
 #endif
 #include "ipv6-utils.h"
 #include "addr_resolv.h"
 #include "filesystem.h"
+
+#include <epan/strutil.h>
 #include <wiretap/file_util.h>
 #include <epan/prefs.h>
 #include <epan/emem.h>
 #define ENAME_ETHERS           "ethers"
 #define ENAME_IPXNETS          "ipxnets"
 #define ENAME_MANUF            "manuf"
+#define ENAME_SERVICES "services"
 
 #define MAXMANUFLEN    9       /* max vendor name length with ending '\0' */
 #define HASHETHSIZE    1024
@@ -231,6 +234,7 @@ static hashipxnet_t *ipxnet_table[HASHIPXNETSIZE];
 
 static int             eth_resolution_initialized = 0;
 static int             ipxnet_resolution_initialized = 0;
+static int             service_resolution_initialized = 0;
 
 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
 
@@ -249,6 +253,8 @@ gchar *g_ethers_path  = NULL;               /* global ethers file    */
 gchar *g_pethers_path = NULL;          /* personal ethers file  */
 gchar *g_ipxnets_path  = NULL;         /* global ipxnets file   */
 gchar *g_pipxnets_path = NULL;         /* personal ipxnets file */
+gchar *g_services_path  = NULL;                /* global services file   */
+gchar *g_pservices_path = NULL;                /* personal services file */
                                        /* first resolving call  */
 
 /* GNU ADNS */
@@ -274,10 +280,185 @@ GList *adns_queue_head = NULL;
 
 #endif /* HAVE_GNU_ADNS */
 
+
+/*
+ *  Miscellaneous functions
+ */
+
+static int fgetline(char **buf, int *size, FILE *fp)
+{
+  int len;
+  int c;
+
+  if (fp == NULL)
+    return -1;
+
+  if (*buf == NULL) {
+    if (*size == 0)
+      *size = BUFSIZ;
+
+    if ((*buf = g_malloc(*size)) == NULL)
+      return -1;
+  }
+
+  if (feof(fp))
+    return -1;
+
+  len = 0;
+  while ((c = getc(fp)) != EOF && c != '\r' && c != '\n') {
+    if (len+1 >= *size) {
+      if ((*buf = g_realloc(*buf, *size += BUFSIZ)) == NULL)
+       return -1;
+    }
+    (*buf)[len++] = c;
+  }
+
+  if (len == 0 && c == EOF)
+    return -1;
+
+  (*buf)[len] = '\0';
+
+  return len;
+
+} /* fgetline */
+
+
 /*
  *  Local function definitions
  */
 
+
+static void add_service_name(hashport_t **proto_table, guint port, const char *service_name)
+{
+  int hash_idx;
+  hashport_t *tp;
+  
+
+  hash_idx = HASH_PORT(port);
+  tp = proto_table[hash_idx];
+
+  if( tp == NULL ) {
+    tp = proto_table[hash_idx] = (hashport_t *)g_malloc(sizeof(hashport_t));
+  } else {
+    while(1) {
+      if( tp->port == port ) {
+        return;
+      }
+      if (tp->next == NULL) {
+        tp->next = (hashport_t *)g_malloc(sizeof(hashport_t));
+        tp = tp->next;
+        break;
+      }
+      tp = tp->next;
+    }
+  }
+
+  /* fill in a new entry */
+  tp->port = port;
+  tp->next = NULL;
+
+  g_strlcpy(tp->name, service_name, MAXNAMELEN);
+}
+
+
+static void parse_service_line (char *line)
+{
+  /*
+   *  See the services(4) or services(5) man page for services file format
+   *  (not available on all systems).
+   */
+
+  gchar *cp;
+  gchar *service;
+  gchar *port;
+
+
+  if ((cp = strchr(line, '#')))
+    *cp = '\0';
+
+  if ((cp = strtok(line, " \t")) == NULL)
+    return;
+
+  service = cp;
+
+  if ((cp = strtok(NULL, " \t")) == NULL)
+    return;
+
+  port = cp;
+
+  if ((cp = strtok(cp, "/")) == NULL)
+    return;
+
+  if ((cp = strtok(NULL, "/")) == NULL)
+    return;
+
+  /* seems we got all interesting things from the file */
+  if(strcmp(cp, "tcp") == 0) {
+    add_service_name(tcp_port_table, atoi(port), service);
+    return;
+  }
+
+  if(strcmp(cp, "udp") == 0) {
+    add_service_name(udp_port_table, atoi(port), service);
+    return;
+  }
+
+  if(strcmp(cp, "sctp") == 0) {
+    add_service_name(sctp_port_table, atoi(port), service);
+    return;
+  }
+
+  if(strcmp(cp, "dcp") == 0) {
+    add_service_name(dccp_port_table, atoi(port), service);
+    return;
+  }
+
+} /* parse_service_line */
+
+
+
+static void parse_services_file(const char * path)
+{
+  FILE *serv_p;
+  static int     size = 0;
+  static char   *buf = NULL;
+
+  /* services hash table initialization */
+  serv_p = eth_fopen(path, "r");
+
+  if (serv_p == NULL)
+    return;
+
+  while (fgetline(&buf, &size, serv_p) >= 0) {
+    parse_service_line (buf);
+  }
+
+  fclose(serv_p);
+}
+
+
+static void initialize_services(void)
+{
+
+  /* the hash table won't ignore duplicates, so use the personal path first */
+
+  /* set personal services path */
+  if (g_pservices_path == NULL)
+    g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE, FALSE);
+
+  parse_services_file(g_pservices_path);
+
+  /* Compute the pathname of the services file. */
+  if (g_services_path == NULL) {
+    g_services_path = get_datafile_path(ENAME_SERVICES);
+  }
+
+  parse_services_file(g_services_path);
+
+} /* initialize_services */
+
+
+
 static gchar *serv_name_lookup(guint port, port_type proto)
 {
   int hash_idx;
@@ -286,6 +467,12 @@ static gchar *serv_name_lookup(guint port, port_type proto)
   const char *serv_proto = NULL;
   struct servent *servp;
 
+
+  if (!service_resolution_initialized) {
+    initialize_services();
+    service_resolution_initialized = 1;
+  }
+
   switch(proto) {
   case PT_UDP:
     table = udp_port_table;
@@ -307,7 +494,6 @@ static gchar *serv_name_lookup(guint port, port_type proto)
     /* not yet implemented */
     return NULL;
     /*NOTREACHED*/
-    break;
   } /* proto */
 
   hash_idx = HASH_PORT(port);
@@ -338,8 +524,7 @@ static gchar *serv_name_lookup(guint port, port_type proto)
     /* unknown port */
     g_snprintf(tp->name, MAXNAMELEN, "%d", port);
   } else {
-    strncpy(tp->name, servp->s_name, MAXNAMELEN);
-    tp->name[MAXNAMELEN-1] = '\0';
+    g_strlcpy(tp->name, servp->s_name, MAXNAMELEN);
   }
 
   return (tp->name);
@@ -407,7 +592,7 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
     adns_queue_head = g_list_append(adns_queue_head, (gpointer) qmsg);
 
     tp->is_dummy_entry = TRUE;
-    ip_to_str_buf((guint8 *)&addr, tp->name);
+    ip_to_str_buf((guint8 *)&addr, tp->name, MAXNAMELEN);
     return tp->name;
   }
 #endif /* HAVE_GNU_ADNS */
@@ -439,8 +624,7 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
 # endif /* AVOID_DNS_TIMEOUT */
 
       if (hostp != NULL) {
-       strncpy(tp->name, hostp->h_name, MAXNAMELEN);
-       tp->name[MAXNAMELEN-1] = '\0';
+       g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
        tp->is_dummy_entry = FALSE;
        return tp->name;
       }
@@ -453,7 +637,7 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
 
   /* unknown host or DNS timeout */
 
-  ip_to_str_buf((guint8 *)&addr, tp->name);
+  ip_to_str_buf((guint8 *)&addr, tp->name, MAXNAMELEN);
   tp->is_dummy_entry = TRUE;
   *found = FALSE;
 
@@ -513,8 +697,7 @@ static gchar *host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
 # endif /* AVOID_DNS_TIMEOUT */
 
       if (hostp != NULL) {
-       strncpy(tp->name, hostp->h_name, MAXNAMELEN);
-       tp->name[MAXNAMELEN-1] = '\0';
+       g_strlcpy(tp->name, hostp->h_name, MAXNAMELEN);
        tp->is_dummy_entry = FALSE;
        return tp->name;
       }
@@ -561,48 +744,6 @@ static const gchar *solve_address_to_name(address *addr)
 } /* solve_address_to_name */
 
 
-/*
- *  Miscellaneous functions
- */
-
-static int fgetline(char **buf, int *size, FILE *fp)
-{
-  int len;
-  int c;
-
-  if (fp == NULL)
-    return -1;
-
-  if (*buf == NULL) {
-    if (*size == 0)
-      *size = BUFSIZ;
-
-    if ((*buf = g_malloc(*size)) == NULL)
-      return -1;
-  }
-
-  if (feof(fp))
-    return -1;
-
-  len = 0;
-  while ((c = getc(fp)) != EOF && c != '\n') {
-    if (len+1 >= *size) {
-      if ((*buf = g_realloc(*buf, *size += BUFSIZ)) == NULL)
-       return -1;
-    }
-    (*buf)[len++] = c;
-  }
-
-  if (len == 0 && c == EOF)
-    return -1;
-
-  (*buf)[len] = '\0';
-
-  return len;
-
-} /* fgetline */
-
-
 /*
  * Ethernet / manufacturer resolution
  *
@@ -737,7 +878,7 @@ static int parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
    *  See the ethers(4) or ethers(5) man page for ethers file format
    *  (not available on all systems).
    *  We allow both ethernet address separators (':' and '-'),
-   *  as well as Ethereal's '.' separator.
+   *  as well as Wireshark's '.' separator.
    */
 
   gchar *cp;
@@ -754,8 +895,7 @@ static int parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
   if ((cp = strtok(NULL, " \t")) == NULL)
     return -1;
 
-  strncpy(eth->name, cp, MAXNAMELEN);
-  eth->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(eth->name, cp, MAXNAMELEN);
 
   return 0;
 
@@ -921,8 +1061,7 @@ static void add_manuf_name(guint8 *addr, unsigned int mask, gchar *name)
     }
 
     memcpy(tp->addr, addr, sizeof(tp->addr));
-    strncpy(tp->name, name, MAXMANUFLEN);
-    tp->name[MAXMANUFLEN-1] = '\0';
+    g_strlcpy(tp->name, name, MAXMANUFLEN);
     tp->next = NULL;
     return;
   }
@@ -955,8 +1094,7 @@ static void add_manuf_name(guint8 *addr, unsigned int mask, gchar *name)
   }
 
   memcpy(etp->addr, addr, sizeof(etp->addr));
-  strncpy(etp->name, name, MAXNAMELEN);
-  etp->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(etp->name, name, MAXNAMELEN);
   etp->next = NULL;
   etp->is_dummy_entry = FALSE;
 
@@ -966,11 +1104,12 @@ static hashmanuf_t *manuf_name_lookup(const guint8 *addr)
 {
   int hash_idx;
   hashmanuf_t *tp;
+  guint8 stripped_addr[3];
 
   hash_idx = HASH_ETH_MANUF(addr);
 
+  /* first try to find a "perfect match" */
   tp = manuf_table[hash_idx];
-
   while(tp != NULL) {
     if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
       return tp;
@@ -978,6 +1117,22 @@ static hashmanuf_t *manuf_name_lookup(const guint8 *addr)
     tp = tp->next;
   }
 
+  /* Mask out the broadcast/multicast flag but not the locally
+   * administered flag as localy administered means: not assigend
+   * by the IEEE but the local administrator instead.
+   * 0x01 multicast / broadcast bit
+   * 0x02 locally administered bit */
+  memcpy(stripped_addr, addr, 3);
+  stripped_addr[0] &= 0xFE;
+
+  tp = manuf_table[hash_idx];
+  while(tp != NULL) {
+    if (memcmp(tp->addr, stripped_addr, sizeof(tp->addr)) == 0) {
+      return tp;
+    }
+    tp = tp->next;
+  }
+
   return NULL;
 
 } /* manuf_name_lookup */
@@ -1039,7 +1194,7 @@ static void initialize_ethers(void)
    * with it. It's used in get_ethbyname() and get_ethbyaddr()
    */
   if (g_pethers_path == NULL)
-    g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE);
+    g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE, FALSE);
 
   /* manuf hash table initialization */
 
@@ -1092,8 +1247,7 @@ static hashether_t *add_eth_name(const guint8 *addr, const gchar *name)
     }
   }
 
-  strncpy(tp->name, name, MAXNAMELEN);
-  tp->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(tp->name, name, MAXNAMELEN);
   if (new_one) {
       memcpy(tp->addr, addr, sizeof(tp->addr));
       tp->next = NULL;
@@ -1239,8 +1393,7 @@ static gchar *eth_name_lookup(const guint8 *addr)
     tp->is_dummy_entry = TRUE;
 
   } else {
-    strncpy(tp->name, eth->name, MAXNAMELEN);
-    tp->name[MAXNAMELEN-1] = '\0';
+    g_strlcpy(tp->name, eth->name, MAXNAMELEN);
     tp->is_dummy_entry = FALSE;
   }
 
@@ -1324,8 +1477,7 @@ static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
        ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
   }
 
-  strncpy(ipxnet->name, cp, MAXNAMELEN);
-  ipxnet->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(ipxnet->name, cp, MAXNAMELEN);
 
   return 0;
 
@@ -1435,7 +1587,7 @@ static void initialize_ipxnets(void)
    * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
    */
   if (g_pipxnets_path == NULL)
-    g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE);
+    g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE, FALSE);
 
 } /* initialize_ipxnets */
 
@@ -1462,8 +1614,7 @@ static hashipxnet_t *add_ipxnet_name(guint addr, const gchar *name)
   }
 
   tp->addr = addr;
-  strncpy(tp->name, name, MAXNAMELEN);
-  tp->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(tp->name, name, MAXNAMELEN);
   tp->next = NULL;
 
   return tp;
@@ -1506,8 +1657,7 @@ static gchar *ipxnet_name_lookup(const guint addr)
       g_snprintf(tp->name, MAXNAMELEN, "%X", addr);
 
   } else {
-    strncpy(tp->name, ipxnet->name, MAXNAMELEN);
-    tp->name[MAXNAMELEN-1] = '\0';
+    g_strlcpy(tp->name, ipxnet->name, MAXNAMELEN);
   }
 
   return (tp->name);
@@ -1624,17 +1774,17 @@ host_name_lookup_init(void) {
   char *hostspath;
 
 #ifdef HAVE_GNU_ADNS
-#ifdef WIN32
+#ifdef _WIN32
   char *sysroot;
   static char rootpath_nt[] = "\\system32\\drivers\\etc\\hosts";
   static char rootpath_ot[] = "\\hosts";
-#endif /* WIN32 */
+#endif /* _WIN32 */
 #endif /*GNU_ADNS */
 
   /*
    * Load the user's hosts file, if they have one.
    */
-  hostspath = get_persconffile_path(ENAME_HOSTS, FALSE);
+  hostspath = get_persconffile_path(ENAME_HOSTS, FALSE, FALSE);
   if (!read_hosts_file(hostspath) && errno != ENOENT) {
     report_open_failure(hostspath, errno, FALSE);
   }
@@ -1654,7 +1804,7 @@ host_name_lookup_init(void) {
    * We're using GNU ADNS, which doesn't check the system hosts file;
    * we load that file ourselves.
    */
-#ifdef WIN32
+#ifdef _WIN32
 
   sysroot = getenv_utf8("WINDIR");
   if (sysroot != NULL) {
@@ -1675,9 +1825,9 @@ host_name_lookup_init(void) {
     }
     g_free(hostspath);
   }
-#else /* WIN32 */
+#else /* _WIN32 */
   read_hosts_file("/etc/hosts");
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
   /* XXX - Any flags we should be using? */
   /* XXX - We could provide config settings for DNS servers, and
@@ -1837,8 +1987,7 @@ extern void add_ipv4_name(guint addr, const gchar *name)
     }
   }
 
-  strncpy(tp->name, name, MAXNAMELEN);
-  tp->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(tp->name, name, MAXNAMELEN);
   if (new_one) {
       tp->addr = addr;
       tp->next = NULL;
@@ -1880,8 +2029,7 @@ extern void add_ipv6_name(struct e_in6_addr *addrp, const gchar *name)
     }
   }
 
-  strncpy(tp->name, name, MAXNAMELEN);
-  tp->name[MAXNAMELEN-1] = '\0';
+  g_strlcpy(tp->name, name, MAXNAMELEN);
   if (new_one) {
       tp->addr = *addrp;
       tp->next = NULL;
@@ -1890,14 +2038,28 @@ extern void add_ipv6_name(struct e_in6_addr *addrp, const gchar *name)
 
 } /* add_ipv6_name */
 
+/* -----------------
+ * unsigned integer to ascii
+*/
+static gchar *ep_utoa(guint port)
+{
+  gchar *bp = ep_alloc(MAXNAMELEN);
+  
+  bp = &bp[MAXNAMELEN -1];
+  
+  *bp = 0;
+  do {
+      *--bp = (port % 10) +'0';
+  } while ((port /= 10) != 0);
+  return bp;
+}
+
+
 extern gchar *get_udp_port(guint port)
 {
-  gchar *cur;
 
   if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
-    cur=ep_alloc(MAXNAMELEN);
-    g_snprintf(cur, MAXNAMELEN, "%u", port);
-    return cur;
+    return ep_utoa(port);
   }
 
   return serv_name_lookup(port, PT_UDP);
@@ -1906,12 +2068,9 @@ extern gchar *get_udp_port(guint port)
 
 extern gchar *get_dccp_port(guint port)
 {
-  gchar *cur;
 
   if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
-    cur=ep_alloc(MAXNAMELEN);
-    g_snprintf(cur, MAXNAMELEN, "%u", port);
-    return cur;
+    return ep_utoa(port);
   }
 
   return serv_name_lookup(port, PT_DCCP);
@@ -1921,12 +2080,9 @@ extern gchar *get_dccp_port(guint port)
 
 extern gchar *get_tcp_port(guint port)
 {
-  gchar *cur;
 
   if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
-    cur=ep_alloc(MAXNAMELEN);
-    g_snprintf(cur, MAXNAMELEN, "%u", port);
-    return cur;
+    return ep_utoa(port);
   }
 
   return serv_name_lookup(port, PT_TCP);
@@ -1935,12 +2091,9 @@ extern gchar *get_tcp_port(guint port)
 
 extern gchar *get_sctp_port(guint port)
 {
-  gchar *cur;
 
   if (!(g_resolv_flags & RESOLV_TRANSPORT)) {
-    cur=ep_alloc(MAXNAMELEN);
-    g_snprintf(cur, MAXNAMELEN, "%u", port);
-    return cur;
+    return ep_utoa(port);
   }
 
   return serv_name_lookup(port, PT_SCTP);
@@ -1971,14 +2124,9 @@ const gchar *get_addr_name(address *addr)
 
 void get_addr_name_buf(address *addr, gchar *buf, guint size)
 {
-  const gchar *result;
-
-  result = get_addr_name(addr);
-
-  strncpy(buf,result,size);
-  buf[size]='\0';
-  return;
+  const gchar *result = get_addr_name(addr);
 
+  g_snprintf(buf, size, "%s", result);
 } /* get_addr_name_buf */