#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/un.h>
+#include <pwd.h>
+#include <grp.h>
#define DEFINE_PLUG_METHOD_MACROS
#include "putty.h"
(addr)->superfamily == UNIX ? AF_UNIX : \
(step).ai ? (step).ai->ai_family : AF_INET)
#else
+/* Here we gratuitously reference 'step' to avoid gcc warnings about
+ * 'set but not used' when compiling -DNO_IPV6 */
#define SOCKADDR_FAMILY(addr, step) \
((addr)->superfamily == UNRESOLVED ? AF_UNSPEC : \
- (addr)->superfamily == UNIX ? AF_UNIX : AF_INET)
+ (addr)->superfamily == UNIX ? AF_UNIX : \
+ (step).curraddr ? AF_INET : AF_INET)
#endif
/*
}
#else
struct in_addr a;
- assert(SOCKADDR_FAMILY(addr, ignored_macro_parameter) == AF_INET);
+ SockAddrStep step;
+ START_STEP(addr, step);
+ assert(SOCKADDR_FAMILY(addr, step) == AF_INET);
a.s_addr = htonl(addr->addresses[0]);
strncpy(buf, inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
return sockaddr_is_loopback(addr->ais->ai_addr);
#else
struct in_addr a;
- assert(SOCKADDR_FAMILY(addr, ignored_macro_parameter) == AF_INET);
+ SockAddrStep step;
+ START_STEP(addr, step);
+ assert(SOCKADDR_FAMILY(addr, step) == AF_INET);
a.s_addr = htonl(addr->addresses[0]);
return ipv4_is_loopback(a);
#endif
int sk_addrtype(SockAddr addr)
{
+ SockAddrStep step;
int family;
- family = SOCKADDR_FAMILY(addr, ignored_macro_parameter);
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
return (family == AF_INET ? ADDRTYPE_IPV4 :
#ifndef NO_IPV6
static int sk_tcp_write_oob(Socket s, const char *data, int len);
static void sk_tcp_write_eof(Socket s);
static void sk_tcp_set_frozen(Socket s, int is_frozen);
+static char *sk_tcp_peer_info(Socket s);
static const char *sk_tcp_socket_error(Socket s);
static struct socket_function_table tcp_fn_table = {
sk_tcp_write_eof,
sk_tcp_flush,
sk_tcp_set_frozen,
- sk_tcp_socket_error
+ sk_tcp_socket_error,
+ sk_tcp_peer_info,
};
static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
return (Socket) ret;
}
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int orig_address_family)
+Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
+ int local_host_only, int orig_address_family)
{
int s;
#ifndef NO_IPV6
- struct addrinfo hints, *ai;
+ struct addrinfo hints, *ai = NULL;
char portstr[6];
#endif
union sockaddr_union u;
}
retcode = bind(s, &addr->sa, addrlen);
+
+#ifndef NO_IPV6
+ if (ai)
+ freeaddrinfo(ai);
+#endif
+
if (retcode < 0) {
close(s);
ret->error = strerror(errno);
uxsel_tell(s);
}
+static char *sk_tcp_peer_info(Socket sock)
+{
+ Actual_Socket s = (Actual_Socket) sock;
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ char buf[INET6_ADDRSTRLEN];
+
+ if (getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
+ return NULL;
+ if (addr.ss_family == AF_INET) {
+ return dupprintf
+ ("%s:%d",
+ inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr),
+ (int)ntohs(((struct sockaddr_in *)&addr)->sin_port));
+#ifndef NO_IPV6
+ } else if (addr.ss_family == AF_INET6) {
+ return dupprintf
+ ("[%s]:%d",
+ inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
+ buf, sizeof(buf)),
+ (int)ntohs(((struct sockaddr_in6 *)&addr)->sin6_port));
+#endif
+ } else if (addr.ss_family == AF_UNIX) {
+ /*
+ * For Unix sockets, the source address is unlikely to be
+ * helpful. Instead, we try SO_PEERCRED and try to get the
+ * source pid.
+ */
+ int pid, uid, gid;
+ if (so_peercred(s->s, &pid, &uid, &gid)) {
+ char uidbuf[64], gidbuf[64];
+ sprintf(uidbuf, "%d", uid);
+ sprintf(gidbuf, "%d", gid);
+ struct passwd *pw = getpwuid(uid);
+ struct group *gr = getgrgid(gid);
+ return dupprintf("pid %d (%s:%s)", pid,
+ pw ? pw->pw_name : uidbuf,
+ gr ? gr->gr_name : gidbuf);
+ }
+ return NULL;
+ } else {
+ return NULL;
+ }
+}
+
static void uxsel_tell(Actual_Socket s)
{
int rwx = 0;