"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.

    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 }