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 }