on network connections. Note that they are supported only on some
systems.
-@defun network-interface-list
-This function returns a list describing the network interfaces
-of the machine you are using. The value is an alist whose
-elements have the form @code{(@var{name} . @var{address})}.
-@var{address} has the same form as the @var{local-address}
-and @var{remote-address} arguments to @code{make-network-process}.
+@defun network-interface-list &optional full family
+This function returns a list describing the network interfaces of the
+machine you are using. The value is an alist whose elements have the
+form @code{(@var{ifname} . @var{address})}. @var{ifname} is a string
+naming the interface, @var{address} has the same form as the
+@var{local-address} and @var{remote-address} arguments to
+@code{make-network-process}, i.e. a vector of integers. By default
+both IPv4 and IPv6 addresses are returned if possible.
+
+Optional argument @var{full} non-@code{nil} means to instead return a
+list of one or more elements of the form @w{@code{(@var{ifname}
+@var{addr} @var{bcast} @var{netmask})}}. @var{ifname} is a non-unique
+string naming the interface. @var{addr}, @var{bcast}, and
+@var{netmask} are vectors of integers detailing the IP address,
+broadcast address, and network mask.
+
+Optional argument @var{family} specified as symbol @code{ipv4} or
+@code{ipv6} restricts the returned information to IPv4 and IPv6
+addresses respectively, independently of the value of @var{full}.
+Speficying @code{ipv6} when IPv6 support is not available will result
+in an error being signaled.
+
+Some examples:
+
+@example
+(network-interface-list) @result{}
+(("vmnet8" .
+ [172 16 76 1 0])
+ ("vmnet1" .
+ [172 16 206 1 0])
+ ("lo0" .
+ [65152 0 0 0 0 0 0 1 0])
+ ("lo0" .
+ [0 0 0 0 0 0 0 1 0])
+ ("lo0" .
+ [127 0 0 1 0]))
+@end example
+
+@example
+(network-interface-list t) @result{}
+(("vmnet8"
+ [172 16 76 1 0]
+ [172 16 76 255 0]
+ [255 255 255 0 0])
+ ("vmnet1"
+ [172 16 206 1 0]
+ [172 16 206 255 0]
+ [255 255 255 0 0])
+ ("lo0"
+ [65152 0 0 0 0 0 0 1 0]
+ [65152 0 0 0 65535 65535 65535 65535 0]
+ [65535 65535 65535 65535 0 0 0 0 0])
+ ("lo0"
+ [0 0 0 0 0 0 0 1 0]
+ [0 0 0 0 0 0 0 1 0]
+ [65535 65535 65535 65535 65535 65535 65535 65535 0])
+ ("lo0"
+ [127 0 0 1 0]
+ [127 255 255 255 0]
+ [255 0 0 0 0]))
+@end example
@end defun
@defun network-interface-info ifname
@item flags
The current flags of the interface.
@end table
+
+Note that this function returns only IPv4 information.
@end defun
@defun format-network-address address &optional omit-port
** New function 'network-lookup-address-info'.
This does IPv4 and/or IPv6 address lookups on hostnames.
++++
+** 'network-interface-list' can now return IPv4 and IPv6 addresses.
+IPv4 and IPv6 addresses are now returned by default if available,
+optionally including netmask/broadcast address information.
+
---
** Control of the threshold for using the 'distant-foreground' color.
The threshold for color distance below which the 'distant-foreground'
of the local interfaces, this function returns nil. Non-nil
otherwise."
(let ((addresses (network-lookup-address-info host))
- (network-interface-list (network-interface-list))
+ (network-interface-list (network-interface-list t))
(off-net t))
(when
(or (and (functionp nsm-trust-local-network)
(funcall nsm-trust-local-network))
nsm-trust-local-network)
(mapc
- (lambda (address)
+ (lambda (ip)
(mapc
- (lambda (iface)
- (let ((info (network-interface-info (car iface))))
+ (lambda (info)
+ (let ((local-ip (nth 1 info))
+ (mask (nth 2 info)))
(when
- (nsm-network-same-subnet (substring (car info) 0 -1)
- (substring (car (cddr info)) 0 -1)
- (substring address 0 -1))
+ (nsm-network-same-subnet (substring local-ip 0 -1)
+ (substring mask 0 -1)
+ (substring ip 0 -1))
(setq off-net nil))))
network-interface-list))
addresses))
#define connect sys_connect
#define htons sys_htons
#define ntohs sys_ntohs
+#define htonl sys_htonl
+#define ntohl sys_ntohl
#define inet_addr sys_inet_addr
#define gethostname sys_gethostname
#define gethostbyname sys_gethostbyname
int sys_connect (int s, const struct sockaddr *addr, int namelen);
u_short sys_htons (u_short hostshort);
u_short sys_ntohs (u_short netshort);
+u_long sys_htonl (u_long hostlong);
+u_long sys_ntohl (u_long netlong);
unsigned long sys_inet_addr (const char * cp);
int sys_gethostname (char * name, int namelen);
struct hostent * sys_gethostbyname (const char * name);
}
\f
-#ifdef HAVE_NET_IF_H
-#ifdef SIOCGIFCONF
+#ifdef HAVE_GETIFADDRS
static Lisp_Object
-network_interface_list (void)
+network_interface_list (bool full, unsigned short match)
{
- struct ifconf ifconf;
- struct ifreq *ifreq;
- void *buf = NULL;
- ptrdiff_t buf_size = 512;
- int s;
- Lisp_Object res;
- ptrdiff_t count;
+ Lisp_Object res = Qnil;
+ struct ifaddrs *ifap;
- s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (s < 0)
+ if (getifaddrs (&ifap) == -1)
return Qnil;
- count = SPECPDL_INDEX ();
- record_unwind_protect_int (close_file_unwind, s);
- do
+ for (struct ifaddrs *it = ifap; it != NULL; it = it->ifa_next)
{
- buf = xpalloc (buf, &buf_size, 1, INT_MAX, 1);
- ifconf.ifc_buf = buf;
- ifconf.ifc_len = buf_size;
- if (ioctl (s, SIOCGIFCONF, &ifconf))
- {
- emacs_close (s);
- xfree (buf);
- return Qnil;
- }
- }
- while (ifconf.ifc_len == buf_size);
-
- res = unbind_to (count, Qnil);
- ifreq = ifconf.ifc_req;
- while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len)
- {
- struct ifreq *ifq = ifreq;
-#ifdef HAVE_STRUCT_IFREQ_IFR_ADDR_SA_LEN
-#define SIZEOF_IFREQ(sif) \
- ((sif)->ifr_addr.sa_len < sizeof (struct sockaddr) \
- ? sizeof (*(sif)) : sizeof ((sif)->ifr_name) + (sif)->ifr_addr.sa_len)
+ int len;
+ int addr_len;
+ uint32_t *maskp;
+ uint32_t *addrp;
+ Lisp_Object elt = Qnil;
- int len = SIZEOF_IFREQ (ifq);
-#else
- int len = sizeof (*ifreq);
+ /* BSD can allegedly return interfaces with a NULL address. */
+ if (it->ifa_addr == NULL)
+ continue;
+ if (match && it->ifa_addr->sa_family != match)
+ continue;
+ if (it->ifa_addr->sa_family == AF_INET)
+ {
+ DECLARE_POINTER_ALIAS (sin1, struct sockaddr_in, it->ifa_netmask);
+ maskp = (uint32_t *)&sin1->sin_addr;
+ DECLARE_POINTER_ALIAS (sin2, struct sockaddr_in, it->ifa_addr);
+ addrp = (uint32_t *)&sin2->sin_addr;
+ len = sizeof (struct sockaddr_in);
+ addr_len = 1;
+ }
+#ifdef AF_INET6
+ else if (it->ifa_addr->sa_family == AF_INET6)
+ {
+ DECLARE_POINTER_ALIAS (sin6_1, struct sockaddr_in6, it->ifa_netmask);
+ maskp = (uint32_t *) &sin6_1->sin6_addr;
+ DECLARE_POINTER_ALIAS (sin6_2, struct sockaddr_in6, it->ifa_addr);
+ addrp = (uint32_t *) &sin6_2->sin6_addr;
+ len = sizeof (struct sockaddr_in6);
+ addr_len = 4;
+ }
#endif
- char namebuf[sizeof (ifq->ifr_name) + 1];
- ifreq = (struct ifreq *) ((char *) ifreq + len);
+ else
+ continue;
- if (ifq->ifr_addr.sa_family != AF_INET)
- continue;
+ Lisp_Object addr = conv_sockaddr_to_lisp (it->ifa_addr, len);
- memcpy (namebuf, ifq->ifr_name, sizeof (ifq->ifr_name));
- namebuf[sizeof (ifq->ifr_name)] = 0;
- res = Fcons (Fcons (build_string (namebuf),
- conv_sockaddr_to_lisp (&ifq->ifr_addr,
- sizeof (struct sockaddr))),
- res);
+ if (full)
+ {
+ elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt);
+ /* There is an it->ifa_broadaddr field, but its contents are
+ unreliable, so always calculate the broadcast address from
+ the address and the netmask. */
+ int i;
+ uint32_t mask;
+ for (i = 0; i < addr_len; i++)
+ {
+ mask = maskp[i];
+ maskp[i] = (addrp[i] & mask) | ~mask;
+ }
+ elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt);
+ elt = Fcons (addr, elt);
+ }
+ else
+ {
+ elt = addr;
+ }
+ res = Fcons (Fcons (build_string (it->ifa_name), elt), res);
}
+#ifdef HAVE_FREEIFADDRS
+ freeifaddrs (ifap);
+#endif
- xfree (buf);
return res;
}
-#endif /* SIOCGIFCONF */
+#endif /* HAVE_GETIFADDRS */
+#ifdef HAVE_NET_IF_H
#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS)
struct ifflag_def {
#endif /* defined (HAVE_NET_IF_H) */
DEFUN ("network-interface-list", Fnetwork_interface_list,
- Snetwork_interface_list, 0, 0, 0,
+ Snetwork_interface_list, 0, 2, 0,
doc: /* Return an alist of all network interfaces and their network address.
-Each element is a cons, the car of which is a string containing the
-interface name, and the cdr is the network address in internal
-format; see the description of ADDRESS in `make-network-process'.
+Each element is cons of the form (IFNAME . IP) where IFNAME is a
+string containing the interface name, and IP is the network address in
+internal format; see the description of ADDRESS in
+`make-network-process'. The interface name is not guaranteed to be
+unique.
+
+Optional parameter FULL non-nil means return all IP address info for
+each interface. Each element is then a list of the form
+ (IFNAME IP BCAST MASK)
+where IFNAME is the interface name, IP the IP address,
+BCAST the broadcast address, and MASK the network mask.
+
+Optional parameter FAMILY controls the type of addresses to return.
+The default of nil means both IPv4 and IPv6, symbol `ipv4' means IPv4
+only, symbol `ipv6' means IPv6 only.
+
+See also `network-interface-info', which is limited to IPv4 only.
If the information is not available, return nil. */)
- (void)
+ (Lisp_Object full, Lisp_Object family)
{
-#if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT
- return network_interface_list ();
+#if defined HAVE_GETIFADDRS || defined WINDOWSNT
+ unsigned short match;
+ bool full_info = false;
+
+ if (! NILP (full))
+ full_info = true;
+ if (NILP (family))
+ match = 0;
+ else if (EQ (family, Qipv4))
+ match = AF_INET;
+#ifdef AF_INET6
+ else if (EQ (family, Qipv6))
+ match = AF_INET6;
+#endif
+ else
+ error ("Unsupported address family");
+ return network_interface_list (full_info, match);
#else
return Qnil;
#endif
extern void restore_nofile_limit (void);
#ifdef WINDOWSNT
-extern Lisp_Object network_interface_list (void);
+extern Lisp_Object network_interface_list (bool full, unsigned short match);
extern Lisp_Object network_interface_info (Lisp_Object);
#endif
#undef connect
#undef htons
#undef ntohs
+#undef htonl
+#undef ntohl
#undef inet_addr
#undef gethostname
#undef gethostbyname
static BOOL g_b_init_set_named_security_info_w;
static BOOL g_b_init_set_named_security_info_a;
static BOOL g_b_init_get_adapters_info;
+static BOOL g_b_init_get_adapters_addresses;
static BOOL g_b_init_reg_open_key_ex_w;
static BOOL g_b_init_reg_query_value_ex_w;
static BOOL g_b_init_expand_environment_strings_w;
typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
PIP_ADAPTER_INFO pAdapterInfo,
PULONG pOutBufLen);
+typedef DWORD (WINAPI *GetAdaptersAddresses_Proc) (
+ ULONG,
+ ULONG,
+ PVOID,
+ PIP_ADAPTER_ADDRESSES,
+ PULONG);
int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
}
+static DWORD WINAPI
+get_adapters_addresses (ULONG family, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen)
+{
+ static GetAdaptersAddresses_Proc s_pfn_Get_Adapters_Addresses = NULL;
+ HMODULE hm_iphlpapi = NULL;
+
+ if (is_windows_9x () == TRUE)
+ return ERROR_NOT_SUPPORTED;
+
+ if (g_b_init_get_adapters_addresses == 0)
+ {
+ g_b_init_get_adapters_addresses = 1;
+ hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
+ if (hm_iphlpapi)
+ s_pfn_Get_Adapters_Addresses = (GetAdaptersAddresses_Proc)
+ get_proc_addr (hm_iphlpapi, "GetAdaptersAddresses");
+ }
+ if (s_pfn_Get_Adapters_Addresses == NULL)
+ return ERROR_NOT_SUPPORTED;
+ ULONG flags = GAA_FLAG_SKIP_ANYCAST
+ | GAA_FLAG_SKIP_MULTICAST
+ | GAA_FLAG_SKIP_DNS_SERVER;
+ return s_pfn_Get_Adapters_Addresses (family, flags, NULL, pAdapterAddresses, pOutBufLen);
+}
+
static LONG WINAPI
reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions,
REGSAM samDesired, PHKEY phkResult)
u_short (PASCAL *pfn_htons) (u_short hostshort);
u_short (PASCAL *pfn_ntohs) (u_short netshort);
+u_long (PASCAL *pfn_htonl) (u_long hostlong);
+u_long (PASCAL *pfn_ntohl) (u_long netlong);
unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
int (PASCAL *pfn_gethostname) (char * name, int namelen);
struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
LOAD_PROC (shutdown);
LOAD_PROC (htons);
LOAD_PROC (ntohs);
+ LOAD_PROC (htonl);
+ LOAD_PROC (ntohl);
LOAD_PROC (inet_addr);
LOAD_PROC (gethostname);
LOAD_PROC (gethostbyname);
return (winsock_lib != NULL) ?
pfn_ntohs (netshort) : netshort;
}
+u_long
+sys_htonl (u_long hostlong)
+{
+ return (winsock_lib != NULL) ?
+ pfn_htonl (hostlong) : hostlong;
+}
+
+u_long
+sys_ntohl (u_long netlong)
+{
+ return (winsock_lib != NULL) ?
+ pfn_ntohl (netlong) : netlong;
+}
unsigned long
sys_inet_addr (const char * cp)
}
Lisp_Object
-network_interface_list (void)
+network_interface_list (bool full, unsigned short match)
{
- return network_interface_get_info (Qnil);
+ ULONG ainfo_len = sizeof (IP_ADAPTER_ADDRESSES);
+ ULONG family = match;
+ IP_ADAPTER_ADDRESSES *adapter, *ainfo = xmalloc (ainfo_len);
+ DWORD retval = get_adapters_addresses (family, ainfo, &ainfo_len);
+ Lisp_Object res = Qnil;
+
+ if (retval == ERROR_BUFFER_OVERFLOW)
+ {
+ ainfo = xrealloc (ainfo, ainfo_len);
+ retval = get_adapters_addresses (family, ainfo, &ainfo_len);
+ }
+
+ if (retval != ERROR_SUCCESS)
+ {
+ xfree (ainfo);
+ return res;
+ }
+
+ /* For the below, we need some winsock functions, so make sure
+ the winsock DLL is loaded. If we cannot successfully load
+ it, they will have no use of the information we provide,
+ anyway, so punt. */
+ if (!winsock_lib && !init_winsock (1))
+ return res;
+
+ int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
+ int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
+ int tnl_count = 0;
+ int if_num;
+ char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
+ static const char *ifmt[] = {
+ "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
+ "lo%d", "ifx%d", "tunnel%d"
+ };
+ enum {
+ NONE = -1,
+ ETHERNET = 0,
+ TOKENRING = 1,
+ FDDI = 2,
+ PPP = 3,
+ SLIP = 4,
+ WLAN = 5,
+ LOOPBACK = 6,
+ OTHER_IF = 7,
+ TUNNEL = 8
+ } ifmt_idx;
+
+ for (adapter = ainfo; adapter; adapter = adapter->Next)
+ {
+
+ /* Present Unix-compatible interface names, instead of the
+ Windows names, which are really GUIDs not readable by
+ humans. */
+
+ switch (adapter->IfType)
+ {
+ case IF_TYPE_ETHERNET_CSMACD:
+ ifmt_idx = ETHERNET;
+ if_num = eth_count++;
+ break;
+ case IF_TYPE_ISO88025_TOKENRING:
+ ifmt_idx = TOKENRING;
+ if_num = tr_count++;
+ break;
+ case IF_TYPE_FDDI:
+ ifmt_idx = FDDI;
+ if_num = fddi_count++;
+ break;
+ case IF_TYPE_PPP:
+ ifmt_idx = PPP;
+ if_num = ppp_count++;
+ break;
+ case IF_TYPE_SLIP:
+ ifmt_idx = SLIP;
+ if_num = sl_count++;
+ break;
+ case IF_TYPE_IEEE80211:
+ ifmt_idx = WLAN;
+ if_num = wlan_count++;
+ break;
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ ifmt_idx = LOOPBACK;
+ if_num = lo_count++;
+ break;
+ case IF_TYPE_TUNNEL:
+ ifmt_idx = TUNNEL;
+ if_num = tnl_count++;
+ break;
+ default:
+ ifmt_idx = OTHER_IF;
+ if_num = ifx_count++;
+ break;
+ }
+ sprintf (namebuf, ifmt[ifmt_idx], if_num);
+
+ IP_ADAPTER_UNICAST_ADDRESS *address;
+ for (address = adapter->FirstUnicastAddress; address; address = address->Next)
+ {
+ int len;
+ int addr_len;
+ uint32_t *maskp;
+ uint32_t *addrp;
+ Lisp_Object elt = Qnil;
+ struct sockaddr *ifa_addr = address->Address.lpSockaddr;
+
+ if (ifa_addr == NULL)
+ continue;
+ if (match && ifa_addr->sa_family != match)
+ continue;
+
+ struct sockaddr_in ipv4;
+#ifdef AF_INET6
+ struct sockaddr_in6 ipv6;
+#endif
+ struct sockaddr *sin;
+
+ if (ifa_addr->sa_family == AF_INET)
+ {
+ ipv4.sin_family = AF_INET;
+ ipv4.sin_port = 0;
+ DECLARE_POINTER_ALIAS (sin_in, struct sockaddr_in, ifa_addr);
+ addrp = (uint32_t *)&sin_in->sin_addr;
+ maskp = (uint32_t *)&ipv4.sin_addr;
+ sin = (struct sockaddr *)&ipv4;
+ len = sizeof (struct sockaddr_in);
+ addr_len = 1;
+ }
+#ifdef AF_INET6
+ else if (ifa_addr->sa_family == AF_INET6)
+ {
+ ipv6.sin6_family = AF_INET6;
+ ipv6.sin6_port = 0;
+ DECLARE_POINTER_ALIAS (sin_in6, struct sockaddr_in6, ifa_addr);
+ addrp = (uint32_t *)&sin_in6->sin6_addr;
+ maskp = (uint32_t *)&ipv6.sin6_addr;
+ sin = (struct sockaddr *)&ipv6;
+ len = sizeof (struct sockaddr_in6);
+ addr_len = 4;
+ }
+#endif
+ else
+ continue;
+
+ Lisp_Object addr = conv_sockaddr_to_lisp (ifa_addr, len);
+
+ if (full)
+ {
+ /* GetAdaptersAddress returns information in network
+ byte order, so convert from host to network order
+ when generating the netmask. */
+ int i;
+ ULONG numbits = address->OnLinkPrefixLength;
+ for (i = 0; i < addr_len; i++)
+ {
+ if (numbits >= 32)
+ {
+ maskp[i] = -1U;
+ numbits -= 32;
+ }
+ else if (numbits)
+ {
+ maskp[i] = sys_htonl (-1U << (32 - numbits));
+ numbits = 0;
+ }
+ else
+ {
+ maskp[i] = 0;
+ }
+ }
+ elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
+ uint32_t mask;
+ for (i = 0; i < addr_len; i++)
+ {
+ mask = maskp[i];
+ maskp[i] = (addrp[i] & mask) | ~mask;
+
+ }
+ elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
+ elt = Fcons (addr, elt);
+ }
+ else
+ {
+ elt = addr;
+ }
+ res = Fcons (Fcons (build_string (namebuf), elt), res);
+ }
+ }
+ xfree (ainfo);
+ return res;
}
Lisp_Object
g_b_init_set_named_security_info_w = 0;
g_b_init_set_named_security_info_a = 0;
g_b_init_get_adapters_info = 0;
+ g_b_init_get_adapters_addresses = 0;
g_b_init_reg_open_key_ex_w = 0;
g_b_init_reg_query_value_ex_w = 0;
g_b_init_expand_environment_strings_w = 0;