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