home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / IPCMD.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  21KB  |  745 lines

  1. /* IP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  /* Mods by PA0GRI */
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "internet.h"
  8. #include "timer.h"
  9. #include "netuser.h"
  10. #include "iface.h"
  11. #include "session.h"
  12. #include "ip.h"
  13. #include "cmdparse.h"
  14. #include "commands.h"
  15. #include "rip.h"
  16. #include "rspf.h"
  17. #include "domain.h"
  18. #include "pktdrvr.h"
  19. #include "socket.h"
  20.   
  21. int32 Ip_addr;
  22. #ifdef __GNUC__
  23. int Route_Sort = 1;
  24. #else
  25. extern int Route_Sort=1;
  26. #endif
  27.   
  28. static int doadd __ARGS((int argc,char *argv[],void *p));
  29. #ifdef  IPACCESS
  30. static int doaccess __ARGS((int argc,char *argv[],void *p));
  31. #endif
  32. static int dodrop __ARGS((int argc,char *argv[],void *p));
  33. static int doflush __ARGS((int argc,char *argv[],void *p));
  34. static int doipaddr __ARGS((int argc,char *argv[],void *p));
  35. static int doipstat __ARGS((int argc,char *argv[],void *p));
  36. static int dolook __ARGS((int argc,char *argv[],void *p));
  37. static int dortimer __ARGS((int argc,char *argv[],void *p));
  38. static int dottl __ARGS((int argc,char *argv[],void *p));
  39. int doipheard __ARGS((int argc,char *argv[],void *p));
  40. static int doiphport __ARGS((int argc,char *argv[],void *p));
  41. static int doiphsize __ARGS((int argc,char *argv[],void *p));
  42. void dumproute __ARGS((struct route *rp,char *p));
  43. static int doroutesort __ARGS((int argc,char *argv[],void *p));
  44.   
  45. static struct cmds DFAR Ipcmds[] = {
  46. #ifdef  IPACCESS
  47.     "access",       doaccess,       0,      0, NULLCHAR,
  48. #endif
  49.     "address",      doipaddr,       0,      0, NULLCHAR,
  50.     "heard",        doipheard,      0,      0, NULLCHAR,
  51.     "hport",        doiphport,      0,      0, NULLCHAR,
  52.     "hsize",        doiphsize,      0,      0, NULLCHAR,
  53.     "rtimer",       dortimer,       0,      0, NULLCHAR,
  54.     "status",       doipstat,       0,      0, NULLCHAR,
  55.     "ttl",          dottl,          0,      0, NULLCHAR,
  56.     NULLCHAR,
  57. };
  58. /* "route" subcommands */
  59. static struct cmds Rtcmds[] = {
  60.     "add",          doadd,          0,      3,
  61.     "route add <dest addr>[/<bits>] <if name> [<gateway> | direct [metric]]",
  62.   
  63.     "addprivate",   doadd,          0,      3,
  64.     "route addprivate <dest addr>[/<bits>] <if name> [<gateway> | direct [metric]]",
  65.   
  66.     "drop",         dodrop,         0,      2,
  67.     "route drop <dest addr>[/<bits>]",
  68.   
  69.     "flush",        doflush,        0,      0,
  70.     NULLCHAR,
  71.   
  72.     "lookup",       dolook,         0,      2,
  73.     "route lookup <dest addr>",
  74.   
  75.     "sort",         doroutesort,    0,      0,
  76.     NULLCHAR,
  77.   
  78.     NULLCHAR,
  79. };
  80.   
  81. int
  82. doip(argc,argv,p)
  83. int argc;
  84. char *argv[];
  85. void *p;
  86. {
  87.     return subcmd(Ipcmds,argc,argv,p);
  88. }
  89. #ifdef  IPACCESS
  90. static int
  91. doaccess(argc,argv,p)
  92. int argc;
  93. char *argv[];
  94. void *p;
  95. {
  96.     struct iface *ifp;
  97.     int32 source,target;
  98.     unsigned sbits,tbits;
  99.     char *bitp;
  100.     int16 lport,hport,protocol,state;
  101.     char *cp; /* for printing the table */
  102.     struct rtaccess *tpacc;
  103.     struct rtaccess *btacc;
  104.     struct rtaccess *bfacc;
  105.     struct rtaccess *head;
  106.     char tmpbuf[15];
  107.   
  108.     if(argc == 1){ /* print out the table */
  109.         tputs("Source Address  Len Dest Address    Len Interface    Proto Low   High  State\n");
  110.         for(tpacc = IPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtiface){
  111.             for(btacc = tpacc;btacc != NULLACCESS;btacc = btacc->nxtbits){
  112.                 if(btacc->source != 0)
  113.                     cp = inet_ntoa(btacc->source);
  114.                 else
  115.                     cp = "all";
  116.                 tprintf("%-16s",cp);
  117.                 tprintf("%2u  ",btacc->sbits);
  118.                 if(btacc->target != 0)
  119.                     cp = inet_ntoa(btacc->target);
  120.                 else
  121.                     cp = "all";
  122.                 tprintf("%-16s",cp);
  123.                 tprintf("%2u  ",btacc->bits);
  124.                 tprintf("%-13s",btacc->iface->name);
  125.                 switch (btacc->protocol) {
  126.                     case 0:
  127.                         cp = "any";
  128.                         break;
  129.                     case ICMP_PTCL:
  130.                         cp = "icmp";
  131.                         break;
  132.                     case TCP_PTCL:
  133.                         cp = "tcp";
  134.                         break;
  135.                     case UDP_PTCL:
  136.                         cp = "udp";
  137.                         break;
  138.                     default:
  139.                         cp = itoa(btacc->protocol,tmpbuf,10);
  140.                 }
  141.                 tprintf("%-5s ",cp);
  142.                 tprintf("%5u ",btacc->lowport);
  143.                 tprintf("%5u ",btacc->highport);
  144.                 if(btacc->status)
  145.                     cp = "deny";
  146.                 else
  147.                     cp = "permit";
  148.                 tprintf("%-6s\n",cp);
  149.             }
  150.         }
  151.         return 0;
  152.     }
  153.   
  154.     if(strcmp(argv[1],"permit") == 0){
  155.         state = 0;
  156.     } else {
  157.         if((strcmp(argv[1],"deny") == 0)
  158.         || (strcmp(argv[1],"delete") == 0)){
  159.             state = -1;
  160.         } else {
  161.             tputs(" Format: ip access <permit|deny|delete> <proto> <src addr>[/<bits>] <dest addr>[/<bits>] <if name> [low [high]]\n");
  162.             return 1;
  163.         }
  164.     }
  165.   
  166.     switch (*argv[2]){
  167.         case 'a':       /* ANY */
  168.             protocol = 0;
  169.             break;
  170.         case 'i':       /* ICMP */
  171.             protocol = ICMP_PTCL;
  172.             break;
  173.         case 't':       /* TCP */
  174.             protocol = TCP_PTCL;
  175.             break;
  176.         case 'u':       /* UDP */
  177.             protocol = UDP_PTCL;
  178.             break;
  179.         default:
  180.             protocol = atoi(argv[2]);
  181.     }
  182.   
  183.     if(strcmp(argv[3],"all") == 0){
  184.         source = 0;
  185.         sbits = 0;
  186.     } else {
  187.         /* If IP address is followed by an optional slash and
  188.          * a length field, (e.g., 128.96/16) get it;
  189.          * otherwise assume a full 32-bit address
  190.          */
  191.         if((bitp = strchr(argv[3],'/')) != NULLCHAR){
  192.             /* Terminate address token for resolve() call */
  193.             *bitp++ = '\0';
  194.             sbits = atoi(bitp);
  195.         } else
  196.             sbits = 32;
  197.   
  198.         if((source = resolve(argv[3])) == 0){
  199.             tprintf(Badhost,argv[3]);
  200.             return 1;
  201.         }
  202.     }
  203.     if(strcmp(argv[4],"all") == 0){
  204.         target = 0;
  205.         tbits = 0;
  206.     } else {
  207.         if((bitp = strchr(argv[4],'/')) != NULLCHAR){
  208.             *bitp++ = '\0';
  209.             tbits = atoi(bitp);
  210.         } else
  211.             tbits = 32;
  212.   
  213.         if((target = resolve(argv[4])) == 0){
  214.             tprintf(Badhost,argv[4]);
  215.             return 1;
  216.         }
  217.     }
  218.   
  219.     if((ifp = if_lookup(argv[5])) == NULLIF){
  220.         tprintf(Badinterface,argv[5]);
  221.         return 1;
  222.     }
  223.   
  224.     if(((protocol != TCP_PTCL) && (protocol != UDP_PTCL)) || (argc < 7)) {
  225.         lport = 0;
  226.         hport = 0;
  227.     } else {
  228.         if(strcmp(argv[6],"all") == 0){
  229.             lport = 0;
  230.         } else {
  231.             lport = atoi(argv[6]);
  232.         }
  233.         if((argc < 8) || (lport == 0))
  234.             hport = lport;
  235.         else
  236.             hport = atoi(argv[7]);
  237.     }
  238.   
  239.     if(strcmp(argv[1],"delete") == 0){
  240.         head = IPaccess;
  241.         for(tpacc = IPaccess;tpacc != NULLACCESS;head = tpacc,tpacc = tpacc->nxtiface){
  242.             if(tpacc->iface == ifp){
  243.                 for(btacc = tpacc;btacc != NULLACCESS;
  244.                 head = btacc,btacc = btacc->nxtbits){
  245.                     if((btacc->protocol == protocol) &&
  246.                         (btacc->source == source)     &&
  247.                         (btacc->sbits == sbits)       &&
  248.                         (btacc->target == target)     &&
  249.                         (btacc->bits == tbits)        &&
  250.                         (btacc->lowport == lport)     &&
  251.                     (btacc->highport == hport)) { /*match*/
  252.                         bfacc = btacc; /* save to unalloc */
  253.                 /*now delete. watch for special cases*/
  254.                         if(btacc != tpacc){ /* not at head of list */
  255.                             head->nxtbits = btacc->nxtbits;
  256.                             free(bfacc);
  257.                             return 0;
  258.                         }
  259.                         if(btacc == IPaccess){ /* real special case */
  260.                             if(IPaccess->nxtbits == NULLACCESS)
  261.                                 IPaccess = btacc->nxtiface;
  262.                             else {
  263.                                 IPaccess = btacc->nxtbits;
  264.                                 (btacc->nxtbits)->nxtiface = btacc->nxtiface;
  265.                             }
  266.                         } else { /* we know tpacc=btacc <> IPaccess */
  267.                             if(btacc->nxtbits == NULLACCESS)
  268.                                 head->nxtiface = btacc->nxtiface;
  269.                             else {
  270.                                 head->nxtiface = btacc->nxtbits;
  271.                                 (btacc->nxtbits)->nxtiface = btacc->nxtiface;
  272.                             }
  273.                         }
  274.                         free(bfacc);
  275.                         return 0;
  276.                     }
  277.                 }
  278.             }
  279.         }
  280.         tputs("Not found.\n");
  281.         return 1;
  282.     }
  283.     /* add the access */
  284.     addaccess(protocol,source,sbits,target,tbits,ifp,lport,hport,state);
  285.     return 0;
  286. }
  287. #endif
  288. static int
  289. doipaddr(argc,argv,p)
  290. int argc;
  291. char *argv[];
  292. void *p;
  293. {
  294.     int32 n;
  295.   
  296.     if(argc < 2) {
  297.         tprintf("%s\n",inet_ntoa(Ip_addr));
  298.     } else if((n = resolve(argv[1])) == 0){
  299.         tprintf(Badhost,argv[1]);
  300.         return 1;
  301.     } else
  302.         Ip_addr = n;
  303.     return 0;
  304. }
  305. static int
  306. dortimer(argc,argv,p)
  307. int argc;
  308. char *argv[];
  309. void *p;
  310. {
  311.     return setlong(&ipReasmTimeout,"IP reasm timeout (sec)",argc,argv);
  312. }
  313. static int
  314. dottl(argc,argv,p)
  315. int argc;
  316. char *argv[];
  317. void *p;
  318. {
  319.     return setlong(&ipDefaultTTL,"IP Time-to-live",argc,argv);
  320. }
  321.   
  322.   
  323. char RouteHeader[] = "Destination      Len Interface Gateway          Metric P Timer  Use\n";
  324.   
  325. /* Display and/or manipulate routing table */
  326. int
  327. doroute(argc,argv,p)
  328. int argc;
  329. char *argv[];
  330. void *p;
  331. {
  332.     register int i,j,k,l,m,bits,flow_tmp;
  333.     register struct route *rp;
  334.     char *temp,temp2[80];
  335.   
  336.     if(argc >= 2)
  337.         return subcmd(Rtcmds,argc,argv,p);
  338.   
  339.     /* Dump IP routing table
  340.      * Dest            Len Interface    Gateway          Use
  341.      * 192.001.002.003 32  sl0          192.002.003.004  0
  342.      * modified for Sorted output - D. Crompton 2.92
  343.      */
  344.   
  345.     flow_tmp=Current->flowmode;
  346.     Current->flowmode=1;
  347.   
  348.     tputs(RouteHeader);
  349.   
  350.     for(j=0,bits=31;bits>=0;bits--)
  351.         for(i=0;i<HASHMOD;i++)
  352.             for(rp = Routes[bits][i];rp != NULLROUTE;j++,rp = rp->next);
  353.   
  354.     if (j){
  355.   
  356.         temp=mallocw(j*80);
  357.   
  358.         for(bits=31,k=0;bits>=0;bits--)
  359.             for(i=0;i<HASHMOD;i++)
  360.                 for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next,k+=80)
  361.                     dumproute(rp,&temp[k]);
  362.   
  363. #ifdef LINUX
  364.         if (Route_Sort) qsort(temp,(size_t)j,80,(int (*)__ARGS((void*,void*))) strcmp);
  365. #else
  366.         if (Route_Sort) qsort(temp,(size_t)j,80,(int (*) ()) strcmp);
  367. #endif
  368.   
  369.         for (i=0,k=4;i<j;i++,k+=80) {
  370.             tputs(&temp[k]);
  371.             if (tputc('\n') == EOF)
  372.             {
  373.                 Current->flowmode=flow_tmp;
  374.                 free(temp);
  375.                 return 0;
  376.             }
  377.         }
  378.         free(temp);
  379.     }
  380.     if(R_default.iface != NULLIF){
  381.         dumproute(&R_default,temp2);
  382.         tprintf("%s\n",&temp2[4]);
  383.     }
  384.     Current->flowmode = flow_tmp;
  385.     return 0;
  386. }
  387.   
  388. /* Dump a routing table entry */
  389. void
  390. dumproute(rp,temp)
  391. register struct route *rp;
  392. char *temp;
  393. {
  394.     char *cp;
  395.     unsigned int a=0;
  396.     char *name;
  397.   
  398.     if(rp->target != 0) {
  399.         if(DTranslate && (name = resolve_a(rp->target,!DVerbose)) != NULLCHAR) {
  400.             strcpy(temp,name);
  401.             free(name);
  402.         } else {
  403.             cp = inet_ntobos(rp->target);
  404.             sprintf(temp,"%4s",cp);
  405.         }
  406.         cp = inet_ntoa(rp->target);
  407.     } else {
  408.         strcpy(temp,"default");    /* Don't really matter, but avoid unknown value */
  409.         cp = "default";
  410.     }
  411.     a=4;
  412.     a+=sprintf(&temp[a],"%-16.16s ",cp);
  413.     a+=sprintf(&temp[a],"%-4u",rp->bits);
  414.     a+=sprintf(&temp[a],"%-9.9s ",rp->iface->name);
  415.     if(rp->gateway != 0)
  416.         cp = inet_ntoa(rp->gateway);
  417.     else
  418.         cp = "";
  419.     a+=sprintf(&temp[a],"%-16.16s ",cp);
  420.     a+=sprintf(&temp[a],"%-6lu ",rp->metric);
  421.     a+=sprintf(&temp[a],"%c ",(rp->flags & RTPRIVATE) ? 'P' : ' ');
  422.     if(rp->timer.state == TIMER_STOP){
  423.         if(rp->timer.duration == 1) a+=sprintf(&temp[a],"rspf   ");
  424.         else a+=sprintf(&temp[a],"man    ");
  425.     } else {
  426.         a+=sprintf(&temp[a],"%-7lu",read_timer(&rp->timer) / 1000L);
  427.     }
  428.     sprintf(&temp[a],"%lu",rp->uses);
  429. }
  430.   
  431.   
  432. /* Sort Route dump */
  433. static int
  434. doroutesort(argc,argv,p)
  435. int argc ;
  436. char *argv[] ;
  437. void *p;
  438. {
  439.     extern int Route_Sort;
  440.   
  441.     return setbool(&Route_Sort,"Route Sort flag",argc,argv);
  442. }
  443.   
  444.   
  445. /* Add an entry to the routing table
  446.  * E.g., "add 1.2.3.4 ax0 5.6.7.8 3"
  447.  */
  448. static int
  449. doadd(argc,argv,p)
  450. int argc;
  451. char *argv[];
  452. void *p;
  453. {
  454.     struct iface *ifp;
  455.     int32 dest,gateway;
  456.     unsigned bits;
  457.     char *bitp;
  458.     int32 metric;
  459.     char private;
  460.   
  461.     if(strncmp(argv[0],"addp",4) == 0)
  462.         private = 1;
  463.     else
  464.         private = 0;
  465.     if(strcmp(argv[1],"default") == 0){
  466.         dest = 0L;
  467.         bits = 0;
  468.     } else {
  469.         /* If IP address is followed by an optional slash and
  470.          * a length field, (e.g., 128.96/16) get it;
  471.          * otherwise assume a full 32-bit address
  472.          */
  473.         if((bitp = strchr(argv[1],'/')) != NULLCHAR){
  474.             /* Terminate address token for resolve() call */
  475.             *bitp++ = '\0';
  476.             bits = atoi(bitp);
  477.         } else
  478.             bits = 32;
  479.   
  480.         if((dest = resolve(argv[1])) == 0){
  481.             tprintf(Badhost,argv[1]);
  482.             return 1;
  483.         }
  484.     }
  485.     if((ifp = if_lookup(argv[2])) == NULLIF){
  486.         tprintf(Badinterface,argv[2]);
  487.         return 1;
  488.     }
  489.   
  490.     metric = 1;
  491.   
  492.     if(argc > 3){
  493.         /* Next "trick is needed to set the metric on subnets
  494.          * higher as the default 1 for rspf.
  495.          * route add subnet/bits iface default 10
  496.          */
  497.         if(strcmp(argv[3],"direct") == 0){      /* N1BEE */
  498.             gateway = 0;
  499.         /* calculate a nice metric based on subnet mask size */
  500.             if(bits != 0 && bits < 32)
  501.                 metric = (39 - bits) * 5 / 17;
  502.         } else {
  503.             if((gateway = resolve(argv[3])) == 0){
  504.                 tprintf(Badhost,argv[3]);
  505.                 return 1;
  506.             }
  507.         }
  508.     } else {
  509.         gateway = 0;
  510.     }
  511.     if (argc > 4)
  512.         metric = atol(argv[4]);
  513.   
  514.     if(rt_add(dest,bits,gateway,ifp,metric,0,private) == NULLROUTE)
  515.         tputs("Can't add route\n");
  516. #ifdef  RSPF
  517.     if(!private)
  518.         rspfrouteupcall(dest,bits,gateway);     /* Do an RSPF upcall */
  519. #endif  /* RSPF */
  520.     return 0;
  521. }
  522. /* Drop an entry from the routing table
  523.  * E.g., "drop 128.96/16
  524.  */
  525. static int
  526. dodrop(argc,argv,p)
  527. int argc;
  528. char *argv[];
  529. void *p;
  530. {
  531.     char *bitp;
  532.     unsigned bits;
  533.     int32 n;
  534.   
  535.     if(strcmp(argv[1],"default") == 0){
  536.         n = 0L;
  537.         bits = 0;
  538.     } else {
  539.         /* If IP address is followed by an optional slash and length field,
  540.          * (e.g., 128.96/16) get it; otherwise assume a full 32-bit address
  541.          */
  542.         if((bitp = strchr(argv[1],'/')) != NULLCHAR){
  543.             /* Terminate address token for resolve() call */
  544.             *bitp++ = '\0';
  545.             bits = atoi(bitp);
  546.         } else
  547.             bits = 32;
  548.   
  549.         if((n = resolve(argv[1])) == 0){
  550.             tprintf(Badhost,argv[1]);
  551.             return 1;
  552.         }
  553.     }
  554.     return rt_drop(n,bits);
  555. }
  556. /* Force a timeout on all temporary routes */
  557. static int
  558. doflush(argc,argv,p)
  559. int argc;
  560. char *argv[];
  561. void *p;
  562. {
  563.     register struct route *rp;
  564.     struct route *rptmp;
  565.     int i,j;
  566.   
  567.     if(R_default.timer.state == TIMER_RUN){
  568.         rt_drop(0,0);   /* Drop default route */
  569.     }
  570.     for(i=0;i<HASHMOD;i++){
  571.         for(j=0;j<32;j++){
  572.             for(rp = Routes[j][i];rp != NULLROUTE;rp = rptmp){
  573.                 rptmp = rp->next;
  574.                 if(rp->timer.state == TIMER_RUN){
  575.                     rt_drop(rp->target,rp->bits);
  576.                 }
  577.             }
  578.         }
  579.     }
  580.     return 0;
  581. }
  582.   
  583. static int
  584. dolook(argc,argv,p)
  585. int argc;
  586. char *argv[];
  587. void *p;
  588. {
  589.     struct route *rp;
  590.     int32 addr;
  591.     char temp[80];
  592.   
  593.     addr = resolve(argv[1]);
  594.     if(addr == 0){
  595.         tprintf(Badhost,argv[1]);
  596.         return 1;
  597.     }
  598.     if((rp = rt_lookup(addr)) == NULLROUTE){
  599.         tprintf("Host %s (%s) unreachable\n",argv[1],inet_ntoa(addr));
  600.         return 1;
  601.     }
  602.   
  603.     dumproute(rp,temp);
  604.     tputs(RouteHeader);
  605.     tprintf("%s\n",&temp[4]);
  606.   
  607.     return 0;
  608. }
  609.   
  610. static int
  611. doipstat(argc,argv,p)
  612. int argc;
  613. char *argv[];
  614. void *p;
  615. {
  616.     register struct reasm *rp;
  617.     register struct frag *fp;
  618.     int i;
  619.   
  620.     for(i=1;i<=NUMIPMIB;i++){
  621.         tprintf("(%2u)%-20s%10lu",i,
  622.         Ip_mib[i].name,Ip_mib[i].value.integer);
  623.         if(i % 2)
  624.             tputs("     ");
  625.         else
  626.             tputc('\n');
  627.     }
  628.     if((i % 2) == 0)
  629.         tputc('\n');
  630.   
  631.     if(Reasmq != NULLREASM)
  632.         tputs("Reassembly fragments:\n");
  633.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  634.         tprintf("src %s",inet_ntoa(rp->source));
  635.         tprintf(" dest %s",inet_ntoa(rp->dest));
  636.         if(tprintf(" id %u pctl %u time %lu len %u\n",
  637.             rp->id,uchar(rp->protocol),read_timer(&rp->timer),
  638.             rp->length) == EOF)
  639.             break;
  640.         for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  641.             if(tprintf(" offset %u last %u\n",fp->offset,
  642.                 fp->last) == EOF)
  643.                 break;
  644.         }
  645.     }
  646.     return 0;
  647. }
  648.   
  649. /* IP heard logging - WG7J */
  650. static struct iph *iph_create __ARGS((int32 addr));
  651. static struct iph *iph_lookup __ARGS((int32 addr));
  652. struct iph *Iph;
  653.   
  654. static int Maxipheard = MAXIPHEARD;
  655.   
  656. static int doiphsize(int argc,char *argv[],void *p) {
  657.     return setint(&Maxipheard,"Max ip-heard",argc,argv);
  658. }
  659.   
  660. /* Configure a port to do ip-heard logging */
  661. static int
  662. doiphport(argc,argv,p)
  663. int argc;
  664. char *argv[];
  665. void *p;
  666. {
  667.     return setflag(argc,argv[1],LOG_IPHEARD,argv[2]);
  668. }
  669.   
  670. int
  671. doipheard(int argc,char *argv[],void *p) {
  672.     struct iph *iph;
  673.   
  674.     if(tputs("Tcp/Ip systems heard:\n"
  675.         "Address                Port       Since       Pkts\n") == EOF)
  676.         return EOF;
  677.     for(iph=Iph;iph;iph=iph->next) {
  678.         if(tprintf("%-22s %-8s %12s %5ld\n",inet_ntoa(iph->addr),iph->iface->name,
  679.             tformat(secclock() - iph->time),iph->count) == EOF)
  680.             return EOF;
  681.     }
  682.     return 0;
  683. }
  684.   
  685. void
  686. log_ipheard(int32 addr,struct iface *ifp) {
  687.     struct iph *niph;
  688.   
  689.     if((niph = iph_lookup(addr)) == NULLIPH)
  690.         if((niph = iph_create(addr)) == NULLIPH)
  691.             return;
  692.     niph->iface = ifp;
  693.     niph->count++;
  694.     niph->time = secclock();
  695. }
  696.   
  697. /* Look up an entry in the ip data base */
  698. struct iph *
  699. iph_lookup(addr)
  700. int32 addr;
  701. {
  702.     register struct iph *ip;
  703.     struct iph *last = NULLIPH;
  704.   
  705.     for(ip = Iph;ip != NULLIPH;last = ip,ip = ip->next){
  706.         if(ip->addr == addr) {
  707.             if(last != NULLIPH){
  708.                 /* Move entry to top of list */
  709.                 last->next = ip->next;
  710.                 ip->next = Iph;
  711.                 Iph = ip;
  712.             }
  713.             return ip;
  714.         }
  715.     }
  716.     return NULLIPH;
  717. }
  718.   
  719. /* Create a new entry in the source database */
  720. /* If there are too many entries, override the oldest one - WG7J */
  721. static struct iph *
  722. iph_create(addr)
  723. int32 addr;
  724. {
  725.     static int numdb;
  726.     register struct iph *iph;
  727.     struct iph *last = NULLIPH;
  728.   
  729.     if(Maxipheard && numdb == Maxipheard) {
  730.     /* find and use last one in list */
  731.         for(iph = Iph;iph->next != NULLIPH;last = iph,iph = iph->next);
  732.     /* delete entry from end */
  733.         last->next = NULLIPH;
  734.     } else {    /* create a new entry */
  735.         numdb++;
  736.         iph = (struct iph *)callocw(1,sizeof(struct iph));
  737.     }
  738.     iph->addr = addr;
  739.     iph->count = 0;            /* VE3DTE */
  740.     iph->next = Iph;
  741.     Iph = iph;
  742.   
  743.     return iph;
  744. }
  745.