The attached patch is against Squid 3.5. Given Squid 3.5's status as a
stable release, this probably won't be integrated into the vanilla Squid
release, but I'm posting here in case anyone finds it useful, or if
someone wants to port it to Squid 4.
Squid currently supports ACLs and logformat specifiers which rely on the
EUI-48 (MAC address) for IPv4 traffic, and EUI-64 for IPv6 traffic.
For IPv4, Squid queries the ARP cache for the client's address. For
IPv6, Squid extracts the EUI-64 from site-local SLAAC addresses. This
isn't going to work for most clients, since site-local addresses are
rarely used in the real world. This patch brings the IPv6 functionality
in line with the IPv4 functionality by querying the neighbour table
using rtnetlink.
Open question: we could also pull the EUI-64 from a global scope SLAAC
address. Would it be trustworthy enough? Is it worth doing? Since
most clients now use privacy extensions it's probably not worthwhile.
Notes:
- We have to examine the entire neighbour table since (as far as I can
tell) the kernel doesn't allow querying a specific IP address. This
could be slow if there are a lot of neighbours.
- The IPv4 neighbour table can be retrieved in the same way, so there is
scope for unifying the IPv6 and IPv4 code.
- The neighbour table contains MAC addresses (i.e. EUI-48), not EUI-64
addresses. This patch converts the retrieved EUI-48 into an EUI-64 by
inserting 0xfffe into the middle.
- If the IPv4/IPv6 code is to be unified in the future, consider
converting everything to EUI-64 instead of making a distinction between
EUI-48 and EUI-64.
- This code is useful where users are being authenticated through a
mechanism other than HTTP proxy auth. For example, a client can
identify itself through a captive portal, but then use a combination of
IPv4 and numerous IPv6 addresses (due to privacy extensions) thereafter.
The client can be linked back to their portal login through their MAC,
irrespective of the IP address they are using for any given request.
- Obviously the client needs to be on the same layer 2 network as Squid,
so this doesn't help in situations where clients are behind a router.
--
- Steve Hill
Technical Director
Opendium Online Safety / Web Filtering http://www.opendium.com
Enquiries Support
--------- -------
[email protected] [email protected]
+44-1792-824568 +44-1792-825748
Index: squid/trunk/source/src/eui/Eui64.cc
===================================================================
--- squid/trunk/source/src/eui/Eui64.cc (revision 529)
+++ squid/trunk/source/src/eui/Eui64.cc (working copy)
@@ -12,6 +12,11 @@
#if USE_SQUID_EUI
+#if _SQUID_LINUX_
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
#include "compat/eui64_aton.h"
#include "Debug.h"
#include "eui/Eui64.h"
@@ -77,19 +82,95 @@
bool
Eui::Eui64::lookupNdp(const Ip::Address &c)
{
-#if 0 /* no actual lookup coded yet */
+ bool success = false;
- /* no OS yet supported for NDP protocol lookup */
- debugs(28, DBG_CRITICAL, "ERROR: ARP / MAC / EUI-* operations not supported on this operating system.");
+#if _SQUID_LINUX_
+ int rtnetlink_sock;
+ struct {
+ struct nlmsghdr hdr;
+ struct ndmsg ndm;
+ } req;
+ struct sockaddr_nl sa;
+ struct iovec iov;
+ struct msghdr msg;
+ char buf[16384];
+ ssize_t buff_fill;
+ struct nlmsghdr * nl_reply_hdr;
+ struct nlmsghdr * nl_reply_msg;
+ struct rtattr * rt_reply_attr;
+ size_t rt_reply_len;
+ bool found_ip = 0;
+ bool done = 0;
+ struct in6_addr ip;
+ void * mac_ptr;
- /*
- * Address was not found on any interface
- */
- debugs(28, 3, "id=" << (void*)this << ' ' << c << " NOT found");
-#endif /* 0 */
+ c.getInAddr(ip);
- clear();
- return false;
+ // Prepare rtnetlink request
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req.hdr.nlmsg_type = RTM_GETNEIGH;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req.hdr.nlmsg_seq = 0;
+ req.hdr.nlmsg_pid = 0;
+ req.ndm.ndm_family = AF_INET6;
+ req.ndm.ndm_state = 0;
+
+ iov.iov_base = &req;
+ iov.iov_len = req.hdr.nlmsg_len;
+
+ msg.msg_name = &sa;
+ msg.msg_namelen = sizeof(sa);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ // Send rtnetlink request
+ rtnetlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtnetlink_sock >= 0) {
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ if (sendmsg(rtnetlink_sock, &msg, 0) >= 0) {
+ // Loop through all the responses
+ while ((! done) && ((buff_fill = recv(rtnetlink_sock, buf, sizeof(buf), 0)) >= 0)) {
+ mac_ptr = NULL;
+ for (nl_reply_hdr = (struct nlmsghdr *) buf; (! done) && NLMSG_OK(nl_reply_hdr, buff_fill); nl_reply_hdr = NLMSG_NEXT(nl_reply_hdr, buff_fill)) {
+ if (nl_reply_hdr->nlmsg_type == NLMSG_DONE) done = 1;
+ else if (nl_reply_hdr->nlmsg_type == RTM_NEWNEIGH) {
+ nl_reply_msg = (struct nlmsghdr *) NLMSG_DATA(nl_reply_hdr);
+ rt_reply_len = RTM_PAYLOAD(nl_reply_hdr);
+
+ for (rt_reply_attr = RTM_RTA(nl_reply_msg); (! done) && RTA_OK(rt_reply_attr, rt_reply_len); rt_reply_attr = RTA_NEXT(rt_reply_attr, rt_reply_len)) {
+ if (rt_reply_attr->rta_type == NDA_DST) {
+ if (memcmp(ip.s6_addr, RTA_DATA(rt_reply_attr), 16)) {
+ // IP doesn't match - don't loop through the rest of the RTAs
+ break;
+ } else found_ip = 1;
+ } else if (rt_reply_attr->rta_type == NDA_LLADDR) mac_ptr = RTA_DATA(rt_reply_attr);
+
+ if (found_ip && mac_ptr) {
+ // We've found the right IP and its MAC address.
+ // Insert 0xfffe to turn the MAC (EUI48) into an EUI64.
+ memcpy(eui, mac_ptr, 3);
+ eui[3] = 0xff;
+ eui[4] = 0xfe;
+ memcpy(eui+5, ((char *) mac_ptr) + 3, 3);
+ done = 1;
+ success = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ close(rtnetlink_sock);
+ }
+ if (! success) debugs(28, 4, "id=" << (void*)this << " NDP Fail on " << c);
+#endif
+
+ if (! success) clear();
+ return success;
}
#endif /* USE_SQUID_EUI */
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev