source: lib/canohost.c @ 0e2c8b4

Last change on this file since 0e2c8b4 was b097945, checked in by Wilmer van der Gaast <github@…>, at 2017-04-06T20:25:08Z

Move canohost functions (diff licence) to separate file.

  • Property mode set to 100644
File size: 4.7 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2017 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/*
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License with
19  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
20  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
21  Fifth Floor, Boston, MA  02110-1301  USA
22*/
23
24/* These two functions, with some modifications, taken from OpenSSH:
25 *
26 * $OpenBSD: canohost.c,v 1.73 2016/03/07 19:02:43 djm Exp
27 *
28 * Author: Tatu Ylonen <ylo@cs.hut.fi>
29 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
30 *                    All rights reserved
31 * Functions for returning the canonical host name of the remote site.
32 *
33 * As far as I am concerned, the code I have written for this software
34 * can be used freely for any purpose.  Any derived versions of this
35 * software must be clearly marked as such, and if the derived work is
36 * incompatible with the protocol description in the RFC file, it must be
37 * called by a name other than "ssh" or "Secure Shell".
38 */
39
40#include "canohost.h"
41
42char *reverse_lookup(const struct sockaddr *from_, const socklen_t fromlen_)
43{
44        struct sockaddr_storage from;
45        socklen_t fromlen;
46        struct addrinfo hints, *ai, *aitop;
47        char name[NI_MAXHOST], ntop2[NI_MAXHOST];
48        char ntop[INET6_ADDRSTRLEN];
49
50        fromlen = sizeof(from);
51        memset(&from, 0, sizeof(from));
52        memcpy(&from, from_, fromlen_);
53        ipv64_normalise_mapped(&from, &fromlen);
54        if (from.ss_family == AF_INET6) {
55                fromlen = sizeof(struct sockaddr_in6);
56        }
57
58        if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
59            NULL, 0, NI_NUMERICHOST) != 0) {
60                return NULL;
61        }
62
63        /* Map the IP address to a host name. */
64        if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
65            NULL, 0, NI_NAMEREQD) != 0) {
66                /* Host name not found.  Use ip address. */
67                return g_strdup(ntop);
68        }
69
70        /*
71         * if reverse lookup result looks like a numeric hostname,
72         * someone is trying to trick us by PTR record like following:
73         *      1.1.1.10.in-addr.arpa.  IN PTR  2.3.4.5
74         */
75        memset(&hints, 0, sizeof(hints));
76        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
77        hints.ai_flags = AI_NUMERICHOST;
78        if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
79                freeaddrinfo(ai);
80                return g_strdup(ntop);
81        }
82
83        /* Names are stored in lowercase. */
84        char *tolower = g_utf8_strdown(name, -1);
85        g_snprintf(name, sizeof(name), "%s", tolower);
86        g_free(tolower);
87
88        /*
89         * Map it back to an IP address and check that the given
90         * address actually is an address of this host.  This is
91         * necessary because anyone with access to a name server can
92         * define arbitrary names for an IP address. Mapping from
93         * name to IP address can be trusted better (but can still be
94         * fooled if the intruder has access to the name server of
95         * the domain).
96         */
97        memset(&hints, 0, sizeof(hints));
98        hints.ai_family = from.ss_family;
99        hints.ai_socktype = SOCK_STREAM;
100        if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
101                return g_strdup(ntop);
102        }
103        /* Look for the address from the list of addresses. */
104        for (ai = aitop; ai; ai = ai->ai_next) {
105                if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
106                    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
107                    (strcmp(ntop, ntop2) == 0))
108                        break;
109        }
110        freeaddrinfo(aitop);
111        /* If we reached the end of the list, the address was not there. */
112        if (ai == NULL) {
113                /* Address not found for the host name. */
114                return g_strdup(ntop);
115        }
116        return g_strdup(name);
117}
118
119void
120ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
121{
122        struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
123        struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
124        struct in_addr inaddr;
125        u_int16_t port;
126
127        if (addr->ss_family != AF_INET6 ||
128            !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
129                return;
130
131        memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
132        port = a6->sin6_port;
133
134        memset(a4, 0, sizeof(*a4));
135
136        a4->sin_family = AF_INET;
137        *len = sizeof(*a4);
138        memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
139        a4->sin_port = port;
140}
Note: See TracBrowser for help on using the repository browser.