1 /**
2  * Copyright (c) 2013, Timothy Stack
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  * * Neither the name of Timothy Stack nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * @file nextwork-extension-functions.cc
30  */
31 
32 #include "config.h"
33 
34 #include <string.h>
35 #include <sys/socket.h>
36 #include <netdb.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 
40 #include "sqlite3.h"
41 
42 #include "auto_mem.hh"
43 #include "vtab_module.hh"
44 #include "sqlite-extension-func.hh"
45 
46 using namespace std;
47 
sql_gethostbyname(const char * name_in)48 static string sql_gethostbyname(const char *name_in)
49 {
50     char             buffer[INET6_ADDRSTRLEN];
51     auto_mem<struct addrinfo> ai(freeaddrinfo);
52     void *           addr_ptr = nullptr;
53     struct addrinfo hints;
54     int rc;
55 
56     memset(&hints, 0, sizeof(hints));
57     for (auto family : {AF_INET, AF_INET6}) {
58         hints.ai_family = family;
59         while ((rc = getaddrinfo(name_in, nullptr, &hints, ai.out())) ==
60                EAI_AGAIN) {
61             sqlite3_sleep(10);
62         }
63         if (rc != 0) {
64             return name_in;
65         }
66 
67         switch (ai.in()->ai_family) {
68             case AF_INET:
69                 addr_ptr = &((struct sockaddr_in *) ai.in()->ai_addr)->sin_addr;
70                 break;
71 
72             case AF_INET6:
73                 addr_ptr = &((struct sockaddr_in6 *) ai.in()->ai_addr)->sin6_addr;
74                 break;
75 
76             default:
77                 return name_in;
78         }
79 
80         inet_ntop(ai.in()->ai_family, addr_ptr, buffer, sizeof(buffer));
81         break;
82     }
83 
84     return buffer;
85 }
86 
sql_gethostbyaddr(const char * addr_str)87 static string sql_gethostbyaddr(const char *addr_str)
88 {
89     union {
90         struct sockaddr_in  sin;
91         struct sockaddr_in6 sin6;
92     }           sa;
93     char        buffer[NI_MAXHOST];
94     int         family, socklen;
95     char *      addr_raw;
96     int         rc;
97 
98     memset(&sa, 0, sizeof(sa));
99     if (strchr(addr_str, ':')) {
100         family              = AF_INET6;
101         socklen             = sizeof(struct sockaddr_in6);
102         sa.sin6.sin6_family = family;
103         addr_raw            = (char *)&sa.sin6.sin6_addr;
104     }
105     else {
106         family            = AF_INET;
107         socklen           = sizeof(struct sockaddr_in);
108         sa.sin.sin_family = family;
109         addr_raw          = (char *)&sa.sin.sin_addr;
110     }
111 
112     if (inet_pton(family, addr_str, addr_raw) != 1) {
113         return addr_str;
114     }
115 
116     while ((rc = getnameinfo((struct sockaddr *)&sa, socklen,
117                              buffer, sizeof(buffer), NULL, 0,
118                              0)) == EAI_AGAIN) {
119         sqlite3_sleep(10);
120     }
121 
122     if (rc != 0) {
123         return addr_str;
124     }
125 
126     return buffer;
127 }
128 
network_extension_functions(struct FuncDef ** basic_funcs,struct FuncDefAgg ** agg_funcs)129 int network_extension_functions(struct FuncDef **basic_funcs,
130                                 struct FuncDefAgg **agg_funcs)
131 {
132     static struct FuncDef network_funcs[] = {
133         sqlite_func_adapter<decltype(&sql_gethostbyname), sql_gethostbyname>::builder(
134             help_text("gethostbyname",
135                       "Get the IP address for the given hostname")
136                 .sql_function()
137                 .with_parameter({"hostname", "The DNS hostname to lookup."})
138                 .with_tags({"net"})
139                 .with_example({
140                     "To get the IP address for 'localhost'",
141                     "SELECT gethostbyname('localhost')"
142                 })
143         ),
144 
145         sqlite_func_adapter<decltype(&sql_gethostbyaddr), sql_gethostbyaddr>::builder(
146             help_text("gethostbyaddr",
147                       "Get the hostname for the given IP address")
148                 .sql_function()
149                 .with_parameter({"hostname", "The IP address to lookup."})
150                 .with_tags({"net"})
151                 .with_example({
152                     "To get the hostname for the IP '127.0.0.1'",
153                     "SELECT gethostbyaddr('127.0.0.1')"
154                 })
155         ),
156 
157         { nullptr }
158     };
159 
160     *basic_funcs = network_funcs;
161 
162     return SQLITE_OK;
163 }
164