"Fossies" - the Fresh Open Source Software Archive

Member "scanssh-2.1/interface.c" (17 Mar 2004, 9521 Bytes) of package /linux/privat/old/scanssh-2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "interface.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright 2003 Niels Provos <provos@citi.umich.edu>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Niels Provos.
   16  * 4. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/types.h>
   32 #include <sys/param.h>
   33 
   34 #ifdef HAVE_CONFIG_H
   35 #include "config.h"
   36 #endif
   37 
   38 #include <sys/ioctl.h>
   39 #include <sys/tree.h>
   40 #include <sys/queue.h>
   41 #ifdef HAVE_SYS_TIME_H
   42 #include <sys/time.h>
   43 #endif
   44 
   45 #include <err.h>
   46 #include <errno.h>
   47 #include <stdio.h>
   48 #include <stdlib.h>
   49 #include <string.h>
   50 #include <syslog.h>
   51 #include <unistd.h>
   52 
   53 #include <event.h>
   54 #include <pcap.h>
   55 #include <dnet.h>
   56 
   57 #include "interface.h"
   58 
   59 /* Prototypes */
   60 static int pcap_dloff(pcap_t *);
   61 
   62 void ss_recv_cb(u_char *, const struct pcap_pkthdr *, const u_char *);
   63 
   64 static char *interface_expandips(int, char **, int);
   65 static void interface_recv(int, short, void *);
   66 static void interface_poll_recv(int, short, void *);
   67 
   68 #define SS_POLL_INTERVAL    {0, 10000}
   69 
   70 int ss_dopoll;
   71 
   72 static TAILQ_HEAD(ifq, interface) interfaces;
   73 intf_t *ss_intf;
   74 extern struct interface *ss_inter;
   75 
   76 void
   77 interface_initialize(void)
   78 {
   79     TAILQ_INIT(&interfaces);
   80 
   81     if ((ss_intf = intf_open()) == NULL)
   82         err(1, "intf_open");
   83 }
   84 
   85 /* Get a new interface structure */
   86 
   87 static struct interface *
   88 interface_new(char *dev)
   89 {
   90     char ebuf[PCAP_ERRBUF_SIZE];
   91     struct interface *inter;
   92 
   93     if ((inter = calloc(1, sizeof(struct interface))) == NULL)
   94         err(1, "%s: calloc", __func__);
   95 
   96     if (dev == NULL) {
   97         if ((dev = pcap_lookupdev(ebuf)) == NULL)
   98             errx(1, "pcap_lookupdev: %s", ebuf);
   99     }
  100 
  101     TAILQ_INSERT_TAIL(&interfaces, inter, next);
  102 
  103     inter->if_ent.intf_len = sizeof(struct intf_entry);
  104     strlcpy(inter->if_ent.intf_name, dev, sizeof(inter->if_ent.intf_name));
  105     
  106     if (intf_get(ss_intf, &inter->if_ent) < 0)
  107         err(1, "%s: intf_get", __func__);
  108 
  109     if (inter->if_ent.intf_addr.addr_type != ADDR_TYPE_IP)
  110         errx(1, "%s: bad interface configuration: %s is not IP",
  111             __func__, dev);
  112 
  113     return (inter);
  114 }
  115 
  116 struct interface *
  117 interface_find(char *name)
  118 {
  119     struct interface *inter;
  120 
  121     TAILQ_FOREACH(inter, &interfaces, next) {
  122         if (strcasecmp(inter->if_ent.intf_name, name) == 0)
  123             return (inter);
  124     }
  125 
  126     return (NULL);
  127 }
  128 
  129 struct interface *
  130 interface_find_addr(struct addr *addr)
  131 {
  132     struct interface *inter;
  133 
  134     TAILQ_FOREACH(inter, &interfaces, next) {
  135         if (addr_cmp(addr, &inter->if_ent.intf_addr) == 0)
  136             return (inter);
  137     }
  138 
  139     return (NULL);
  140 }
  141 
  142 void
  143 interface_close(struct interface *inter)
  144 {
  145     TAILQ_REMOVE(&interfaces, inter, next);
  146 
  147     if (inter->if_eth != NULL)
  148         eth_close(inter->if_eth);
  149     pcap_close(inter->if_pcap);
  150 
  151     free(inter);
  152 }
  153 
  154 void
  155 interface_close_all(void)
  156 {
  157     struct interface *inter;
  158 
  159     while((inter = TAILQ_FIRST(&interfaces)) != NULL)
  160         interface_close(inter);
  161 }
  162 
  163 void
  164 interface_init(char *dev, int naddresses, char **addresses, char *filter)
  165 {
  166     struct bpf_program fcode;
  167     char ebuf[PCAP_ERRBUF_SIZE], *dst;
  168     struct interface *inter;
  169     int time;
  170 
  171     if (dev != NULL && interface_find(dev) != NULL) {
  172         fprintf(stderr, "Warning: Interface %s already configured\n",
  173             dev);
  174         return;
  175     }
  176 
  177     ss_inter = inter = interface_new(dev);
  178 
  179     /* 
  180      * Compute the monitored IP addresses.  If we are ethernet,
  181      * ignore our own packets.
  182      */
  183 
  184     /* Destination addresses only */
  185     dst = interface_expandips(naddresses, addresses, 1);
  186 
  187     if (snprintf(inter->if_filter, sizeof(inter->if_filter),
  188         "(%s) %s%s%s",
  189         filter,
  190         dst ? "and (" : "", dst ? dst : "", dst ? ")" : "") >= 
  191         sizeof(inter->if_filter))
  192         errx(1, "%s: pcap filter exceeds maximum length", __func__);
  193 
  194     inter->if_ent.intf_addr.addr_bits = IP_ADDR_BITS;
  195     
  196     time = ss_dopoll ? 10 : 30;
  197     if ((inter->if_pcap = pcap_open_live(inter->if_ent.intf_name,
  198          128 /* inter->if_ent.intf_mtu + 40 */,
  199          0, time, ebuf)) == NULL)
  200         errx(1, "pcap_open_live: %s", ebuf);
  201 
  202     /* Get offset to packet data */
  203     inter->if_dloff = pcap_dloff(inter->if_pcap);
  204     
  205     if (pcap_compile(inter->if_pcap, &fcode, inter->if_filter, 1, 0) < 0 ||
  206         pcap_setfilter(inter->if_pcap, &fcode) < 0)
  207         errx(1, "bad pcap filter: %s", pcap_geterr(inter->if_pcap));
  208 #if defined(BSD) && defined(BIOCIMMEDIATE)
  209     {
  210         int on = 1;
  211         if (ioctl(pcap_fileno(inter->if_pcap), BIOCIMMEDIATE, &on) < 0)
  212             warn("BIOCIMMEDIATE");
  213     }
  214 #endif
  215 
  216     syslog(LOG_INFO, "listening on %s: %s",
  217         inter->if_ent.intf_name, inter->if_filter);
  218 
  219     if (!ss_dopoll) {
  220         event_set(&inter->if_recvev, pcap_fileno(inter->if_pcap),
  221             EV_READ, interface_recv, inter);
  222         event_add(&inter->if_recvev, NULL);
  223     } else {
  224         struct timeval tv = SS_POLL_INTERVAL;
  225 
  226         syslog(LOG_INFO, "switching to polling mode");
  227         timeout_set(&inter->if_recvev, interface_poll_recv, inter);
  228         timeout_add(&inter->if_recvev, &tv);
  229     }
  230 }
  231 
  232 /*
  233  * Expands several command line arguments into a complete pcap filter string.
  234  * Deals with normal CIDR notation and IP-IP ranges.
  235  */
  236 
  237 static char *
  238 interface_expandips(int naddresses, char **addresses, int dstonly)
  239 {
  240     static char filter[1024];
  241     char line[1024], *p;
  242     struct addr dst;
  243 
  244     if (naddresses == 0)
  245         return (NULL);
  246 
  247     filter[0] = '\0';
  248 
  249     while (naddresses--) {
  250         /* Get current address */
  251         p = *addresses++;
  252 
  253         if (filter[0] != '\0') {
  254             if (strlcat(filter, " or ", sizeof(filter)) >= sizeof(filter))
  255                 errx(1, "%s: too many address for filter", 
  256                     __func__);
  257         }
  258 
  259         if (addr_pton(p, &dst) != -1) {
  260             snprintf(line, sizeof(line), "%s%s%s",
  261                 dstonly ? "dst " : "",
  262                 dst.addr_bits != 32 ? "net ": "", p);
  263         } else {
  264             char *first, *second;
  265             struct addr astart, aend;
  266             struct in_addr in;
  267             ip_addr_t istart, iend;
  268 
  269             second = p;
  270 
  271             first = strsep(&second, "-");
  272             if (second == NULL)
  273                 errx(1, "%s: Invalid network range: %s",
  274                     __func__, p);
  275 
  276             line[0] = '\0';
  277             if (addr_pton(first, &astart) == -1 ||
  278                 addr_pton(second, &aend) == -1)
  279                 errx(1, "%s: bad addresses %s-%s", __func__,
  280                     first, second);
  281             if (addr_cmp(&astart, &aend) >= 0)
  282                 errx(1, "%s: inverted range %s-%s", __func__,
  283                 first, second);
  284 
  285             /* Completely, IPv4 specific */
  286             istart = ntohl(astart.addr_ip);
  287             iend = ntohl(aend.addr_ip);
  288             while (istart <= iend) {
  289                 char single[32];
  290                 int count = 0, done = 0;
  291                 ip_addr_t tmp;
  292 
  293                 do {
  294                     ip_addr_t bit = 1 << count;
  295                     ip_addr_t mask;
  296 
  297                     mask = ~(~0 << count);
  298                     tmp = istart | mask;
  299 
  300                     if (istart & bit)
  301                         done = 1;
  302 
  303                     if (iend < tmp) {
  304                         count--;
  305                         mask = ~(~0 << count);
  306                         tmp = istart | mask;
  307                         break;
  308                     } else if (done)
  309                         break;
  310                     
  311                     count++;
  312                 } while (count < IP_ADDR_BITS);
  313 
  314                 if (line[0] != '\0')
  315                     strlcat(line, " or ", sizeof(line));
  316                 in.s_addr = htonl(istart);
  317                 snprintf(single, sizeof(single),
  318                     "dst net %s/%d",
  319                     inet_ntoa(in), 32 - count);
  320 
  321                 strlcat(line, single, sizeof(line));
  322 
  323                 istart = tmp + 1;
  324             }
  325         }
  326         
  327         if (strlcat(filter, line, sizeof(filter)) >= sizeof(filter))
  328             errx(1, "%s: too many address for filter", 
  329                 __func__);
  330     }
  331 
  332     return (filter);
  333 }
  334 
  335 /* Interface receiving functions */
  336 
  337 static void
  338 interface_recv(int fd, short type, void *arg)
  339 {
  340     struct interface *inter = arg;
  341 
  342     if (!ss_dopoll)
  343         event_add(&inter->if_recvev, NULL);
  344 
  345     if (pcap_dispatch(inter->if_pcap, -1,
  346         ss_recv_cb, (u_char *)inter) < 0)
  347         syslog(LOG_ERR, "pcap_dispatch: %s",
  348             pcap_geterr(inter->if_pcap));
  349 }
  350  
  351 static void
  352 interface_poll_recv(int fd, short type, void *arg)
  353 {
  354     struct interface *inter = arg;
  355     struct timeval tv = SS_POLL_INTERVAL;
  356 
  357     timeout_add(&inter->if_recvev, &tv);
  358 
  359     interface_recv(fd, type, arg);
  360 }
  361 
  362 static int
  363 pcap_dloff(pcap_t *pd)
  364 {
  365     int offset = -1;
  366     
  367     switch (pcap_datalink(pd)) {
  368     case DLT_EN10MB:
  369         offset = 14;
  370         break;
  371     case DLT_IEEE802:
  372         offset = 22;
  373         break;
  374     case DLT_FDDI:
  375         offset = 21;
  376         break;
  377 #ifdef DLT_PPP
  378         case DLT_PPP:
  379                 offset = 24;
  380                 break;
  381 #endif
  382 #ifdef DLT_LINUX_SLL
  383         case DLT_LINUX_SLL:
  384                 offset = 16;
  385                 break;
  386 #endif
  387 #ifdef DLT_LOOP
  388     case DLT_LOOP:
  389 #endif
  390     case DLT_NULL:
  391         offset = 4;
  392         break;
  393     default:
  394         warnx("unsupported datalink type");
  395         break;
  396     }
  397     return (offset);
  398 }