NCBI C++ ToolKit
ncbi_iprange.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_iprange.c 95655 2021-12-06 00:40:13Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anton Lavrentiev
27  *
28  * File Description:
29  * IP range manipulating API
30  *
31  */
32 
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_assert.h"
35 #include <connect/ncbi_iprange.h>
36 #include <connect/ncbi_socket.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 
43 extern int/*bool*/ NcbiIsInIPRange(const SIPRange* range,
44  const TNCBI_IPv6Addr* addr)
45 {
46  if (range && addr) {
47  unsigned int a, b, ip;
48 
49  switch (range->type) {
50  case eIPRange_Host:
51  assert(!range->b);
52  assert(sizeof(range->a) == sizeof(*addr));
53  return !memcmp(&range->a, addr, sizeof(range->a));
54  case eIPRange_Range:
55  assert(NcbiIsIPv4(&range->a));
56  if (!NcbiIsIPv4(addr))
57  break;
58  /* all host byte order */
60  b = SOCK_NetToHostLong( range->b );
62  assert(a < b);
63  return a <= ip && ip <= b;
64  case eIPRange_Network:
65  a = !NcbiIsIPv4(&range->a);
66  b = !NcbiIsIPv4(addr);
67  if (a ^ b)
68  break;
69  if (a & b)
70  return NcbiIsInIPv6Network(&range->a, range->b, addr);
71  /* all network byte order */
72  a = NcbiIPv6ToIPv4(&range->a, 0);
73  b = range->b;
74  ip = NcbiIPv6ToIPv4( addr, 0);
75  assert(a && b);
76  return !((ip & b) ^ a);
77  default:
78  assert(0);
79  /*FALLTHRU*/
80  case eIPRange_None:
82  break;
83  }
84  }
85  return 0/*false*/;
86 }
87 
88 
90 {
91  unsigned int a;
92  SIPRange retval;
93  switch (range ? range->type : eIPRange_None) {
94  default:
95  assert(0);
96  /*FALLTHRU*/
97  case eIPRange_None:
99  memset(&retval, 0, sizeof(retval));
100  /*retval.type = eIPRange_None;*/
101  return retval;
102  case eIPRange_Host:
103  assert(!range->b);
104  if (!NcbiIsIPv4(&range->a)) {
105  retval = *range;
106  return retval;
107  }
108  retval.a = range->a;
109  retval.b = NcbiIPv6ToIPv4(&range->a, 0);
110  break;
111  case eIPRange_Range:
112  assert(NcbiIsIPv4(&range->a) && range->b);
115  retval.a = range->a;
116  retval.b = range->b;
117  break;
118  case eIPRange_Network:
119  assert(!NcbiIsEmptyIPv6(&range->a) && range->b);
120  if (!NcbiIsIPv4(&range->a)) {
121  retval = *range;
122  return retval;
123  }
124  a = NcbiIPv6ToIPv4(&range->a, 0);
125  assert(a && !(a & ~range->b));
126  retval.a = range->a;
127  retval.b = a | ~range->b;
128  break;
129  }
130  retval.type = eIPRange_Range;
131  return retval;
132 }
133 
134 
135 #ifdef __GNUC__
136 inline
137 #endif /*__GNUC__*/
138 static size_t x_size(const char* dst, size_t len, const char* ptr)
139 {
140  return len > (size_t)(ptr - dst) ? len - (size_t)(ptr - dst) : 0;
141 }
142 
143 
144 extern const char* NcbiDumpIPRange(const SIPRange* range,
145  char* buf, size_t bufsize)
146 {
147  char result[150];
148 
149  if (!buf || !bufsize)
150  return 0;
151  if (!range) {
152  *buf = '\0';
153  return 0;
154  }
155  if (range->type == eIPRange_Application) {
156  *buf = '\0';
157  return buf;
158  }
159 
160  if (range->type != eIPRange_None) {
162  char* s = result;
163  switch (range->type) {
164  case eIPRange_Host:
165  assert(!range->b);
166  memcpy(s, "Host", 4);
167  s += 4;
168  break;
169  case eIPRange_Range:
170  assert(NcbiIsIPv4(&range->a));
171  assert(range->b);
172  memcpy(s, "Range", 5);
173  s += 5;
174  break;
175  case eIPRange_Network:
176  assert(range->b);
177  memcpy(s, "Network", 7);
178  s += 7;
179  break;
180  default:
181  *buf = '\0';
182  assert(0);
183  return 0;
184  }
185  *s++ = ' ';
186  if (temp.type != eIPRange_Range) {
187  assert(!NcbiIsIPv4(&range->a));
188  assert(memcmp(&temp, range, sizeof(temp)) == 0);
189  s = NcbiIPv6ToString(s, x_size(result, sizeof(result), s),
190  &temp.a);
191  assert(s + 40 < result + sizeof(result));
192  if (s && temp.type == eIPRange_Network)
193  sprintf(s, "/%u", temp.b);
194  } else {
195  assert(memcmp(&temp.a, &range->a, sizeof(temp.a)) == 0);
196  if (SOCK_ntoa(NcbiIPv6ToIPv4(&temp.a, 0),
197  s, x_size(result, sizeof(result), s)) != 0) {
198  strcpy(s++, "?");
199  } else
200  s += strlen(s);
201  if (range->type != eIPRange_Host) {
202  *s++ = '-';
203  if (SOCK_ntoa(temp.b,
204  s, x_size(result, sizeof(result), s)) != 0) {
205  strcpy(s, "?");
206  }
207  }
208  }
209  } else
210  strcpy(result, "None");
211 
212  return strncpy0(buf, result, bufsize - 1);
213 }
214 
215 
216 extern int/*bool*/ NcbiParseIPRange(SIPRange* range, const char* str)
217 {
218  unsigned int addr, temp;
219  const char* p;
220  size_t len, n;
221  int dots;
222  char* e;
223  long d;
224 
225  if (!range || !str)
226  return 0/*failure*/;
227 
228  if (!*str) {
229  memset(range, 0, sizeof(*range));
230  /*range->type = eIPRange_None;*/
231  return 1/*success*/;
232  }
233 
234  p = NcbiIPToAddr(&range->a, str, len = strlen(str));
235  if (p) {
236  assert(p > str);
237  if (!*p /*p == str + len*/) {
238  range->b = 0;
239  range->type = eIPRange_Host;
240  return 1/*success*/;
241  }
242  if (*p++ == '/' && !isspace((unsigned char)(*p))) {
243  errno = 0;
244  d = strtol(p, &e, 10);
245  if (!errno && p != e && !*e && d > 0) {
246  int/*bool*/ ipv4 = NcbiIsIPv4(&range->a);
247  if (ipv4 && d <= 32) {
248  if (!d || d == 32) {
249  range->b = 0;
250  range->type = eIPRange_Host;
251  return 1/*success*/;
252  }
253  addr = SOCK_NetToHostLong(NcbiIPv6ToIPv4(&range->a, 0));
254  temp = (unsigned int)(~0UL << (32 - d));
255  range->b = SOCK_HostToNetLong(temp);
256  range->type = eIPRange_Network;
257  return addr && !(addr & ~temp);
258  } else if (!ipv4
259  && (size_t) d <= (sizeof(range->a.octet) << 3)) {
260  if (!d || (size_t) d == (sizeof(range->a.octet) << 3)) {
261  range->b = 0;
262  range->type = eIPRange_Host;
263  return 1/*success*/;
264  }
265  if (NcbiIsEmptyIPv6(&range->a))
266  return 0/*failure*/;
267  range->b = (unsigned int) d; /* d > 0 */
268  range->type = eIPRange_Network;
269  d = (long)(sizeof(range->a.octet) << 3) - d;
270  assert(d > 0);
271  for (n = sizeof(range->a.octet); n > 0; --n) {
272  if (d >= 8) {
273  if (range->a.octet[n - 1] & ~0)
274  return 0/*failure*/;
275  d -= 8;
276  } else if (d) {
277  if (range->a.octet[n - 1] & ~(~0 << d))
278  return 0/*failure*/;
279  break;
280  } else
281  break;
282  }
283  return 1/*success*/;
284  } else
285  return 0/*failure*/;
286  }
287  }
288  }
289  if (SOCK_isip(str)) {
290  /* forbid other misleading IP representations */
291  assert(!SOCK_isipEx(str, 1/*fullquad*/));
292  return 0/*failure*/;
293  }
294 
295  p = str;
296  dots = 0;
297  range->type = eIPRange_Host;
298  addr = 0/*not actually necessary*/;
299  for (;;) {
300  const char* t;
301  if (*p != '*') {
302  char s[4];
303  errno = 0;
304  d = strtol(p, &e, 10);
305  if (errno || p == e || e - p > 3 || d < 0 || 255 < d
306  || sprintf(s, "%u", (unsigned int) d) != (int)(e - p)) {
307  break/*goto out*/;
308  }
309  p = e;
310  } else if (!*++p && dots) {
311  temp = (unsigned int)((4 - dots) << 3);
312  addr <<= temp;
313  NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0);
314  range->b = SOCK_HostToNetLong((unsigned int)(~0UL << temp));
315  range->type = eIPRange_Network;
316  return 1/*success*/;
317  } else
318  return 0/*failure (asterisks not valid in hostnames)*/;
319  switch (range->type) {
320  case eIPRange_Host:
321  addr <<= 8;
322  addr |= (unsigned int) d;
323  if (*p != '.') {
324  addr <<= (3 - dots) << 3;
325  switch (*p) {
326  case '/':
327  range->type = eIPRange_Network;
328  break;
329  case '-':
330  range->type = eIPRange_Range;
331  p++;
332  continue;
333  default:
334  goto out;
335  }
336  } else if (++dots <= 3) {
337  p++;
338  continue;
339  } else
340  goto out;
341  assert(*p == '/' && range->type == eIPRange_Network);
342  t = NcbiStringToIPv4(&range->b, ++p, 0);
343  if (!t || *t)
344  continue;
345  NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0);
346  if (!range->b || !(temp = ~SOCK_NetToHostLong(range->b))) {
347  range->b = 0;
348  range->type = eIPRange_Host;
349  return 1/*success*/;
350  }
351  return !(temp & (temp + 1)) && addr && !(addr & temp);
352  case eIPRange_Range:
353  if (*p)
354  goto out;
355  temp = dots > 0 ? addr : 0;
356  temp &= (unsigned int)(~((1UL << ((4 - dots) << 3)) - 1));
357  temp |= (unsigned int) (d << ((3 - dots) << 3));
358  temp |= (unsigned int) ((1U << ((3 - dots) << 3)) - 1);
359  NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0);
360  if (addr == temp) {
361  range->b = 0;
362  range->type = eIPRange_Host;
363  return 1/*success*/;
364  }
365  range->b = SOCK_HostToNetLong(temp);
366  return addr < temp;
367  case eIPRange_Network:
368  if (*p || d > 32)
369  return 0/*failure (slashes not valid in hostnames)*/;
370  NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0);
371  if (!d || d == 32) {
372  range->b = 0;
373  range->type = eIPRange_Host;
374  return 1/*success*/;
375  }
376  temp = (unsigned int)(~0UL << (32 - d));
377  range->b = SOCK_HostToNetLong(temp);
378  return addr && !(addr & ~temp);
379  default:
380  assert(0);
381  return 0/*failure*/;
382  }
383  }
384  out:
385 
386  /* last resort (and maybe expensive one): try as a regular host name */
387  range->b = 0;
388  range->type = eIPRange_Host;
389  p = NcbiDNSIPToAddr(&range->a, str, len);
390  assert(!p || p > str);
391  if (p && !*p)
392  return 1/*success*/;
393  if (!(addr = SOCK_gethostbyname(str)))
394  return 0/*failure*/;
395  NcbiIPv4ToIPv6(&range->a, addr, 0);
396  return 1/*success*/;
397 }
static const char ip[]
Definition: des.c:75
std::ofstream out("events_result.xml")
main entry point for tests
static const char * str(char *buf, int n)
Definition: stats.c:84
int SOCK_isipEx(const char *host, int fullquad)
Check whether the given string represents a valid IPv4 address.
Definition: ncbi_socket.c:8680
unsigned int SOCK_HostToNetLong(unsigned int value)
See man for the BSDisms, htonl() and htons().
Definition: ncbi_socket.c:8736
#define SOCK_NetToHostLong
Definition: ncbi_socket.h:2096
unsigned int SOCK_gethostbyname(const char *hostname)
Same as SOCK_gethostbynameEx(,<current API data logging>)
Definition: ncbi_socket.c:8790
int SOCK_ntoa(unsigned int addr, char *buf, size_t bufsize)
Convert IP address to a string in dotted notation.
Definition: ncbi_socket.c:8661
int SOCK_isip(const char *host)
Equivalent of SOCK_isip(host, 0)
Definition: ncbi_socket.c:8712
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
char * buf
yy_size_t n
int len
range(_Ty, _Ty) -> range< _Ty >
char * strncpy0(char *s1, const char *s2, size_t n)
Copy not more than "n" characters from string "s2" into "s1", and return the result,...
SIPRange NcbiTrueIPRange(const SIPRange *range)
Definition: ncbi_iprange.c:89
int NcbiIsInIPRange(const SIPRange *range, const TNCBI_IPv6Addr *addr)
Definition: ncbi_iprange.c:43
const char * NcbiDumpIPRange(const SIPRange *range, char *buf, size_t bufsize)
Definition: ncbi_iprange.c:144
static size_t x_size(const char *dst, size_t len, const char *ptr)
Definition: ncbi_iprange.c:138
int NcbiParseIPRange(SIPRange *range, const char *str)
Acceptable forms (netmasked IPv4s may omit trailing .0s before '/'): 4 quad full IP: 123....
Definition: ncbi_iprange.c:216
@ eIPRange_Network
Definition: ncbi_iprange.h:47
@ eIPRange_None
Definition: ncbi_iprange.h:44
@ eIPRange_Range
Definition: ncbi_iprange.h:46
@ eIPRange_Host
Definition: ncbi_iprange.h:45
@ eIPRange_Application
Definition: ncbi_iprange.h:48
int NcbiIsEmptyIPv6(const TNCBI_IPv6Addr *addr)
Return non-zero if the address is empty (either as IPv6 or IPv4); return zero otherwise.
Definition: ncbi_ipv6.c:80
const char * NcbiDNSIPToAddr(TNCBI_IPv6Addr *addr, const char *str, size_t len)
Convert into an IPv6 address, the first "len" (or "strlen(str)" if "len" is 0) bytes of "str",...
Definition: ncbi_ipv6.c:697
unsigned int NcbiIPv6ToIPv4(const TNCBI_IPv6Addr *addr, size_t pfxlen)
Extract and return a network byte order IPv4 embedded address from an IPv6 address,...
Definition: ncbi_ipv6.c:101
char * NcbiIPv6ToString(char *buf, size_t bufsize, const TNCBI_IPv6Addr *addr)
Convert an IPv6 address into a hex colon-separated text form and store the result in the "buf" of siz...
Definition: ncbi_ipv6.c:476
int NcbiIsIPv4(const TNCBI_IPv6Addr *addr)
Return non-zero(true) if the address is a true IPv4 address (a mapped IPv4 address); return zero(fals...
Definition: ncbi_ipv6.c:89
const char * NcbiStringToIPv4(unsigned int *addr, const char *str, size_t len)
Convert into a network byte order IPv4 address, the first "len" (or "strlen(str)" if "len" is 0) byte...
Definition: ncbi_ipv6.c:346
int NcbiIsInIPv6Network(const TNCBI_IPv6Addr *base, unsigned int bits, const TNCBI_IPv6Addr *addr)
Return non-zero(true) if "addr" belongs to the network specified as CIDR "base/bits"; return a zero(f...
Definition: ncbi_ipv6.c:706
int NcbiIPv4ToIPv6(TNCBI_IPv6Addr *addr, unsigned int ipv4, size_t pfxlen)
Embed a passed network byte order IPv4 address into an IPv6 address using the specified prefix length...
Definition: ncbi_ipv6.c:142
const char * NcbiIPToAddr(TNCBI_IPv6Addr *addr, const char *str, size_t len)
Convert into an IPv6 address, the first "len" (or "strlen(str)" if "len" is 0) bytes of "str" from ei...
Definition: ncbi_ipv6.c:679
unsigned int a
Definition: ncbi_localip.c:102
EIPRangeType t
Definition: ncbi_localip.c:101
int isspace(Uchar c)
Definition: ncbictype.hpp:69
static int bufsize
Definition: pcregrep.c:162
#define assert(x)
Definition: srv_diag.hpp:58
unsigned int b
Definition: ncbi_iprange.h:55
EIPRangeType type
Definition: ncbi_iprange.h:53
TNCBI_IPv6Addr a
Definition: ncbi_iprange.h:54
else result
Definition: token2.c:20
Modified on Mon Apr 22 04:03:02 2024 by modify_doxy.py rev. 669887