nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

ip.c (7209B)


      1 #include <string.h>
      2 #include "ip.h"
      3 #ifdef CAVEMAN_DEBUGGING
      4 #define DEBUGFD 2
      5 #include <stdio.h>
      6 #endif
      7 
      8 #include "fmt.h"
      9 #include "scan.h"
     10 #include "case.h"
     11 
     12 /* ip4 functions */
     13 static
     14 unsigned int ip4_fmt(char *s, struct ip4_address *ip)
     15 {
     16   unsigned int len;
     17   unsigned int i;
     18 
     19   len = 0;
     20   i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
     21   i = fmt_str(s,"."); len += i; if (s) s += i;
     22   i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
     23   i = fmt_str(s,"."); len += i; if (s) s += i;
     24   i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
     25   i = fmt_str(s,"."); len += i; if (s) s += i;
     26   i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
     27   return len;
     28 }
     29 
     30 static
     31 unsigned int ip4_scan(char *s, struct ip4_address *ip)
     32 {
     33   unsigned int i;
     34   unsigned int len;
     35   unsigned long u;
     36 
     37   len = 0;
     38   i = scan_ulong(s,&u); if (!i) return 0; ip->d[0] = u; s += i; len += i;
     39   if (*s != '.') return 0; ++s; ++len;
     40   i = scan_ulong(s,&u); if (!i) return 0; ip->d[1] = u; s += i; len += i;
     41   if (*s != '.') return 0; ++s; ++len;
     42   i = scan_ulong(s,&u); if (!i) return 0; ip->d[2] = u; s += i; len += i;
     43   if (*s != '.') return 0; ++s; ++len;
     44   i = scan_ulong(s,&u); if (!i) return 0; ip->d[3] = u; s += i; len += i;
     45   return len;
     46 }
     47 
     48 static
     49 unsigned int ip4_scanbracket(char *s, struct ip4_address *ip)
     50 {
     51   unsigned int len;
     52 
     53   if (*s != '[') return 0;
     54   len = ip4_scan(s + 1,ip);
     55   if (!len) return 0;
     56   if (s[len + 1] != ']') return 0;
     57   return len + 2;
     58 }
     59 
     60 /* ip6 functions */
     61 static
     62 unsigned int ip6_fmt(char *s, struct ip6_address *ip)
     63 {
     64   unsigned int len;
     65   unsigned int i, j, k, seenearliest;
     66   unsigned long word;
     67   unsigned int zf[8]; /* !0 means a word is all 0s */
     68   unsigned int hwm = 0; /* length of longest run */
     69   len = j = k = seenearliest = 0;
     70   for (; j < 8; ++j) {
     71     word = (unsigned long) ((ip->d[(j*2)]) << 8) + (ip->d[(j*2)+1]);
     72     k = (word != 0) ? 0 : k + 1; /* length of this run */
     73     zf[j] = (word != 0) ? 0 : k;
     74     if (k > hwm) hwm = k;
     75   }
     76   k = 0;
     77   for (j = 0; j < 7; ++j) {
     78     if (j+hwm > 7) break; /* continuation makes no sense because we are past the longest run */
     79     if (!seenearliest && zf[j] != 0 && zf[j+hwm] == hwm) {
     80       seenearliest = 1;
     81       while (zf[j] != 0 && j < 8) zf[j++] = hwm;
     82       while (j < 8) zf[j++] = 0; /* at this point we don't care about runs, they should be encoded as 0, not "" */
     83     }
     84   }
     85   for (j = 0; j < 8; ++j) {
     86     word = (unsigned long) ((ip->d[(j*2)]) << 8)|(ip->d[(j*2)+1]);
     87     i = fmt_ulongalphabet(s, word, "0123456789abcdef", 16);
     88     len += i;
     89     if (s) s += i;
     90     if ((j + 1) < 8) {
     91       i = fmt_str(s,":");
     92       len += i;
     93       if (s) s += i;
     94     }
     95   }
     96   return len;
     97 }
     98 
     99 /* as one august programmer once said,
    100  * parsing IPv6 addresses is a real pig, or something.
    101  * This is a horrendous interface. It's only saved because in qmail,
    102  * *s is only ever a buffer full of the desired address.
    103  */
    104 static
    105 unsigned int ip6_scan(char *s, struct ip6_address *ip)
    106 {
    107   unsigned int i, j;
    108   signed int k, wantrhswords, hasrhswords;
    109   unsigned int len;
    110   unsigned long u;
    111 #ifdef CAVEMAN_DEBUGGING
    112   char *st = s;
    113 #endif
    114   unsigned char ebuf[16];
    115 
    116   len = i = j = hasrhswords = 0; k = wantrhswords = -1;
    117   /* left side */
    118   for (j = 0; j < 16; ++j) {
    119     ip->d[j] = 0;
    120     ebuf[j] = 0;
    121   }
    122   for (j = 0; j < 8; ++j) {
    123     u = 0x0;
    124     i = scan_ulongalphabet(s,&u, "0123456789abcdef", 16);
    125     /* if (!i) return 0; this could yet be valid!.. */
    126     if (!i) u = 0x0U;
    127     ip->d[(j*2)] = (unsigned char)((u & 0xff00) >> 8);
    128     ip->d[(j*2)+1] = (u & 0xff);
    129     s += i;
    130     len += i;
    131     if (*s == ':') if (*(s + 1) == ':') {
    132 #ifdef  CAVEMAN_DEBUGGING
    133       dprintf(DEBUGFD, "Jump to right hand side at step %u of lhs ip6_scan(\"%s\", ipstruct);\n", j, st);
    134 #endif
    135       s += 2; len += 2; wantrhswords = 7 - (k = j); hasrhswords = 0; break;
    136     }
    137     if (j < 7 && *s != ':') {
    138       // invalid data; zero and return
    139       for (j = 0; j < 16; ++j) {
    140         ip->d[j] = 0;
    141         ebuf[j] = 0;
    142       }
    143       return 0;
    144     }
    145     ++s; ++len;
    146   }
    147   /* right side */
    148   if (k != -1) {
    149     for (j = 0; j < wantrhswords; ++j) {
    150       u = 0x0;
    151       i = scan_ulongalphabet(s,&u, "0123456789abcdef", 16);
    152 #ifdef  CAVEMAN_DEBUGGING
    153       dprintf(DEBUGFD, "scanned %u, ebuf[%u] = %lu, ebuf[%u] = %lu\n", i, (j*2), ((u & 0xff00) >> 8), (j*2)+1, (u & 0xff));
    154 #endif
    155       if (!i) {
    156 #ifdef  CAVEMAN_DEBUGGING
    157         dprintf(DEBUGFD, "scan_ulongalphabet died in right hand side step %u of ip6_scan(\"%s\", ipstruct); want %u has %u\n", j, st, wantrhswords, hasrhswords);
    158 #endif
    159         break;
    160       }
    161       if (u != 0) hasrhswords++;
    162       ebuf[(j*2)] = (unsigned char)((u & 0xff00) >> 8);
    163       ebuf[(j*2)+1] = (u & 0xff);
    164       s += i;
    165       len += i;
    166       if (*s == ':') {
    167         if (*(s + 1) == ':') {
    168 #ifdef  CAVEMAN_DEBUGGING
    169           dprintf(DEBUGFD, "Aaaack! Double :: - break! in right hand side step %u of ip6_scan(\"%s\", ipstruct); want %u has %u\n", j, st, wantrhswords, hasrhswords);
    170 #endif
    171           for (j = 0; j < 16; ++j) {
    172             ip->d[j] = 0;
    173             ebuf[j] = 0;
    174           }
    175           return 0; /* There should never be double :: */
    176         } else {
    177           s += 1;
    178         }
    179       }
    180     }
    181 #ifdef  CAVEMAN_DEBUGGING
    182     dprintf(DEBUGFD, "Before copying rhswords in right hand side step %u of ip6_scan(\"%s\", ipstruct); want %u has %u\n", j, st, wantrhswords, hasrhswords);
    183 #endif
    184     for (k = 0; k < (hasrhswords * 2); ++k) {
    185 #ifdef  CAVEMAN_DEBUGGING
    186       dprintf(DEBUGFD, "Copying rhswords in right hand side step %u of ip6_scan(\"%s\", ipstruct); ebuf reached %u words\n", j, st, hasrhswords);
    187       dprintf(DEBUGFD, "scanned %u, ebuf[%u] = %hhu, to ip->d[%u]\n", i, (j * 2)-1-k, ebuf[(j * 2)-1-k], 15-k);
    188 #endif
    189       ip->d[15-k] = ebuf[(j * 2)-1-k];
    190     }
    191   }
    192   return len;
    193 }
    194 
    195 unsigned int ip6_scanbracket(char *s, struct ip_address *ip)
    196 {
    197   /* SMTP-specific scanbracket. */
    198   unsigned int len;
    199 
    200   if (*s != '[') return 0;
    201   if (*++s != 'I' && *s != 'i') return 0;
    202   if (*++s != 'P' && *s != 'p') return 0;
    203   if (*++s != 'V' && *s != 'v') return 0;
    204   if (*++s != '6') return 0;
    205   if (*++s != ':') return 0;
    206   len = ip_scan(s + 1,ip); /* IPv6:::ffff:127.0.0.1 ... it's 2022, you never know ~H */
    207   if (!len) return 0;
    208   if (s[len + 1] != ']') return 0;
    209   return len + 7;
    210 }
    211 
    212 unsigned int ip_fmt(char *s, struct ip_address *ip)
    213 {
    214   return (ip->is6 ?
    215    ip6_fmt(s, &(ip->ip.aaaa)) :
    216    ip4_fmt(s, &(ip->ip.a))
    217   );
    218 }
    219 
    220 unsigned int ip_scan(char *s, struct ip_address *ip)
    221 {
    222   unsigned int r;
    223   /* this won't catch all cases of 6map4, but it's good enough. ~Hildie */
    224   if (case_starts(s, "::ffff:")) if ((r = ip4_scan(s + 7, &(ip->ip.a)))) return (ip->is6 = 0, r);
    225   if (case_starts(s, "0::ffff:")) if ((r = ip4_scan(s + 8, &(ip->ip.a)))) return (ip->is6 = 0, r);
    226   if ((r = ip6_scan(s, &(ip->ip.aaaa)))) return (ip->is6 = 1, r);
    227   if ((r = ip4_scan(s, &(ip->ip.a)))) return (ip->is6 = 0, r);
    228   return 0;
    229 }
    230 
    231 unsigned int ip_scanbracket(char *s, struct ip_address *ip)
    232 {
    233   unsigned int r;
    234   if ((r = ip6_scanbracket(s, ip))) return (ip->is6 = 1, r);
    235   if ((r = ip4_scanbracket(s, &(ip->ip.a)))) return (ip->is6 = 0, r);
    236   return (ip->is6 = 0, 0);
    237 }