Eui48.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 89 EUI-48 Lookup */
10 
11 #include "squid.h"
12 
13 #if USE_SQUID_EUI
14 
15 #include "Debug.h"
16 #include "eui/Eui48.h"
17 #include "globals.h"
18 #include "ip/Address.h"
19 
20 #include <cerrno>
21 
22 /* START Legacy includes pattern */
23 /* TODO: clean this up so we dont have per-OS requirements.
24  The files are checked for existence individually
25  and can be wrapped
26  */
27 
28 #if _SQUID_WINDOWS_
29 struct arpreq {
30 
31  Ip::Address arp_pa; /* protocol address */
32 
33  struct sockaddr arp_ha; /* hardware address */
34  int arp_flags; /* flags */
35 };
36 #if HAVE_IPHLPAPI_H
37 #include <iphlpapi.h>
38 #endif
39 #endif
40 
41 #if HAVE_SYS_PARAM_H
42 #include <sys/param.h>
43 #endif
44 #if HAVE_SYS_SOCKIO_H
45 /* required by Solaris */
46 #include <sys/sockio.h>
47 #endif
48 #if HAVE_SYS_SYSCTL_H
49 #include <sys/sysctl.h>
50 #endif
51 #if HAVE_NET_ROUTE_H
52 #include <net/route.h>
53 #endif
54 #if HAVE_NET_IF_H
55 #include <net/if.h>
56 #endif
57 #if HAVE_NET_IF_ARP_H
58 #include <net/if_arp.h>
59 #endif
60 #if HAVE_NET_IF_DL_H
61 #include <net/if_dl.h>
62 #endif
63 #if HAVE_NETINET_IF_ETHER_H
64 #include <netinet/if_ether.h>
65 #endif
66 #if HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
68 #endif
69 
70 /* ==== BEGIN EUI LOOKUP SUPPORT ============================================= */
71 
72 /*
73  * From: dale@server.ctam.bitmcnit.bryansk.su (Dale)
74  * To: wessels@nlanr.net
75  * Subject: Another Squid patch... :)
76  * Date: Thu, 04 Dec 1997 19:55:01 +0300
77  * ============================================================================
78  *
79  * Working on setting up a proper firewall for a network containing some
80  * Win'95 computers at our Univ, I've discovered that some smart students
81  * avoid the restrictions easily just changing their IP addresses in Win'95
82  * Contol Panel... It has been getting boring, so I took Squid-1.1.18
83  * sources and added a new acl type for hard-wired access control:
84  *
85  * acl <name> arp <Ethernet address> ...
86  *
87  * For example,
88  *
89  * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
90  *
91  * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
92  * Original (BSD-specific) code no longer works.
93  * Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
94  */
95 
96 bool
97 Eui::Eui48::decode(const char *asc)
98 {
99  int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
100 
101  if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
102  debugs(28, DBG_CRITICAL, "Decode EUI-48: Invalid ethernet address '" << asc << "'");
103  clear();
104  return false; /* This is not valid address */
105  }
106 
107  eui[0] = (u_char) a1;
108  eui[1] = (u_char) a2;
109  eui[2] = (u_char) a3;
110  eui[3] = (u_char) a4;
111  eui[4] = (u_char) a5;
112  eui[5] = (u_char) a6;
113 
114  debugs(28, 4, "id=" << (void*)this << " decoded " << asc);
115  return true;
116 }
117 
118 bool
119 Eui::Eui48::encode(char *buf, const int len) const
120 {
121  if (len < SZ_EUI48_BUF)
122  return false;
123 
124  snprintf(buf, len, "%02x:%02x:%02x:%02x:%02x:%02x",
125  eui[0] & 0xff, eui[1] & 0xff,
126  eui[2] & 0xff, eui[3] & 0xff,
127  eui[4] & 0xff, eui[5] & 0xff);
128 
129  debugs(28, 4, "id=" << (void*)this << " encoded " << buf);
130  return true;
131 }
132 
133 // return binary representation of the EUI
134 bool
136 {
137  Ip::Address ipAddr = c;
138  ipAddr.port(0);
139 
140 #if _SQUID_LINUX_
141 
142  unsigned char ifbuffer[sizeof(struct ifreq) * 64];
143  struct ifconf ifc;
144 
145  struct ifreq *ifr;
146  int offset;
147 
148  /* IPv6 builds do not provide the first http_port as an IPv4 socket for ARP */
149  int tmpSocket = socket(AF_INET,SOCK_STREAM,0);
150  if (tmpSocket < 0) {
151  int xerrno = errno;
152  debugs(28, DBG_IMPORTANT, "Attempt to open socket for EUI retrieval failed: " << xstrerr(xerrno));
153  clear();
154  return false;
155  }
156 
157  /*
158  * The linux kernel 2.2 maintains per interface ARP caches and
159  * thus requires an interface name when doing ARP queries.
160  *
161  * The older 2.0 kernels appear to use a unified ARP cache,
162  * and require an empty interface name
163  *
164  * To support both, we attempt the lookup with a blank interface
165  * name first. If that does not succeed, the try each interface
166  * in turn
167  */
168 
169  /*
170  * Set up structures for ARP lookup with blank interface name
171  */
172  struct arpreq arpReq;
173  memset(&arpReq, '\0', sizeof(arpReq));
174 
175  struct sockaddr_in *sa = (struct sockaddr_in*)&arpReq.arp_pa;
176  ipAddr.getSockAddr(*sa);
177 
178  /* Query ARP table */
179  debugs(28, 4, "id=" << (void*)this << " query ARP table");
180  if (ioctl(tmpSocket, SIOCGARP, &arpReq) != -1) {
181  /* Skip non-ethernet interfaces */
182  close(tmpSocket);
183 
184  if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
185  debugs(28, 4, "id=" << (void*)this << " ... not an Ethernet interface: " << arpReq.arp_ha.sa_data);
186  clear();
187  return false;
188  }
189 
190  debugs(28, 4, "id=" << (void*)this << " got address "<< std::setfill('0') << std::hex <<
191  std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
192  std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
193  std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
194  std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
195  std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
196  std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
197 
198  set(arpReq.arp_ha.sa_data, 6);
199  return true;
200  }
201 
202  /* lookup list of interface names */
203  ifc.ifc_len = sizeof(ifbuffer);
204 
205  ifc.ifc_buf = (char *)ifbuffer;
206 
207  if (ioctl(tmpSocket, SIOCGIFCONF, &ifc) < 0) {
208  int xerrno = errno;
209  debugs(28, DBG_IMPORTANT, "Attempt to retrieve interface list failed: " << xstrerr(xerrno));
210  clear();
211  close(tmpSocket);
212  return false;
213  }
214 
215  if (ifc.ifc_len > (int)sizeof(ifbuffer)) {
216  debugs(28, DBG_IMPORTANT, "Interface list too long - " << ifc.ifc_len);
217  clear();
218  close(tmpSocket);
219  return false;
220  }
221 
222  /* Attempt ARP lookup on each interface */
223  offset = 0;
224  debugs(28, 4, "id=" << (void*)this << " query ARP on each interface (" << ifc.ifc_len << " found)");
225  while (offset < ifc.ifc_len) {
226 
227  ifr = (struct ifreq *) (ifbuffer + offset);
228  offset += sizeof(*ifr);
229 
230  debugs(28, 4, "id=" << (void*)this << " found interface " << ifr->ifr_name);
231 
232  /* Skip loopback and aliased interfaces */
233  if (!strncmp(ifr->ifr_name, "lo", 2))
234  continue;
235 
236  if (strchr(ifr->ifr_name, ':'))
237  continue;
238 
239  debugs(28, 4, "id=" << (void*)this << " looking up ARP address for " << ipAddr << " on " << ifr->ifr_name);
240 
241  /* Set up structures for ARP lookup */
242 
243  memset(&arpReq, '\0', sizeof(arpReq));
244 
245  sa = (sockaddr_in*)&arpReq.arp_pa;
246  ipAddr.getSockAddr(*sa);
247 
248  strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
249 
250  arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
251 
252  /* Query ARP table */
253  if (-1 == ioctl(tmpSocket, SIOCGARP, &arpReq)) {
254  int xerrno = errno;
255  // Query failed. Do not log failed lookups or "device not supported"
256  if (ENXIO != xerrno && ENODEV != xerrno)
257  debugs(28, DBG_IMPORTANT, "ARP query " << ipAddr << " failed: " << ifr->ifr_name << ": " << xstrerr(xerrno));
258 
259  continue;
260  }
261 
262  /* Skip non-ethernet interfaces */
263  if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
264  debugs(28, 4, "id=" << (void*)this << "... not an Ethernet interface");
265  continue;
266  }
267 
268  debugs(28, 4, "id=" << (void*)this << " got address "<< std::setfill('0') << std::hex <<
269  std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
270  std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
271  std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
272  std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
273  std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
274  std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff) << " on "<<
275  std::setfill(' ') << ifr->ifr_name);
276 
277  set(arpReq.arp_ha.sa_data, 6);
278 
279  /*
280  * Should we stop looking here? Can the same IP address
281  * exist on multiple interfaces?
282  */
283 
284  /* AYJ: 2009-10-06: for now we have to. We can only store one EUI at a time. */
285  close(tmpSocket);
286  return true;
287  }
288 
289  close(tmpSocket);
290 
291 #elif _SQUID_SOLARIS_
292 
293  /* IPv6 builds do not provide the first http_port as an IPv4 socket for ARP */
294  int tmpSocket = socket(AF_INET,SOCK_STREAM,0);
295  if (tmpSocket < 0) {
296  int xerrno = errno;
297  debugs(28, DBG_IMPORTANT, "Attempt to open socket for EUI retrieval failed: " << xstrerr(xerrno));
298  clear();
299  return false;
300  }
301 
302  /* Set up structures for ARP lookup with blank interface name */
303  struct arpreq arpReq;
304  memset(&arpReq, '\0', sizeof(arpReq));
305 
306  struct sockaddr_in *sa = (struct sockaddr_in*)&arpReq.arp_pa;
307  ipAddr.getSockAddr(*sa);
308 
309  /* Query ARP table */
310  if (ioctl(tmpSocket, SIOCGARP, &arpReq) != -1) {
311  /*
312  * Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
313  * it returns 00:00:00:00:00:00 for non-ethernet media
314  */
315  close(tmpSocket);
316 
317  if (arpReq.arp_ha.sa_data[0] == 0 &&
318  arpReq.arp_ha.sa_data[1] == 0 &&
319  arpReq.arp_ha.sa_data[2] == 0 &&
320  arpReq.arp_ha.sa_data[3] == 0 &&
321  arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
322  clear();
323  return false;
324  }
325 
326  debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
327  std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
328  std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
329  std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
330  std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
331  std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
332  std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
333 
334  set(arpReq.arp_ha.sa_data, 6);
335  return true;
336  } else {
337  close(tmpSocket);
338  }
339 
340 #elif _SQUID_FREEBSD_ || _SQUID_NETBSD_ || _SQUID_OPENBSD_ || _SQUID_DRAGONFLY_ || _SQUID_KFREEBSD_
341 
342  int mib[6];
343 
344  size_t needed;
345 
346  char *lim, *buf, *next;
347 
348  struct rt_msghdr *rtm;
349 
350  struct sockaddr_inarp *sin;
351 
352  struct sockaddr_dl *sdl;
353 
354  /*
355  * Set up structures for ARP lookup with blank interface name
356  */
357  struct arpreq arpReq;
358  memset(&arpReq, '\0', sizeof(arpReq));
359 
360  struct sockaddr_in *sa = (struct sockaddr_in*)&arpReq.arp_pa;
361  ipAddr.getSockAddr(*sa);
362 
363  /* Query ARP table */
364  mib[0] = CTL_NET;
365 
366  mib[1] = PF_ROUTE;
367 
368  mib[2] = 0;
369 
370  mib[3] = AF_INET;
371 
372  mib[4] = NET_RT_FLAGS;
373 
374 #if defined(RTF_LLDATA)
375  mib[5] = RTF_LLDATA;
376 #else
377  mib[5] = RTF_LLINFO;
378 #endif
379 
380  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
381  debugs(28, DBG_CRITICAL, "Can't estimate ARP table size!");
382  clear();
383  return false;
384  }
385 
386  if ((buf = (char *)xmalloc(needed)) == NULL) {
387  debugs(28, DBG_CRITICAL, "Can't allocate temporary ARP table!");
388  clear();
389  return false;
390  }
391 
392  if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
393  debugs(28, DBG_CRITICAL, "Can't retrieve ARP table!");
394  xfree(buf);
395  clear();
396  return false;
397  }
398 
399  lim = buf + needed;
400 
401  for (next = buf; next < lim; next += rtm->rtm_msglen) {
402 
403  rtm = (struct rt_msghdr *) next;
404 
405  sin = (struct sockaddr_inarp *) (rtm + 1);
406  /*sdl = (struct sockaddr_dl *) (sin + 1); */
407 
408 #define ROUNDUP(a) \
409  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
410 
411  sdl = (struct sockaddr_dl *)((char *) sin + ROUNDUP(sin->sin_len));
412 
413  if (ipAddr == sin->sin_addr) {
414  if (sdl->sdl_alen) {
415 
416  arpReq.arp_ha.sa_len = sizeof(struct sockaddr);
417  arpReq.arp_ha.sa_family = AF_UNSPEC;
418  memcpy(arpReq.arp_ha.sa_data, LLADDR(sdl), sdl->sdl_alen);
419  }
420  }
421  }
422 
423  xfree(buf);
424 
425  if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
426  arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
427  arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
428  clear();
429  return false;
430  }
431 
432  debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
433  std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
434  std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
435  std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
436  std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
437  std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
438  std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
439 
440  set(arpReq.arp_ha.sa_data, 6);
441  return true;
442 
443 #elif _SQUID_WINDOWS_
444 
445  DWORD dwNetTable = 0;
446 
447  DWORD ipNetTableLen = 0;
448 
449  PMIB_IPNETTABLE NetTable = NULL;
450 
451  DWORD i;
452 
453  struct arpreq arpReq;
454  memset(&arpReq, '\0', sizeof(arpReq));
455 
456  /* Get size of Windows ARP table */
457  if (GetIpNetTable(NetTable, &ipNetTableLen, FALSE) != ERROR_INSUFFICIENT_BUFFER) {
458  debugs(28, DBG_CRITICAL, "Can't estimate ARP table size!");
459  clear();
460  return false;
461  }
462 
463  /* Allocate space for ARP table and assign pointers */
464  if ((NetTable = (PMIB_IPNETTABLE)xmalloc(ipNetTableLen)) == NULL) {
465  debugs(28, DBG_CRITICAL, "Can't allocate temporary ARP table!");
466  clear();
467  return false;
468  }
469 
470  /* Get actual ARP table */
471  if ((dwNetTable = GetIpNetTable(NetTable, &ipNetTableLen, FALSE)) != NO_ERROR) {
472  debugs(28, DBG_CRITICAL, "Can't retrieve ARP table!");
473  xfree(NetTable);
474  clear();
475  return false;
476  }
477 
478  /* Find MAC address from net table */
479  for (i = 0 ; i < NetTable->dwNumEntries ; ++i) {
480  in_addr a;
481  a.s_addr = NetTable->table[i].dwAddr;
482  if (c == a && (NetTable->table[i].dwType > 2)) {
483  arpReq.arp_ha.sa_family = AF_UNSPEC;
484  memcpy(arpReq.arp_ha.sa_data, NetTable->table[i].bPhysAddr, NetTable->table[i].dwPhysAddrLen);
485  }
486  }
487 
488  xfree(NetTable);
489 
490  if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
491  arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
492  arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
493  clear();
494  return false;
495  }
496 
497  debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
498  std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
499  std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
500  std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
501  std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
502  std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
503  std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
504 
505  set(arpReq.arp_ha.sa_data, 6);
506  return true;
507 
508 #else
509 
510  debugs(28, DBG_CRITICAL, "ERROR: ARP / MAC / EUI-* operations not supported on this operating system.");
511 
512 #endif
513  /*
514  * Address was not found on any interface
515  */
516  debugs(28, 3, "id=" << (void*)this << ' ' << ipAddr << " NOT found");
517 
518  clear();
519  return false;
520 }
521 
522 /* ==== END EUI LOOKUP SUPPORT =============================================== */
523 
524 #endif /* USE_SQUID_EUI */
525 
bool decode(const char *asc)
Definition: Eui48.cc:97
#define SZ_EUI48_BUF
Definition: Eui48.h:15
int i
Definition: membanger.c:49
#define DBG_CRITICAL
Definition: Debug.h:44
unsigned char eui[SZ_EUI48_BUF]
Definition: Eui48.h:73
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool lookup(const Ip::Address &c)
Definition: Eui48.cc:135
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void const char * buf
Definition: stub_helper.cc:16
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition: Address.cc:942
unsigned short port() const
Definition: Address.cc:786
typedef DWORD
Definition: WinSvc.cc:73
#define FALSE
Definition: std-includes.h:56
#define xmalloc
int a
Definition: membanger.c:50
#define xfree
bool encode(char *buf, const int len) const
Definition: Eui48.cc:119
#define NULL
Definition: types.h:166
void clear()
Definition: Eui48.h:46

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors