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