Eui48.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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/Stream.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 do not have per-OS requirements.
24 The files are checked for existence individually
25 and can be wrapped
26 */
27
28#if _SQUID_WINDOWS_
29struct 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 * Control 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
96bool
97Eui::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, "ERROR: 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
118bool
119Eui::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
134bool
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, "ERROR: 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, "ERROR: 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, "ERROR: 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, "ERROR: 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, nullptr, &needed, nullptr, 0) < 0) {
381 debugs(28, DBG_CRITICAL, "ERROR: Cannot estimate ARP table size!");
382 clear();
383 return false;
384 }
385
386 if ((buf = (char *)xmalloc(needed)) == NULL) {
387 debugs(28, DBG_CRITICAL, "ERROR: Cannot allocate temporary ARP table!");
388 clear();
389 return false;
390 }
391
392 if (sysctl(mib, 6, buf, &needed, nullptr, 0) < 0) {
393 debugs(28, DBG_CRITICAL, "ERROR: Cannot 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 = nullptr;
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, "ERROR: Cannot 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, "ERROR: Cannot 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, "ERROR: Cannot 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
#define SZ_EUI48_BUF
Definition: Eui48.h:15
unsigned char eui[SZ_EUI48_BUF]
Definition: Eui48.h:71
void clear()
Definition: Eui48.h:44
bool lookup(const Ip::Address &c)
Definition: Eui48.cc:135
bool encode(char *buf, const int len) const
Definition: Eui48.cc:119
bool decode(const char *asc)
Definition: Eui48.cc:97
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition: Address.cc:924
unsigned short port() const
Definition: Address.cc:778
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
#define xfree
#define xmalloc
#define FALSE
Definition: std-includes.h:56
#define NULL
Definition: types.h:145
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors