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

Go to the SVN repository for this file.

1 /* $Id: ncbi_localnet.c 99864 2023-05-17 19:32:48Z saprykin $
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  * Get IP address of CGI client and determine the IP locality
30  *
31  */
32 
33 #include "../ncbi_ansi_ext.h"
34 #include "../ncbi_priv.h"
35 #include <connect/ncbi_socket.h>
37 #include <stdlib.h>
38 #if defined(NCBI_OS_UNIX)
39 # include <sys/types.h>
40 # include <netinet/in.h>
41 #endif /*NCBI_OS_UNIX*/
42 
43 
44 #ifndef INADDR_LOOPBACK
45 # define INADDR_LOOPBACK 0x7F000001
46 #endif /*!INADDR_LOOPBACK*/
47 
48 #ifdef SizeOf
49 # undef SizeOf
50 #endif /*SizeOf*/
51 #define SizeOf(a) (sizeof(a) / sizeof((a)[0]))
52 
53 #if defined(_DEBUG) && !defined(NDEBUG)
54 /*# define NCBI_LOCALNET_DEBUG 1*/
55 #endif /*_DEBUG && !NDEBUG*/
56 
57 
58 #ifdef __GNUC__
59 inline
60 #endif /*__GNUC__*/
61 static int/*bool*/ x_IsPrivateIP(unsigned int addr)
62 {
63  return
64 #if defined(IN_LOOPBACK)
65  IN_LOOPBACK(addr) ||
66 #elif defined(IN_LOOPBACKNET) && \
67  defined(IN_CLASSA) && defined(IN_CLASSA_NET) && defined(IN_CLASSA_NSHIFT)
68  (IN_CLASSA(addr)
69  && (addr & IN_CLASSA_NET) == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) ||
70 #else
71  !((addr & 0xFF000000) ^ (INADDR_LOOPBACK-1)) || /* 127/8 */
72 #endif /*IN_LOOPBACK*/
73  /* private [non-routable] IP ranges, according to RFC1918 */
74  !((addr & 0xFF000000) ^ 0x0A000000) || /* 10/8 */
75  !((addr & 0xFFF00000) ^ 0xAC100000) || /* 172.16.0.0-172.31.255.255 */
76  !((addr & 0xFFFF0000) ^ 0xC0A80000) || /* 192.168/16 */
77  /* multicast IP range is also excluded: 224.0.0.0-239.255.255.255 */
78 #if defined(IN_MULTICAST)
79  IN_MULTICAST(addr)
80 #elif defined(IN_CLASSD)
81  IN_CLASSD(addr)
82 #else
83  !((addr & 0xF0000000) ^ 0xE0000000)
84 #endif /*IN_MULTICAST*/
85  ;
86 }
87 
88 
89 extern int/*bool*/ NcbiIsPrivateIP(unsigned int ip)
90 {
92 }
93 
94 
95 #ifdef __GNUC__
96 inline
97 #endif /*__GNUC__*/
98 static int/*bool*/ x_IsAPIPA(unsigned int addr)
99 {
100  return !((addr & 0xFFFF0000) ^ 0xA9FE0000); /* 169.254/16 per IANA */
101 }
102 
103 
104 extern int/*bool*/ NcbiIsAPIPA(unsigned int ip)
105 {
107 }
108 
109 
110 #ifdef __GNUC__
111 inline
112 #endif /*__GNUC__*/
113 static int/*bool*/ s_IsPrivateIP(unsigned int ip)
114 {
115  unsigned int addr = SOCK_NetToHostLong(ip);
116  return x_IsPrivateIP(addr) || x_IsAPIPA(addr);
117 }
118 
119 
120 /* NB: "str" is either NULL or non-empty */
122  const char* str)
123 {
124  const char* end = NcbiStringToAddr(addr, str, 0);
125  assert(!str || *str);
126  if (str /*&& *str*/ && (!end || *end))
128  return addr;
129 }
130 
131 
132 /* NB: returns either NULL or non-empty value for the "name" */
133 static const char* s_SearchTrackingEnv(const char* name,
134  const char* const* tracking_env)
135 {
136  const char* result;
137 
138  if (!tracking_env) {
139  // CORE_LOCK_READ;
140  result = getenv(name);
141  // CORE_UNLOCK;
142 #ifdef NCBI_LOCALNET_DEBUG
143  CORE_LOGF(eLOG_Trace, ("Getenv('%s') = %s%s%s", name,
144  result ? "\"" : "",
145  result ? result : "NULL",
146  result ? "\"" : ""));
147 #endif /*NCBI_LOCALNET_DEBUG*/
148  } else {
149  size_t len = strlen(name);
150  const char* const* str;
151  result = 0;
152  for (str = tracking_env; *str; ++str) {
153  if (strncasecmp(*str, name, len) == 0 && (*str)[len] == '=') {
154  result = &(*str)[++len];
155  break;
156  }
157  }
158 #ifdef NCBI_LOCALNET_DEBUG
159  CORE_LOGF(eLOG_Trace, ("Tracking '%s' = %s%s%s", name,
160  result ? "\"" : "",
161  result ? result : "NULL",
162  result ? "\"" : ""));
163 #endif /*NCBI_LOCALNET_DEBUG*/
164  }
165  return result && *(result += strspn(result, " \t")) ? result : 0;
166 }
167 
168 
169 static const char* s_SearchForwardedFor(TNCBI_IPv6Addr* addr,
170  const char* const* tracking_env)
171 {
172  const char* f = s_SearchTrackingEnv("HTTP_X_FORWARDED_FOR", tracking_env);
173  TNCBI_IPv6Addr xaddr;
174  int/*bool*/ external;
175  char *p, *q, *r, *s;
176 
177  if (!f)
178  return 0;
179  r = 0;
180  external = !(s = strdup(f)) ? 1/*T*/ : 0/*F*/;
181  for (p = s; p && *p; p = q + strspn(q, ", \t")) {
182  int/*bool*/ private_ip;
183  q = p + strcspn(p, ", \t");
184  if (*q)
185  *q++ = '\0';
186  if (!*p || NcbiIsEmptyIPv6(x_StringToAddr(&xaddr, p))) {
187 #ifdef NCBI_LOCALNET_DEBUG
188  CORE_LOG(eLOG_Trace, "Forcing external");
189 #endif /*NCBI_LOCALNET_DEBUG*/
190  external = 1/*true*/;
191  r = 0/*error*/;
192  } else if (!(private_ip = s_IsPrivateIP(NcbiIPv6ToIPv4(&xaddr, 0)))
193  && !NcbiIsLocalIPEx(&xaddr, 0)) {
194  r = p;
195  *addr = xaddr;
196  break;
197  } else if (!external
198  && (!r
199  || (!private_ip
200  && s_IsPrivateIP(NcbiIPv6ToIPv4(addr, 0))))) {
201  r = p;
202  *addr = xaddr;
203  }
204  }
205  if (r) {
206  memmove(s, r, strlen(r) + 1);
207  assert(*s && !NcbiIsEmptyIPv6(addr));
208  return s;
209  }
210  if (s)
211  free(s);
212  memset(addr, 0, sizeof(*addr));
213  return external ? "" : 0;
214 }
215 
216 
217 /* The environment checked here must be in correspondence with the tracking
218  * environment created by CTrackingEnvHolder::CTrackingEnvHolder()
219  * (header: <cgi/ncbicgi.hpp>, source: cgi/ncbicgi.cpp, library: xcgi)
220  */
222  char* buf,
223  size_t buf_size,
224  const char* const* tracking_env)
225 {
226  struct {
227  const char* host;
228  TNCBI_IPv6Addr addr;
229  } probe[4];
230  int/*bool*/ external = 0/*false*/;
231  const char* host = 0;
232  TNCBI_IPv6Addr addr;
233  size_t i;
234 
235  memset(&addr, 0, sizeof(addr));
236  memset(probe, 0, sizeof(probe));
237  for (i = 0; i < SizeOf(probe); ++i) {
238  int/*bool*/ bad_addr = 1/*true*/;
239  switch (i) {
240  case 0:
241  probe[i].host = s_SearchTrackingEnv("HTTP_CAF_PROXIED_HOST",
242  tracking_env);
243  break;
244  case 1:
245  /* NB: sets probe[i].addr */
246  probe[i].host = s_SearchForwardedFor(&probe[i].addr,
247  tracking_env);
248  bad_addr = 0/*false*/;
249  break;
250  case 2:
251  probe[i].host = s_SearchTrackingEnv("PROXIED_IP",
252  tracking_env);
253  break;
254  case 3:
255  probe[i].host = s_SearchTrackingEnv("HTTP_X_FWD_IP_ADDR",
256  tracking_env);
257  break;
258  default:
259  assert(0);
260  continue;
261  }
262  if (!probe[i].host)
263  continue;
264  assert(*probe[i].host || !bad_addr/*forwarded_for*/);
265  if ( bad_addr)
266  x_StringToAddr(&probe[i].addr, probe[i].host);
267  bad_addr = NcbiIsEmptyIPv6(&probe[i].addr);
268  if (!bad_addr && NcbiIsLocalIPEx(&probe[i].addr, 0))
269  continue;
270 #ifdef NCBI_LOCALNET_DEBUG
271  CORE_LOG(eLOG_Trace, "External on");
272 #endif /*NCBI_LOCALNET_DEBUG*/
273  external = 1/*true*/;
274  if (bad_addr/*unresolvable*/
275  || (bad_addr = !s_IsPrivateIP(NcbiIPv6ToIPv4(&probe[i].addr, 0)))
276  || !host/*1st occurrence*/) {
277  assert(probe[i].host);
278  host = probe[i].host;
279  addr = probe[i].addr;
280  if (bad_addr)
281  break;
282  }
283  }
284  if (!external) {
285  assert(NcbiIsEmptyIPv6(&addr));
286  for (i = flag == eCgiClientIP_TryLeast ? 1 : 0;
287  i <= (flag == eCgiClientIP_TryAll ? 8 : 7); ++i) {
288  switch (i) {
289  case 0:
290  host = s_SearchTrackingEnv("HTTP_CLIENT_HOST",
291  tracking_env);
292  break;
293  case 1:
294  case 2:
295  case 3:
296  case 4:
297  host = probe[i - 1].host;
298  break;
299  case 5:
300  host = s_SearchTrackingEnv("HTTP_X_REAL_IP",
301  tracking_env);
302  break;
303  case 6:
304  host = s_SearchTrackingEnv("REMOTE_HOST",
305  tracking_env);
306  if (host) {
307  /* consider as a special case per semantics in RFC-3875 */
308  x_StringToAddr(&addr, s_SearchTrackingEnv("REMOTE_ADDR",
309  tracking_env));
310  }
311  break;
312  case 7:
313  host = s_SearchTrackingEnv("REMOTE_ADDR",
314  tracking_env);
315  break;
316  case 8:
317  host = s_SearchTrackingEnv("NI_CLIENT_IPADDR",
318  tracking_env);
319  break;
320  default:
321  assert(0);
322  continue;
323  }
324  if (host) {
325  assert(*host);
326  if (1 <= i && i <= 4)
327  addr = probe[i - 1].addr;
328  else if (i != 6/*REMOTE_HOST*/ || NcbiIsEmptyIPv6(&addr))
329  x_StringToAddr(&addr, host);
330  break;
331  }
332  }
333  }
334  if (buf && buf_size) {
335  if (host && (i = strlen(host)) < buf_size)
336  memcpy(buf, host, ++i);
337  else
338  *buf = '\0';
339  }
340  if (probe[1].host && *probe[1].host)
341  free((void*) probe[1].host /*forwarded_for*/);
342  return addr;
343 }
344 
345 
347  const char* const* tracking_env)
348 {
349  return NcbiGetCgiClientIPv6Ex(flag, 0, 0, tracking_env);
350 }
351 
352 
353 extern unsigned int NcbiGetCgiClientIPEx(ECgiClientIP flag,
354  char* buf,
355  size_t buf_size,
356  const char* const* tracking_env)
357 {
359  addr = NcbiGetCgiClientIPv6Ex(flag, buf, buf_size, tracking_env);
360  return NcbiIPv6ToIPv4(&addr, 0);
361 }
362 
363 
364 extern unsigned int NcbiGetCgiClientIP(ECgiClientIP flag,
365  const char* const* tracking_env)
366 {
367  return NcbiGetCgiClientIPEx(flag, 0, 0, tracking_env);
368 }
369 
370 
371 extern int/*bool*/ NcbiIsLocalCgiClient(const char* const* tracking_env)
372 {
373  TNCBI_IPv6Addr addr;
374  if (s_SearchTrackingEnv("HTTP_CAF_EXTERNAL", tracking_env))
375  return 0/*false*/;
376  if (s_SearchTrackingEnv("HTTP_NCBI_EXTERNAL", tracking_env))
377  return 0/*false*/;
378  addr = NcbiGetCgiClientIPv6(eCgiClientIP_TryAll, tracking_env);
379  return NcbiIsLocalIPEx(&addr, 0);
380 }
static const char ip[]
Definition: des.c:75
static const char * str(char *buf, int n)
Definition: stats.c:84
#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
@ eLOG_Trace
Definition: ncbi_core.h:293
char * buf
int i
int len
#define strdup
Definition: ncbi_ansi_ext.h:70
#define strncasecmp
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
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
const char * NcbiStringToAddr(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:688
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
#define NcbiIsLocalIPEx
static const char * s_SearchTrackingEnv(const char *name, const char *const *tracking_env)
static const char * s_SearchForwardedFor(TNCBI_IPv6Addr *addr, const char *const *tracking_env)
TNCBI_IPv6Addr NcbiGetCgiClientIPv6Ex(ECgiClientIP flag, char *buf, size_t buf_size, const char *const *tracking_env)
Same as NcbiGetCgiClientIPEx but IPv6-aware.
int NcbiIsLocalCgiClient(const char *const *tracking_env)
Return non-zero (true) if called from within a CGI that was invoked by an NCBI local client; zero oth...
int NcbiIsAPIPA(unsigned int ip)
Return non-zero (true) if the IP address (in network byte order) provided as an agrument,...
unsigned int NcbiGetCgiClientIPEx(ECgiClientIP flag, char *buf, size_t buf_size, const char *const *tracking_env)
unsigned int NcbiGetCgiClientIP(ECgiClientIP flag, const char *const *tracking_env)
Same as NcbiGetCgiClientIPEx(., NULL, 0, .)
TNCBI_IPv6Addr NcbiGetCgiClientIPv6(ECgiClientIP flag, const char *const *tracking_env)
Same as NcbiGetCgiClientIPv6Ex(., NULL, 0, .)
static int s_IsPrivateIP(unsigned int ip)
static int x_IsPrivateIP(unsigned int addr)
Definition: ncbi_localnet.c:61
static int x_IsAPIPA(unsigned int addr)
Definition: ncbi_localnet.c:98
int NcbiIsPrivateIP(unsigned int ip)
Return non-zero (true) if the IP address (in network byte order) provided as an agrument,...
Definition: ncbi_localnet.c:89
#define INADDR_LOOPBACK
Definition: ncbi_localnet.c:45
static const TNCBI_IPv6Addr * x_StringToAddr(TNCBI_IPv6Addr *addr, const char *str)
#define SizeOf(a)
Definition: ncbi_localnet.c:51
ECgiClientIP
Return IP address (in network byte order) of the CGI client, and optionally store the client hostname...
@ eCgiClientIP_TryLeast
Try to detect caller's IP only,not origin.
@ eCgiClientIP_TryAll
Try all env.vars (NI_CLIENT_IPADDR incl.)
#define CORE_LOGF(level, fmt_args)
Definition: ncbi_priv.h:158
#define CORE_LOG(level, message)
Definition: ncbi_priv.h:154
#define IN_LOOPBACKNET
Definition: ncbi_socket.c:145
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
#define memmove(a, b, c)
#define assert(x)
Definition: srv_diag.hpp:58
else result
Definition: token2.c:20
void free(voidpf ptr)
Modified on Wed Jul 24 17:17:50 2024 by modify_doxy.py rev. 669887