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