1 /*
2 ** Copyright (C) 2001-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  skipaddr.h
11 **
12 **    Macros and function declarations for handling IP addresses
13 **    (skipaddr_t and skIPUnion_t).
14 **
15 */
16 #ifndef _SKIPADDR_H
17 #define _SKIPADDR_H
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 #include <silk/silk.h>
23 
24 RCSIDENTVAR(rcsID_SKIPADDR_H, "$SiLK: skipaddr.h ef14e54179be 2020-04-14 21:57:45Z mthomas $");
25 
26 #include <silk/silk_types.h>
27 
28 /*
29 **  For reference.  Defined in silk_types.h
30 **
31 **    typedef union skipunion_un {
32 **        uint32_t    ipu_ipv4;
33 **    #if SK_ENABLE_IPV6
34 **        uint8_t     ipu_ipv6[16];
35 **    #endif
36 **    } skIPUnion_t;
37 **
38 **
39 **    typedef struct skipaddr_st {
40 **        skIPUnion_t ip_ip;
41 **    #if SK_ENABLE_IPV6
42 **        unsigned    ip_is_v6 :1;
43 **    #endif
44 **    } skipaddr_t;
45 */
46 
47 
48 /*
49  *  is_zero = SK_IPV6_IS_ZERO(ipv6);
50  *
51  *    Return true if the specified ipv6 address is zero, where ipv6
52  *    was defined as:
53  *
54  *    uint8_t ipv6[16];
55  */
56 #define SK_IPV6_IS_ZERO(v6_byte_array)                                  \
57     (0 == memcmp((v6_byte_array), sk_ipv6_zero, SK_IPV6_ZERO_LEN))
58 #define SK_IPV6_ZERO_LEN 16
59 extern const uint8_t sk_ipv6_zero[SK_IPV6_ZERO_LEN];
60 
61 
62 /*
63  *  is_v4_in_v6 = SK_IPV6_IS_V4INV6(ipv6);
64  *
65  *    Return true if the specified ipv6 address represents an
66  *    IPv6-encoded-IPv4 address, where ipv6 was defined as:
67  *
68  *    uint8_t ipv6[16];
69  */
70 #define SK_IPV6_IS_V4INV6(v6_byte_array)                                   \
71     (0 == memcmp((v6_byte_array), sk_ipv6_v4inv6, SK_IPV6_V4INV6_LEN))
72 #define SK_IPV6_V4INV6_LEN 12
73 extern const uint8_t sk_ipv6_v4inv6[SK_IPV6_V4INV6_LEN];
74 
75 
76 /* ****  skIPUnion_t  **** */
77 
78 /* Macros dealing with skIPUnion_t's are typically for use by other
79  * SiLK macros and functions.  These macros are subject to change at
80  * any time. */
81 
82 /* Get and Set the V4 part of the address structure */
83 #define skIPUnionGetV4(ipu)                     \
84     ((ipu)->ipu_ipv4)
85 
86 #define skIPUnionSetV4(ipu, in_vp)              \
87     memcpy(&((ipu)->ipu_ipv4), (in_vp), 4)
88 
89 #define skIPUnionApplyMaskV4(ipu, v4_mask)              \
90     do { ((ipu)->ipu_ipv4) &= (v4_mask); } while(0)
91 
92 /* Get the 'cidr' most significant bits of the V4 address */
93 #define skIPUnionGetCIDRV4(ipu, cidr)                   \
94     (((cidr) >= 32)                                     \
95      ? ((ipu)->ipu_ipv4)                                \
96      : (((ipu)->ipu_ipv4) & ~(UINT32_MAX >> cidr)))
97 
98 /* Set the V4 address to its 'cidr' most significant bits.  Assumes
99  * the following: 0 <= 'cidr' < 32 */
100 #define skIPUnionApplyCIDRV4(ipu, cidr)                                 \
101     do { (((ipu)->ipu_ipv4) &= ~(UINT32_MAX >> cidr)); } while(0)
102 
103 #if SK_ENABLE_IPV6
104 
105 /* Get and Set the V6 parts of the address structure */
106 #define skIPUnionGetV6(ipu, out_vp)             \
107     memcpy((out_vp), (ipu)->ipu_ipv6, 16)
108 
109 #define skIPUnionSetV6(ipu, in_vp)              \
110     memcpy((ipu)->ipu_ipv6, (in_vp), 16)
111 
112 /* Convert a pointer to a native uint32_t to an IPv6 byte array  */
113 #define skIPUnionU32ToV6(src_u32, dst_v6)                               \
114     do {                                                                \
115         uint32_t ipu32tov6 = htonl(*(src_u32));                         \
116         memcpy((dst_v6), sk_ipv6_v4inv6, SK_IPV6_V4INV6_LEN);           \
117         memcpy(((uint8_t*)(dst_v6)+SK_IPV6_V4INV6_LEN), &ipu32tov6, 4); \
118     } while(0)
119 
120 /* Write the V4 address into a V6 location. The two parameters can
121  * point to the same skIPUnion_t. */
122 #define skIPUnionGetV4AsV6(ipu, ipv6)           \
123     skIPUnionU32ToV6(&((ipu)->ipu_ipv4), ipv6)
124 
125 /* Convert a V4 skIPUnion_t to an V6 skIPUnion_t. The two parameters
126  * can point to the same skIPUnion_t. */
127 #define skIPUnion4to6(src_ipu, dst_ipu)                                 \
128     skIPUnionU32ToV6(&((src_ipu)->ipu_ipv4), (dst_ipu)->ipu_ipv6)
129 
130 #define skIPUnionApplyMaskV6(ipu, v6_mask)                              \
131     do {                                                                \
132         int ipuam;                                                      \
133         for (ipuam = 0; ipuam < 16; ++ipuam) {                          \
134             (ipu)->ipu_ipv6[ipuam] &= ((int8_t*)(v6_mask))[ipuam];      \
135         }                                                               \
136     } while(0)
137 
138 
139 /* Get the 'cidr' most significant bits of the V6 address */
140 #define skIPUnionGetCIDRV6(ipu, out_vp, cidr)                           \
141     if ((cidr) >= 128) {                                                \
142         skIPUnionGetV6((ipu), (out_vp));                                \
143     } else {                                                            \
144         int ipugc6 = (cidr) >> 3;                                       \
145         memcpy((out_vp), (ipu)->ipu_ipv6, ipugc6);                      \
146         ((uint8_t*)(out_vp))[ipugc6] = ((ipu)->ipu_ipv6[ipugc6]         \
147                                         & ~(0xFF >> (0x7 & (cidr))));   \
148         memset(&((uint8_t*)(out_vp))[ipugc6+1], 0, 15 - ipugc6);        \
149     }
150 
151 /* Set the V6 address to its 'cidr' most significant bits.  assumes
152  * the following: 0 <= cidr < 128 */
153 #define skIPUnionApplyCIDRV6(ipu, cidr)                         \
154     do {                                                        \
155         int ipugc6 = (cidr) >> 3;                               \
156         (ipu)->ipu_ipv6[ipugc6] &= ~(0xFF >> (0x7 & (cidr)));   \
157         memset(&(ipu)->ipu_ipv6[ipugc6+1], 0, 15 - ipugc6);     \
158     } while(0)
159 #endif  /* #if SK_ENABLE_IPV6 */
160 
161 
162 /* ****  skipaddr_t  **** */
163 
164 /**
165  *  is_v6 = skipaddrIsV6(ipaddr).
166  *
167  *    Return 1 if the skipaddr_t 'ipaddr' is an IPv6 address.  Return
168  *    0 otherwise.
169  */
170 #if 0
171 int
172 skipaddrIsV6(
173     const skipaddr_t   *ipaddr);
174 #endif  /* 0 */
175 #if !SK_ENABLE_IPV6
176 #  define skipaddrIsV6(addr)   0
177 #else
178 #  define skipaddrIsV6(addr)   ((addr)->ip_is_v6)
179 #endif  /* #else of #if !SK_ENABLE_IPV6 */
180 
181 
182 /**
183  *  skipaddrSetVersion(addr, is_v6);
184  *
185  *    If 'is_v6' is non-zero, specify that the skipaddr_t 'addr'
186  *    contains an IPv6 address.  This does not modify the
187  *    representation of the IP address.  See also skipaddrV4toV6().
188  */
189 #if 0
190 void
191 skipaddrSetVersion(
192     skipaddr_t         *ipaddr,
193     int                 is_v6);
194 #endif  /* 0 */
195 #if !SK_ENABLE_IPV6
196 #  define skipaddrSetVersion(addr, is_v6)
197 #else
198 #  define skipaddrSetVersion(addr, is_v6)     \
199     do { (addr)->ip_is_v6 = !!(is_v6); } while(0)
200 #endif  /* #else of #if !SK_ENABLE_IPV6 */
201 
202 
203 /**
204  *  skipaddrCopy(dst, src);
205  *
206  *    Copy the skipaddr_t pointed at by 'src' to the location of the
207  *    skipaddr_t pointed at by 'dst'.
208  */
209 #if 0
210 void
211 skipaddrCopy(
212     skipaddr_t         *dst,
213     const skipaddr_t   *src);
214 #endif  /* 0 */
215 #if !SK_ENABLE_IPV6
216 #  define skipaddrCopy(dst, src)                                        \
217     do {                                                                \
218         skIPUnionGetV4(&(dst)->ip_ip) = skIPUnionGetV4(&(src)->ip_ip);  \
219     } while(0)
220 #else
221 #  define skipaddrCopy(dst, src)   memcpy((dst), (src), sizeof(skipaddr_t))
222 #endif  /* #else of #if !SK_ENABLE_IPV6 */
223 
224 
225 /**
226  *  skipaddrClear(addr);
227  *
228  *    Set all bits in the skipaddr_t pointed at by 'addr' to 0.  This
229  *    causes 'addr' to represent the IPv4 address 0.0.0.0.
230  */
231 #if 0
232 void
233 skipaddrClear(
234     skipaddr_t         *ipaddr);
235 #endif  /* 0 */
236 #if !SK_ENABLE_IPV6
237 #  define skipaddrClear(addr)                           \
238     do { skIPUnionGetV4(&(addr)->ip_ip) = 0; } while(0)
239 #else
240 #  define skipaddrClear(addr)   memset((addr), 0, sizeof(skipaddr_t))
241 #endif  /* #else of #if !SK_ENABLE_IPV6 */
242 
243 
244 /**
245  *  ipv4 = skipaddrGetV4(addr);
246  *
247  *    Treat the skipaddr_t 'addr' as containing an IPv4 address and
248  *    return that value in native (host) byte order.  To properly
249  *    handle the cases where 'addr' contains an IPv6 address, use
250  *    skipaddrGetAsV4().
251  */
252 #if 0
253 uint32_t
254 skipaddrGetV4(
255     const skipaddr_t   *addr);
256 #endif  /* 0 */
257 #define skipaddrGetV4(addr)    (skIPUnionGetV4(&((addr)->ip_ip)))
258 
259 
260 /**
261  *  is_v4_mapped_v6 = skipaddrIsV4MappedV6(addr);
262  *
263  *    Return true if 'addr' is an IPv6 address and is in the
264  *    ::ffff:0:0/96 netblock.  That is, whether 'addr' is an
265  *    IPv4-mapped IPv6 address.
266  *
267  *    Return false if 'addr' is an IPv4 address.
268  *
269  *    If the IPv4 address is wanted, use skipaddrGetAsV4() which
270  *    extracts the IPv4 address and returns 0 if successful or returns
271  *    -1 if the address is not IPv4 nor an IPv4-mapped IPv6 address.
272  *
273  *    Since SiLK 3.17.0.
274  */
275 #if 0
276 int
277 skipaddrIsV4MappedV6(
278     const skipaddr_t   *ipaddr);
279 #endif  /* 0 */
280 #if !SK_ENABLE_IPV6
281 #  define skipaddrIsV4MappedV6(addr)    0
282 #else
283 #  define skipaddrIsV4MappedV6(addr)                                    \
284     ((addr)->ip_is_v6 && SK_IPV6_IS_V4INV6((addr)->ip_ip.ipu_ipv6))
285 #endif  /* #else of #if !SK_ENABLE_IPV6 */
286 
287 
288 /**
289  *  ok = skipaddrGetAsV4(addr, &ipv4);
290  *
291  *    If the skipaddr_t 'addr' contains an IPv4 address or an
292  *    IPv4-mapped IPv6 address (i.e., an address in the ::ffff:0:0/96
293  *    netblock), set the value pointed at by the uint32_t 'ipv4' to
294  *    the IPv4 address (in native (host) byte order) and return 0.
295  *    Otherwise leave the value pointed at by 'ipv4' unchanged and
296  *    return -1.
297  *
298  *    If 'addr' is known to be IPv4, consider using skipaddrGetV4().
299  *
300  *    If 'addr' is known to be IPv6 and the IPv4-mapped address is not
301  *    needed, you may check whether this function would return 0 by
302  *    using skipaddrIsV4MappedV6().
303  */
304 #if !SK_ENABLE_IPV6
305 /* use comma expression so expression evaluates to 0 */
306 #  define skipaddrGetAsV4(addr, ipv4_ptr)       \
307     ((*(ipv4_ptr) = skipaddrGetV4(addr)), 0)
308 #else
309 int
310 skipaddrGetAsV4(
311     const skipaddr_t   *addr,
312     uint32_t           *ipv4);
313 #endif  /* #else of #if !SK_ENABLE_IPV6 */
314 
315 
316 /**
317  *  skipaddrSetV4(addr, src);
318  *
319  *    Copy the uint32_t refereneced by 'src' into the skipaddr_t
320  *    'addr' and set the 'addr' as containing an IPv4 address.  'src'
321  *    should be in native (host) byte order.
322  */
323 #if 0
324 void
325 skipaddrSetV4(
326     skipaddr_t         *addr,
327     uint32_t            src);
328 #endif  /* 0 */
329 #if !SK_ENABLE_IPV6
330 #  define skipaddrSetV4(addr, in_vp)            \
331     skIPUnionSetV4(&((addr)->ip_ip), in_vp)
332 #else
333 #define skipaddrSetV4(addr, in_vp)                      \
334     do {                                                \
335         skipaddrClear(addr);                            \
336         skIPUnionSetV4(&((addr)->ip_ip), (in_vp));      \
337     } while(0)
338 #endif  /* #else of #if !SK_ENABLE_IPV6 */
339 
340 
341 #if SK_ENABLE_IPV6
342 
343 /**
344  *  skipaddrGetV6(addr, dst);
345  *
346  *    Treat 'addr' as containing an IPv6 address and copy that value
347  *    into the uint8_t[16] refereneced by 'dst'.  To properly handle
348  *    the cases where 'addr' contains an IPv4 address, use
349  *    skipaddrGetAsV6().
350  */
351 #if 0
352 void
353 skipaddrGetV6(
354     const skipaddr_t   *addr,
355     uint8_t             dst[16]);
356 #endif  /* 0 */
357 #define skipaddrGetV6(addr, out_vp)             \
358     skIPUnionGetV6(&((addr)->ip_ip), (out_vp))
359 
360 
361 /**
362  *  skipaddrGetAsV6(addr, dst);
363  *
364  *    Copy an IPv6 representation of the skipaddr_t 'addr' to the
365  *    uint8_t[16] referenced by 'dst'.  If 'addr' contains an IPv4
366  *    address, the result contains an IPv4-mapped IPv6 address (that
367  *    is, an IPv6 address in the ::ffff:0:0/96 netblock).
368  *
369  *    If 'addr' is known to be IPv6, consider using skipaddrGetV6().
370  */
371 #if 0
372 void
373 skipaddrGetAsV6(
374     const skipaddr_t   *addr,
375     uint8_t             dst[16]);
376 #endif  /* 0 */
377 #define skipaddrGetAsV6(addr, out_vp)                   \
378     if (skipaddrIsV6(addr)) {                           \
379         skIPUnionGetV6(&((addr)->ip_ip), (out_vp));     \
380     } else {                                            \
381         skIPUnionGetV4AsV6(&((addr)->ip_ip), (out_vp)); \
382     }
383 
384 
385 /**
386  *  skipaddrSetV6(addr, src);
387  *
388  *    Copy the uint8_t[16] refereneced by 'src' into the skipaddr_t
389  *    'addr' and set the 'addr' as containing an IPv6 address.
390  */
391 #if 0
392 void
393 skipaddrSetV6(
394     skipaddr_t         *addr,
395     uint8_t             src[16]);
396 #endif  /* 0 */
397 #define skipaddrSetV6(addr, in_vp)                      \
398     do {                                                \
399         skIPUnionSetV6(&((addr)->ip_ip), (in_vp));      \
400         (addr)->ip_is_v6 = 1;                           \
401     } while(0)
402 
403 
404 /**
405  *  skipaddrSetV6FromUint32(addr, src);
406  *
407  *    Treat the uint32_t refereneced by 'src' as an IPv4 address in
408  *    native (host) byte order, convert it to an IPv6 address, and
409  *    store the result in skipaddr_t 'addr'.
410  */
411 #if 0
412 void
413 skipaddrSetV6FromUint32(
414     skipaddr_t         *addr,
415     const uint32_t     *src);
416 #endif  /* 0 */
417 #define skipaddrSetV6FromUint32(addr, in_vp)            \
418     do {                                                \
419         uint8_t v6fromu32[16];                          \
420         skIPUnionU32ToV6((in_vp), v6fromu32);           \
421         skIPUnionSetV6(&((addr)->ip_ip), v6fromu32);    \
422         (addr)->ip_is_v6 = 1;                           \
423     } while(0)
424 
425 /**
426  *  skipaddrV4toV6(srcaddr, dstaddr);
427  *
428  *    Assume the skipaddr_t 'srcaddr' contains an IPv4 address,
429  *    convert that address to an IPv4-mapped IPv6 address (that is, an
430  *    address in the ::ffff:0:0/96 netblock), and store the result in
431  *    the skipaddr_t 'dstaddr'. 'srcaddr' and 'dstaddr' may point to
432  *    the same skipaddr_t.
433  */
434 #if 0
435 void
436 skipaddrV4toV6(
437     const skipaddr_t   *srcaddr,
438     skipaddr_t         *dstaddr);
439 #endif  /* 0 */
440 #define skipaddrV4toV6(srcaddr, dstaddr)                                \
441     do {                                                                \
442         skIPUnion4to6(&((srcaddr)->ip_ip), &((dstaddr)->ip_ip));        \
443         (dstaddr)->ip_is_v6 = 1;                                        \
444     } while(0)
445 
446 
447 /**
448  *  ok = skipaddrV6toV4(srcaddr, dstaddr);
449  *
450  *    Assume the skipaddr_t 'srcaddr' contains an IPv6 address. If
451  *    that address is an IPv4-mapped IPv6 address (that is, an address
452  *    in the ::ffff:0:0/96 netblock), convert the address to IPv4,
453  *    store the result in the skipaddr_t 'dstaddr', and return 0.
454  *    Otherwise, return -1 and leave 'dstaddr' unchanged. 'srcaddr'
455  *    and 'dstaddr' may point to the same skipaddr_t.
456  */
457 int
458 skipaddrV6toV4(
459     const skipaddr_t   *srcaddr,
460     skipaddr_t         *dstaddr);
461 #endif  /* #if SK_ENABLE_IPV6 */
462 
463 
464 /**
465  *  cmp = skipaddrCompare(addr1, addr2);
466  *
467  *    Compare the value of the skipaddr_t objects 'addr1' and 'addr2'.
468  *
469  *    Return 0 if 'addr1' is equal to 'addr2'; return a value less
470  *    than 0 if 'addr1' is less than 'addr2'; return a value greater
471  *    than 0 if 'addr1' is greater than 'addr2'.
472  *
473  *    When IPv6 is enabled and either address is IPv6, the comparison
474  *    is done as if both addresses were IPv6 by mapping an IPv4
475  *    address to the ::ffff:0:0/96 netblock.
476  */
477 #if !SK_ENABLE_IPV6
478 #  define skipaddrCompare(addr1, addr2)                         \
479     (((addr1)->ip_ip.ipu_ipv4 < (addr2)->ip_ip.ipu_ipv4)        \
480      ? -1                                                       \
481      : (((addr1)->ip_ip.ipu_ipv4 > (addr2)->ip_ip.ipu_ipv4)     \
482         ? 1                                                     \
483         : 0))
484 #else
485 int
486 skipaddrCompare(
487     const skipaddr_t   *addr1,
488     const skipaddr_t   *addr2);
489 #endif  /* #else of #if !SK_ENABLE_IPV6 */
490 
491 
492 /**
493  *  skipaddrMask(ipaddr, mask_ip);
494  *
495  *    Apply the bit-mask in the skipaddr_t 'mask_ip' to the skipaddr_t
496  *    'ipaddr'.
497  *
498  *    When both addresses are either IPv4 or IPv6, applying the mask
499  *    is straightforward.
500  *
501  *    When 'ipaddr' is IPv6 and 'mask_ip' is IPv4, the function
502  *    converts 'mask_ip' to an IPv4-mapped IPv6 (i.e., an address in
503  *    the ::ffff:0:0/96 netblock) and then applies the mask.  The
504  *    result is an IPv6 address.
505  *
506  *    When 'ipaddr' is IPv4 and 'mask_ip' is IPv6, the function
507  *    converts 'ipaddr' to an IPv4-mapped IPv6 address and performs
508  *    the mask.  If the result is still an IPv4-mapped IPv6 address,
509  *    the function converts the result back to IPv4; otherwise the
510  *    result remains an IPv6 address.
511  */
512 #if !SK_ENABLE_IPV6
513 #  define skipaddrMask(ipaddr, mask_ip)                         \
514     do {                                                        \
515         (ipaddr)->ip_ip.ipu_ipv4 &= (mask_ip)->ip_ip.ipu_ipv4;  \
516     } while(0)
517 #else
518 void
519 skipaddrMask(
520     skipaddr_t         *ipaddr,
521     const skipaddr_t   *mask_ip);
522 #endif  /* #else of #if !SK_ENABLE_IPV6 */
523 
524 
525 /**
526  *  skipaddrApplyCIDR(ipaddr, cidr_prefix);
527  *
528  *    Apply the numeric CIDR prefix 'cidr_prefix' to the skipaddr_t
529  *    'ipaddr', zeroing all but the most significant 'cidr_prefix'
530  *    bits.
531  *
532  *    If a CIDR prefix too large for the address is given, it will be
533  *    ignored.
534  */
535 #if 0
536 void
537 skipaddrApplyCIDR(
538     skipaddr_t         *ipaddr,
539     uint32_t            cidr_prefix);
540 #endif  /* 0 */
541 #if !SK_ENABLE_IPV6
542 #  define skipaddrApplyCIDR(ipaddr, cidr)               \
543     if ((cidr) >= 32) { /* no-op */ } else {            \
544         skIPUnionApplyCIDRV4(&(ipaddr)->ip_ip, cidr);   \
545     }
546 #else
547 #  define skipaddrApplyCIDR(ipaddr, cidr)                       \
548     if (skipaddrIsV6(ipaddr)) {                                 \
549         if ((cidr) < 128) {                                     \
550             skIPUnionApplyCIDRV6(&((ipaddr)->ip_ip), cidr);     \
551         }                                                       \
552     } else {                                                    \
553         if ((cidr) < 32) {                                      \
554             skIPUnionApplyCIDRV4(&((ipaddr)->ip_ip), cidr);     \
555         }                                                       \
556     }
557 #endif  /* #else of #if !SK_ENABLE_IPV6 */
558 
559 
560 /**
561  *  skipaddrIncrement(ipaddr);
562  *
563  *    Add one to the integer representation of the IP address in the
564  *    skipaddr_t 'ipaddr'.  If overflow occurs, wrap the value back to
565  *    0.
566  */
567 #if 0
568 void
569 skipaddrIncrement(
570     skipaddr_t         *ipaddr);
571 #endif  /* 0 */
572 #if !SK_ENABLE_IPV6
573 #define skipaddrIncrement(addr)                 \
574     ((void)(++(addr)->ip_ip.ipu_ipv4))
575 #else
576 #define skipaddrIncrement(addr)                                         \
577     if (!skipaddrIsV6(addr)) {                                          \
578         ++(addr)->ip_ip.ipu_ipv4;                                       \
579     } else {                                                            \
580         int incr_idx;                                                   \
581         for (incr_idx = 15; incr_idx >= 0; --incr_idx) {                \
582             if (UINT8_MAX != (addr)->ip_ip.ipu_ipv6[incr_idx]) {        \
583                 ++(addr)->ip_ip.ipu_ipv6[incr_idx];                     \
584                 break;                                                  \
585             }                                                           \
586             (addr)->ip_ip.ipu_ipv6[incr_idx] = 0;                       \
587         }                                                               \
588     }
589 #endif  /* #else of #if !SK_ENABLE_IPV6 */
590 
591 
592 /**
593  *  skipaddrDecrement(ipaddr);
594  *
595  *    Subtract one from the integer representation of the IP address
596  *    in the skipaddr_t 'ipaddr'.  If underflow occurs, wrap the value
597  *    back to the maximum.
598  */
599 #if 0
600 void
601 skipaddrDecrement(
602     skipaddr_t         *ipaddr);
603 #endif  /* 0 */
604 #if !SK_ENABLE_IPV6
605 #define skipaddrDecrement(addr)                 \
606     ((void)(--(addr)->ip_ip.ipu_ipv4))
607 #else
608 #define skipaddrDecrement(addr)                                         \
609     if (!skipaddrIsV6(addr)) {                                          \
610         --(addr)->ip_ip.ipu_ipv4;                                       \
611     } else {                                                            \
612         int decr_idx;                                                   \
613         for (decr_idx = 15; decr_idx >= 0; --decr_idx) {                \
614             if (0 != (addr)->ip_ip.ipu_ipv6[decr_idx]) {                \
615                 --(addr)->ip_ip.ipu_ipv6[decr_idx];                     \
616                 break;                                                  \
617             }                                                           \
618             (addr)->ip_ip.ipu_ipv6[decr_idx] = UINT8_MAX;               \
619         }                                                               \
620     }
621 #endif  /* #else of #if !SK_ENABLE_IPV6 */
622 
623 
624 /**
625  *  is_zero = skipaddrIsZero(ipaddr);
626  *
627  *    Return 1 if the IP address in the skipaddr_t 'ipaddr' contains
628  *    no high bits.  Return 0 otherwise.
629  *
630  *    skipaddrIsZero(skipaddrClear(ipaddr)) returns 1.
631  */
632 #if 0
633 int
634 skipaddrIsZero(
635     const skipaddr_t   *ipaddr);
636 #endif  /* 0 */
637 #if !SK_ENABLE_IPV6
638 #  define skipaddrIsZero(addr) (0 == (addr)->ip_ip.ipu_ipv4)
639 #else
640 #  define skipaddrIsZero(addr)                                          \
641     (skipaddrIsV6(addr)                                                 \
642      ? SK_IPV6_IS_ZERO((addr)->ip_ip.ipu_ipv6)                          \
643      : (0 == (addr)->ip_ip.ipu_ipv4))
644 #endif  /* #else of #if !SK_ENABLE_IPV6 */
645 
646 
647 /* ****  skcidr_t  **** */
648 
649 /**
650  *    skcidr_t represents a CIDR block or net-block.  The structure
651  *    holds an IP address and the number of subnet bits.
652  */
653 typedef union skcidr_un {
654     struct cidr_un_v4 {
655         /* whether this value contains an IPv6 mask */
656         uint8_t  is_ipv6;
657         /* length of the subnet (in bits). */
658         uint8_t  cidr_length;
659         /* placeholders for alignment */
660         uint8_t  unused2;
661         uint8_t  unused3;
662         /* the base IP of the CIDR block */
663         uint32_t ip;
664         /* pre-computed mask where the upper length bits are high */
665         uint32_t mask;
666     } v4;
667 #if SK_ENABLE_IPV6
668     struct cidr_un_v6 {
669         /* whether this value contains an IPv6 mask */
670         uint8_t  is_ipv6;
671         /* length of the subnet (in bits). */
672         uint8_t  cidr_length;
673         /* number of bytes to memcmp() when comparing IP to CIDR */
674         uint8_t  byte_length;
675         /* pre-computed mask to use when comparing the
676          * "ip[byte_length-1]" byte */
677         uint8_t  mask;
678         /* the base IP of the CIDR block */
679         uint8_t  ip[16];
680     } v6;
681 #endif  /* #if SK_ENABLE_IPV6 */
682 } skcidr_t;
683 
684 
685 /**
686  *  in_cidr = skcidrCheckIP(cidr, ipaddr);
687  *
688  *    Return a true value if 'ipaddr' is contained in the CIDR block
689  *    represented by 'cidr'.  Return false otherwise.
690  */
691 #if !SK_ENABLE_IPV6
692 #define skcidrCheckIP(cidr, ipaddr)                             \
693     ((skipaddrGetV4(ipaddr) & cidr->v4.mask) == (cidr)->v4.ip)
694 #else
695 int
696 skcidrCheckIP(
697     const skcidr_t     *cidr,
698     const skipaddr_t   *ipaddr);
699 #endif  /* #else of #if !SK_ENABLE_IPV6 */
700 
701 
702 /**
703  *  skcidrClear(cidr);
704  *
705  *    Set all bits in the skcidr_t pointed at by 'cidr' to 0.
706  */
707 #if 0
708 void
709 skcidrClear(
710     skcidr_t           *cidr);
711 #endif  /* 0 */
712 #define skcidrClear(cidr)           memset(cidr, 0, sizeof(skcidr_t))
713 
714 
715 /**
716  *  skcidrGetIPAddr(cidr, ipaddr);
717  *
718  *    Fill 'ipaddr' with the IP address contained by 'cidr'; that is,
719  *    with the first IP address in the CIDR block represented by
720  *    'cidr'.
721  */
722 void
723 skcidrGetIPAddr(
724     const skcidr_t     *cidr,
725     skipaddr_t         *ipaddr);
726 
727 
728 /**
729  *  len = skcidrGetLength(cidr);
730  *
731  *    Return the length of the subnet represented by 'cidr'.
732  */
733 #if 0
734 uint8_t
735 skcidrGetLength(
736     const skcidr_t     *cidr);
737 #endif  /* 0 */
738 #define skcidrGetLength(cidr)       ((cidr)->v4.cidr_length)
739 
740 
741 /**
742  *  skcidrIsV6(cidr);
743  *
744  *    Return 1 if the skcidr_t pointed at by 'cidr' contains IPv6
745  *    data.  Return 0 otherwise.
746  */
747 #if 0
748 int
749 skcidrIsV6(
750     const skcidr_t     *cidr);
751 #endif  /* 0 */
752 #if !SK_ENABLE_IPV6
753 #  define skcidrIsV6(cidr)          (0)
754 #else
755 #  define skcidrIsV6(cidr)          ((cidr)->v4.is_ipv6)
756 #endif  /* #else of #if !SK_ENABLE_IPV6 */
757 
758 
759 /**
760  *  ok = skcidrSetFromIPAddr(cidr, ipaddr, length);
761  *
762  *    Set 'cidr' to the CIDR block that represents a subnet of
763  *    'length' bits that has the IP in 'ipaddr' as its base.  Return
764  *    -1 if 'length' is too long for the given 'ipaddr'.  Return 0
765  *    otherwise.
766  */
767 int
768 skcidrSetFromIPAddr(
769     skcidr_t           *cidr,
770     const skipaddr_t   *ipaddr,
771     uint32_t            cidr_len);
772 
773 
774 /**
775  *  ok = skcidrSetV4(cidr, ipv4, length);
776  *
777  *    Similar to skcidrSetFromIPAddr(), except use an integer
778  *    representation of an IPv4 address.
779  */
780 int
781 skcidrSetV4(
782     skcidr_t           *cidr,
783     uint32_t            ipv4,
784     uint32_t            cidr_len);
785 
786 #if SK_ENABLE_IPV6
787 /**
788  *  ok = skcidrSetV6(cidr, ipv6, length);
789  *
790  *    Similar to skcidrSetFromIPAddr(), except use an array
791  *    representation of an IPv6 address.
792  */
793 int
794 skcidrSetV6(
795     skcidr_t           *cidr,
796     const uint8_t      *ipv6,
797     uint32_t            cidr_len);
798 #endif  /* #if SK_ENABLE_IPV6 */
799 
800 
801 /**
802  *  ok = skipaddrToSockaddr(dest_sockaddr, len, src_ipaddr);
803  *
804  *    Clear 'dest_sockaddr', and then set the family and address of
805  *    'dest_sockaddr' from 'src_ipaddr' where 'len' is the length of
806  *    'dest_sockaddr'.  Return -1 if 'len' is too small, 0 otherwise.
807  */
808 int
809 skipaddrToSockaddr(
810     struct sockaddr    *dest_sockaddr,
811     size_t              len,
812     const skipaddr_t   *src_ipaddr);
813 
814 /**
815  *  ok = skipaddrFromSockaddr(dest_ipaddr, src)
816  *
817  *    Set 'dest_ipaddr' to the address in 'src_sockaddr'.  Return -1
818  *    if 'src_sockaddr' does not represent an IP address, 0 otherwise.
819  */
820 int
821 skipaddrFromSockaddr(
822     skipaddr_t             *dest_ipaddr,
823     const struct sockaddr  *src_sockaddr);
824 
825 
826 #ifdef __cplusplus
827 }
828 #endif
829 #endif /* _SKIPADDR_H */
830 
831 /*
832 ** Local Variables:
833 ** mode:c
834 ** indent-tabs-mode:nil
835 ** c-basic-offset:4
836 ** End:
837 */
838