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