Implement hostname->ip lookup function

* src/process.c (conv_sockaddr_to_lisp): Add include_port
argument.  Don't put a port in the result if this is false.
(conv_addrinfo_to_lisp, Fprocess_datagram_address)
(connect_network_socket, network_interface_list)
(network_interface_info, server_accept_connection)
(init_process_emacs): Update callers.
(Fnetwork_lookup_address_info): New function.  Performs hostname to
ip address lookups.

* src/w32.c (network_interface_get_info): Update callers of
  conv_sockaddr_to_lisp

* etc/NEWS : mention addition of 'network-lookup-address-info'
This commit is contained in:
Robert Pluim 2018-07-16 19:43:41 +02:00
parent fab6139b89
commit e89c06e8ce
4 changed files with 105 additions and 24 deletions

View file

@ -84,6 +84,9 @@ work right without some adjustment:
* Changes in Emacs 27.1
** New function 'network-lookup-address-info'.
This does IPv4 and/or IPv6 address lookups on hostnames.
---
** New variable 'xft-ignore-color-fonts'.
Default t means don't try to load color fonts when using Xft, as they

View file

@ -2484,7 +2484,7 @@ usage: (make-pipe-process &rest ARGS) */)
The address family of sa is not included in the result. */
Lisp_Object
conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len, bool include_port)
{
Lisp_Object address;
ptrdiff_t i;
@ -2503,9 +2503,12 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
{
DECLARE_POINTER_ALIAS (sin, struct sockaddr_in, sa);
len = sizeof (sin->sin_addr) + 1;
if (!include_port)
len--;
address = Fmake_vector (make_number (len), Qnil);
p = XVECTOR (address);
p->contents[--len] = make_number (ntohs (sin->sin_port));
if (include_port)
p->contents[--len] = make_number (ntohs (sin->sin_port));
cp = (unsigned char *) &sin->sin_addr;
break;
}
@ -2515,9 +2518,12 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
DECLARE_POINTER_ALIAS (sin6, struct sockaddr_in6, sa);
DECLARE_POINTER_ALIAS (ip6, uint16_t, &sin6->sin6_addr);
len = sizeof (sin6->sin6_addr) / 2 + 1;
if (!include_port)
len--;
address = Fmake_vector (make_number (len), Qnil);
p = XVECTOR (address);
p->contents[--len] = make_number (ntohs (sin6->sin6_port));
if (include_port)
p->contents[--len] = make_number (ntohs (sin6->sin6_port));
for (i = 0; i < len; i++)
p->contents[i] = make_number (ntohs (ip6[i]));
return address;
@ -2568,7 +2574,7 @@ conv_addrinfo_to_lisp (struct addrinfo *res)
{
Lisp_Object protocol = make_number (res->ai_protocol);
eassert (XINT (protocol) == res->ai_protocol);
return Fcons (protocol, conv_sockaddr_to_lisp (res->ai_addr, res->ai_addrlen));
return Fcons (protocol, conv_sockaddr_to_lisp (res->ai_addr, res->ai_addrlen, true));
}
@ -2710,7 +2716,8 @@ set up yet, this function will block until socket setup has completed. */)
channel = XPROCESS (process)->infd;
return conv_sockaddr_to_lisp (datagram_address[channel].sa,
datagram_address[channel].len);
datagram_address[channel].len,
true);
}
DEFUN ("set-process-datagram-address", Fset_process_datagram_address, Sset_process_datagram_address,
@ -3571,7 +3578,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos,
#endif
contact = Fplist_put (contact, p->is_server? QClocal: QCremote,
conv_sockaddr_to_lisp (sa, addrlen));
conv_sockaddr_to_lisp (sa, addrlen, true));
#ifdef HAVE_GETSOCKNAME
if (!p->is_server)
{
@ -3580,7 +3587,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos,
DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1);
if (getsockname (s, psa1, &len1) == 0)
contact = Fplist_put (contact, QClocal,
conv_sockaddr_to_lisp (psa1, len1));
conv_sockaddr_to_lisp (psa1, len1, true));
}
#endif
}
@ -4253,7 +4260,8 @@ network_interface_list (void)
namebuf[sizeof (ifq->ifr_name)] = 0;
res = Fcons (Fcons (build_string (namebuf),
conv_sockaddr_to_lisp (&ifq->ifr_addr,
sizeof (struct sockaddr))),
sizeof (struct sockaddr),
true)),
res);
}
@ -4456,9 +4464,9 @@ network_interface_info (Lisp_Object ifname)
{
any = 1;
#ifdef HAVE_STRUCT_IFREQ_IFR_NETMASK
elt = conv_sockaddr_to_lisp (&rq.ifr_netmask, sizeof (rq.ifr_netmask));
elt = conv_sockaddr_to_lisp (&rq.ifr_netmask, sizeof (rq.ifr_netmask), true);
#else
elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr));
elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr), true);
#endif
}
#endif
@ -4469,7 +4477,7 @@ network_interface_info (Lisp_Object ifname)
if (ioctl (s, SIOCGIFBRDADDR, &rq) == 0)
{
any = 1;
elt = conv_sockaddr_to_lisp (&rq.ifr_broadaddr, sizeof (rq.ifr_broadaddr));
elt = conv_sockaddr_to_lisp (&rq.ifr_broadaddr, sizeof (rq.ifr_broadaddr), true);
}
#endif
res = Fcons (elt, res);
@ -4479,7 +4487,7 @@ network_interface_info (Lisp_Object ifname)
if (ioctl (s, SIOCGIFADDR, &rq) == 0)
{
any = 1;
elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr));
elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr), true);
}
#endif
res = Fcons (elt, res);
@ -4527,6 +4535,67 @@ Data that is unavailable is returned as nil. */)
#endif
}
DEFUN ("network-lookup-address-info", Fnetwork_lookup_address_info,
Snetwork_lookup_address_info, 1, 2, 0,
doc: /* Look up ip address info of NAME.
Optional parameter FAMILY controls whether to look up IPv4 or IPv6
addresses. The default of nil means both, symbol `ipv4' means IPv4
only, symbol `ipv6' means IPv6 only. Returns a list of addresses, or
nil if none were found. Each address is a vector of integers. */)
(Lisp_Object name, Lisp_Object family)
{
Lisp_Object addresses = Qnil;
struct addrinfo *res, *lres;
int ret;
struct addrinfo hints;
if (STRING_MULTIBYTE (name))
error ("Non-ASCII hostname \"%s\" detected, please use puny-encode-string",
SSDATA (name));
memset (&hints, 0, sizeof hints);
if (EQ (family, Qnil))
hints.ai_family = AF_UNSPEC;
if (EQ (family, Qipv4))
hints.ai_family = AF_INET;
if (EQ (family, Qipv6))
#ifdef AF_INET6
hints.ai_family = AF_INET6;
#else
/* If we don't support IPv6, querying will never work anyway */
return addresses;
#endif
hints.ai_socktype = SOCK_DGRAM;
ret = getaddrinfo (SSDATA (name), NULL, &hints, &res);
if (ret)
#ifdef HAVE_GAI_STRERROR
{
synchronize_system_messages_locale ();
char const *str = gai_strerror (ret);
if (! NILP (Vlocale_coding_system))
str = SSDATA (code_convert_string_norecord
(build_string (str), Vlocale_coding_system, 0));
message ("\"%s\" \"%s\"", SSDATA (name), str);
}
#else
message ("%s network-lookup-address-info error %d", SSDATA (name), ret);
#endif
else
{
for (lres = res; lres; lres = lres->ai_next)
{
addresses = Fcons (conv_sockaddr_to_lisp
(lres->ai_addr, lres->ai_addrlen, false),
addresses);
}
addresses = Fnreverse (addresses);
freeaddrinfo (res);
}
return addresses;
}
/* Turn off input and output for process PROC. */
static void
@ -4794,12 +4863,12 @@ server_accept_connection (Lisp_Object server, int channel)
if (!NILP (service))
contact = Fplist_put (contact, QCservice, service);
contact = Fplist_put (contact, QCremote,
conv_sockaddr_to_lisp (&saddr.sa, len));
conv_sockaddr_to_lisp (&saddr.sa, len, true));
#ifdef HAVE_GETSOCKNAME
len = sizeof saddr;
if (getsockname (s, &saddr.sa, &len) == 0)
contact = Fplist_put (contact, QClocal,
conv_sockaddr_to_lisp (&saddr.sa, len));
conv_sockaddr_to_lisp (&saddr.sa, len, true));
#endif
pset_childp (p, contact);
@ -8031,7 +8100,7 @@ init_process_emacs (int sockfd)
union u_sockaddr sa;
socklen_t salen = sizeof sa;
if (getsockname (sockfd, &sa.sa, &salen) == 0)
sockname = conv_sockaddr_to_lisp (&sa.sa, salen);
sockname = conv_sockaddr_to_lisp (&sa.sa, salen, true);
}
# endif
Vinternal__daemon_sockname = sockname;
@ -8269,6 +8338,7 @@ returns non-`nil'. */);
defsubr (&Sset_network_process_option);
defsubr (&Smake_network_process);
defsubr (&Sformat_network_address);
defsubr (&Snetwork_lookup_address_info);
defsubr (&Snetwork_interface_list);
defsubr (&Snetwork_interface_info);
#ifdef DATAGRAM_SOCKETS

View file

@ -278,7 +278,7 @@ extern Lisp_Object system_process_attributes (Lisp_Object);
extern void record_deleted_pid (pid_t, Lisp_Object);
struct sockaddr;
extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, ptrdiff_t);
extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, ptrdiff_t, bool);
extern void hold_keyboard_input (void);
extern void unhold_keyboard_input (void);
extern bool kbd_on_hold_p (void);

View file

@ -9210,7 +9210,8 @@ network_interface_get_info (Lisp_Object ifname)
if (NILP (ifname))
res = Fcons (Fcons (build_string (namebuf),
conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
sizeof (struct sockaddr))),
sizeof (struct sockaddr),
false)),
res);
else if (strcmp (namebuf, SSDATA (ifname)) == 0)
{
@ -9257,7 +9258,8 @@ network_interface_get_info (Lisp_Object ifname)
sa.sin_addr.s_addr = net_mask;
sa.sin_port = 0;
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
}
else
@ -9274,14 +9276,16 @@ network_interface_get_info (Lisp_Object ifname)
sa.sin_addr.s_addr = bcast_addr;
sa.sin_port = 0;
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
/* IP address. */
sa.sin_addr.s_addr = ip_addr;
sa.sin_port = 0;
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
}
else
@ -9299,7 +9303,8 @@ network_interface_get_info (Lisp_Object ifname)
sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
res = Fcons (Fcons (build_string ("lo"),
conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
sizeof (struct sockaddr))),
sizeof (struct sockaddr),
false)),
res);
}
else if (strcmp (SSDATA (ifname), "lo") == 0)
@ -9315,15 +9320,18 @@ network_interface_get_info (Lisp_Object ifname)
res);
sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
sizeof (struct sockaddr)),
sizeof (struct sockaddr),
false),
res);
}