Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: canohost.c,v 1.17 2026/04/08 18:58:40 christos Exp $	*/
      2 /* $OpenBSD: canohost.c,v 1.78 2026/02/14 00:18:34 jsg Exp $ */
      3 
      4 /*
      5  * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
      6  * Copyright (c) 1995 Tatu Ylonen <ylo (at) cs.hut.fi>, Espoo, Finland
      7  *                    All rights reserved
      8  * Functions for returning the canonical host name of the remote site.
      9  *
     10  * As far as I am concerned, the code I have written for this software
     11  * can be used freely for any purpose.  Any derived versions of this
     12  * software must be clearly marked as such, and if the derived work is
     13  * incompatible with the protocol description in the RFC file, it must be
     14  * called by a name other than "ssh" or "Secure Shell".
     15  */
     16 
     17 #include "includes.h"
     18 __RCSID("$NetBSD: canohost.c,v 1.17 2026/04/08 18:58:40 christos Exp $");
     19 #include <sys/types.h>
     20 #include <sys/socket.h>
     21 #include <sys/un.h>
     22 
     23 #include <netinet/in.h>
     24 
     25 #include <errno.h>
     26 #include <netdb.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <stdarg.h>
     31 #include <time.h>
     32 #include <unistd.h>
     33 
     34 #include "xmalloc.h"
     35 #include "log.h"
     36 #include "canohost.h"
     37 #include "misc.h"
     38 
     39 /*
     40  * Returns the local/remote IP-address/hostname of socket as a string.
     41  * The returned string must be freed.
     42  */
     43 static char *
     44 get_socket_address(int sock, int remote, int flags)
     45 {
     46 	struct sockaddr_storage addr;
     47 	socklen_t addrlen;
     48 	char ntop[NI_MAXHOST];
     49 	int r;
     50 
     51 	if (sock < 0)
     52 		return NULL;
     53 
     54 	/* Get IP address of client. */
     55 	addrlen = sizeof(addr);
     56 	memset(&addr, 0, sizeof(addr));
     57 
     58 	if (remote) {
     59 		if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0)
     60 			return NULL;
     61 	} else {
     62 		if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0)
     63 			return NULL;
     64 	}
     65 
     66 	switch (addr.ss_family) {
     67 	case AF_INET:
     68 	case AF_INET6:
     69 		/* Get the address in ascii. */
     70 		if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
     71 		    sizeof(ntop), NULL, 0, flags)) != 0) {
     72 			error_f("getnameinfo %d failed: %s",
     73 			    flags, ssh_gai_strerror(r));
     74 			return NULL;
     75 		}
     76 		return xstrdup(ntop);
     77 	case AF_UNIX:
     78 		/* Get the Unix domain socket path. */
     79 		return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
     80 	default:
     81 		/* We can't look up remote Unix domain sockets. */
     82 		return NULL;
     83 	}
     84 }
     85 
     86 char *
     87 get_peer_ipaddr(int sock)
     88 {
     89 	char *p;
     90 
     91 	if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
     92 		return p;
     93 	return xstrdup("UNKNOWN");
     94 }
     95 
     96 char *
     97 get_local_ipaddr(int sock)
     98 {
     99 	char *p;
    100 
    101 	if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
    102 		return p;
    103 	return xstrdup("UNKNOWN");
    104 }
    105 
    106 char *
    107 get_local_name(int fd)
    108 {
    109 	char *host, myname[NI_MAXHOST];
    110 
    111 	/* Assume we were passed a socket */
    112 	if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
    113 		return host;
    114 
    115 	/* Handle the case where we were passed a pipe */
    116 	if (gethostname(myname, sizeof(myname)) == -1) {
    117 		verbose_f("gethostname: %s", strerror(errno));
    118 		host = xstrdup("UNKNOWN");
    119 	} else {
    120 		host = xstrdup(myname);
    121 	}
    122 
    123 	return host;
    124 }
    125 
    126 /* Returns the local/remote port for the socket. */
    127 
    128 static int
    129 get_sock_port(int sock, int local)
    130 {
    131 	struct sockaddr_storage from;
    132 	socklen_t fromlen;
    133 	char strport[NI_MAXSERV];
    134 	int r;
    135 
    136 	if (sock < 0)
    137 		return -1;
    138 	/* Get IP address of client. */
    139 	fromlen = sizeof(from);
    140 	memset(&from, 0, sizeof(from));
    141 	if (local) {
    142 		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) == -1) {
    143 			error("getsockname failed: %.100s", strerror(errno));
    144 			return 0;
    145 		}
    146 	} else {
    147 		if (getpeername(sock, (struct sockaddr *)&from, &fromlen) == -1) {
    148 			debug("getpeername failed: %.100s", strerror(errno));
    149 			return -1;
    150 		}
    151 	}
    152 
    153 	/* Non-inet sockets don't have a port number. */
    154 	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
    155 		return 0;
    156 
    157 	/* Return port number. */
    158 	if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
    159 	    strport, sizeof(strport), NI_NUMERICSERV)) != 0)
    160 		fatal_f("getnameinfo NI_NUMERICSERV failed: %s",
    161 		    ssh_gai_strerror(r));
    162 	return atoi(strport);
    163 }
    164 
    165 int
    166 get_peer_port(int sock)
    167 {
    168 	return get_sock_port(sock, 0);
    169 }
    170 
    171 int
    172 get_local_port(int sock)
    173 {
    174 	return get_sock_port(sock, 1);
    175 }
    176