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 logfile_sub_source.hh
30 */
31
32 #include "config.h"
33
34 #include <string.h>
35 #include <sqlite3.h>
36
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <sys/socket.h>
40
41 #include "log_level.hh"
42 #include "base/strnatcmp.h"
43
44 #define MAX_ADDR_LEN 128
45
try_inet_pton(int p_len,const char * p,char * n)46 static int try_inet_pton(int p_len, const char *p, char *n)
47 {
48 static int ADDR_FAMILIES[] = { AF_INET, AF_INET6 };
49
50 char buf[MAX_ADDR_LEN + 1];
51 int retval = AF_MAX;
52
53 strncpy(buf, p, p_len);
54 buf[p_len] = '\0';
55 for (int family : ADDR_FAMILIES) {
56 if (inet_pton(family, buf, n) == 1) {
57 retval = family;
58 break;
59 }
60 }
61
62 return retval;
63 }
64
convert_v6_to_v4(int family,char * n)65 static int convert_v6_to_v4(int family, char *n)
66 {
67 struct in6_addr *ia = (struct in6_addr *)n;
68
69 if (family == AF_INET6 &&
70 (IN6_IS_ADDR_V4COMPAT(ia) ||
71 IN6_IS_ADDR_V4MAPPED(ia))) {
72 family = AF_INET;
73 memmove(n, n + 12, sizeof(struct in_addr));
74 }
75
76 return family;
77 }
78
79 static
ipaddress(void * ptr,int a_len,const void * a_in,int b_len,const void * b_in)80 int ipaddress(void *ptr,
81 int a_len, const void *a_in,
82 int b_len, const void *b_in)
83 {
84 char a_addr[sizeof(struct in6_addr)],
85 b_addr[sizeof(struct in6_addr)];
86 const char *a_str = (const char *)a_in, *b_str = (const char *)b_in;
87 int a_family, b_family, retval;
88
89 if ((a_len > MAX_ADDR_LEN) || (b_len > MAX_ADDR_LEN)) {
90 return strnatcasecmp(a_len, a_str, b_len, b_str);
91 }
92
93 int v4res = 0;
94 if (ipv4cmp(a_len, a_str, b_len, b_str, &v4res)) {
95 return v4res;
96 }
97
98 a_family = try_inet_pton(a_len, a_str, a_addr);
99 b_family = try_inet_pton(b_len, b_str, b_addr);
100
101 if (a_family == AF_MAX && b_family == AF_MAX) {
102 return strnatcasecmp(a_len, a_str, b_len, b_str);
103 }
104 else if (a_family == AF_MAX && b_family != AF_MAX) {
105 retval = -1;
106 }
107 else if (a_family != AF_MAX && b_family == AF_MAX) {
108 retval = 1;
109 }
110 else {
111 a_family = convert_v6_to_v4(a_family, a_addr);
112 b_family = convert_v6_to_v4(b_family, b_addr);
113 if (a_family == b_family) {
114 retval = memcmp(a_addr, b_addr,
115 a_family == AF_INET ?
116 sizeof(struct in_addr) :
117 sizeof(struct in6_addr));
118 }
119 else if (a_family == AF_INET) {
120 retval = -1;
121 }
122 else {
123 retval = 1;
124 }
125 }
126
127 return retval;
128 }
129
130 static
sql_strnatcmp(void * ptr,int a_len,const void * a_in,int b_len,const void * b_in)131 int sql_strnatcmp(void *ptr,
132 int a_len, const void *a_in,
133 int b_len, const void *b_in)
134 {
135 return strnatcmp(a_len, (char *)a_in, b_len, (char *)b_in);
136 }
137
138 static
sql_strnatcasecmp(void * ptr,int a_len,const void * a_in,int b_len,const void * b_in)139 int sql_strnatcasecmp(void *ptr,
140 int a_len, const void *a_in,
141 int b_len, const void *b_in)
142 {
143 return strnatcasecmp(a_len, (char *)a_in, b_len, (char *)b_in);
144 }
145
146 static
sql_loglevelcmp(void * ptr,int a_len,const void * a_in,int b_len,const void * b_in)147 int sql_loglevelcmp(void *ptr,
148 int a_len, const void *a_in,
149 int b_len, const void *b_in)
150 {
151 return levelcmp((const char *)a_in, a_len,
152 (const char *)b_in, b_len);
153 }
154
register_collation_functions(sqlite3 * db)155 int register_collation_functions(sqlite3 *db)
156 {
157 sqlite3_create_collation(db, "ipaddress", SQLITE_UTF8, nullptr, ipaddress);
158 sqlite3_create_collation(db, "naturalcase", SQLITE_UTF8, nullptr,
159 sql_strnatcmp);
160 sqlite3_create_collation(db, "naturalnocase", SQLITE_UTF8, nullptr,
161 sql_strnatcasecmp);
162 sqlite3_create_collation(db, "loglevel", SQLITE_UTF8, nullptr,
163 sql_loglevelcmp);
164
165 return 0;
166 }
167