dnscrypt-proxy 1.4.0
[tomato.git] / release / src / router / dnscrypt / src / plugins / example-ldns-opendns-set-client-ip / example-ldns-opendns-set-client-ip.c
blobdda9ab04965aa2bc4b7d3b3341cb8c29b984a298
2 #include <sys/types.h>
3 #ifndef _WIN32
4 # include <sys/socket.h>
5 # include <netinet/in.h>
6 # include <arpa/inet.h>
7 #endif
9 #include <assert.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <string.h>
14 #ifdef _WIN32
15 # include <ws2tcpip.h>
16 #endif
18 #include <dnscrypt/plugin.h>
19 #include <ldns/ldns.h>
20 #include <ldns/util.h>
22 DCPLUGIN_MAIN(__FILE__);
24 #define EDNS_HEADER "4f56" "0014" "4f444e5300" "00"
25 #define EDNS_HEADER_CLIENT_IP "10"
26 #define EDNS_CLIENT_IP "7f000001"
27 #define EDNS_HEADER_FODDER "40"
28 #define EDNS_FODDER "deadbeefabad1dea"
30 #define EDNS_DATA EDNS_HEADER \
31 EDNS_HEADER_CLIENT_IP EDNS_CLIENT_IP EDNS_HEADER_FODDER EDNS_FODDER
33 #define EDNS_CLIENT_IP_OFFSET (sizeof EDNS_HEADER - 1U + \
34 sizeof EDNS_HEADER_CLIENT_IP - 1U)
36 #define EDNS_FODDER_OFFSET (sizeof EDNS_HEADER - 1U + \
37 sizeof EDNS_HEADER_CLIENT_IP - 1U + \
38 sizeof EDNS_CLIENT_IP - 1U + \
39 sizeof EDNS_HEADER_FODDER - 1U)
41 const char *
42 dcplugin_description(DCPlugin * const dcplugin)
44 return "Apply the OpenDNS settings defined for a specific IP address";
47 const char *
48 dcplugin_long_description(DCPlugin * const dcplugin)
50 return
51 "The IP address must be a hex-encoded IPv4 address.\n"
52 "\n"
53 "Usage:\n"
54 "\n"
55 "# dnscrypt-proxy --plugin \\\n"
56 " libdcplugin_example_ldns_opendns_set_client_ip.la,192.30.252.130";
59 static int
60 _inet_pton(const int af, const char * const src, void * const dst)
62 unsigned char *dstc;
63 unsigned int a, b, c, d;
64 char more;
66 if (af != AF_INET) {
67 errno = EAFNOSUPPORT;
68 return -1;
70 if (sscanf(src, "%u.%u.%u.%u%c", &a, &b, &c, &d, &more) != 4) {
71 return 0;
73 if (a > 0xff || b > 0xff || c > 0xff || d > 0xff) {
74 return 0;
76 dstc = (unsigned char *) dst;
77 assert(sizeof(struct in_addr) >= 4U);
78 dstc[0] = (unsigned char) a;
79 dstc[1] = (unsigned char) b;
80 dstc[2] = (unsigned char) c;
81 dstc[3] = (unsigned char) d;
83 return 1;
86 static int
87 parse_client_ip(const char *ip_s, char * const edns_hex)
89 char ip_hex[8U + 1U];
90 struct in_addr ip_in_addr;
91 unsigned char *sa;
92 const size_t ip_s_len = strlen(ip_s);
94 if (ip_s_len <= INET_ADDRSTRLEN && strchr(ip_s, '.') != NULL &&
95 _inet_pton(AF_INET, ip_s, &ip_in_addr) > 0) {
96 sa = (unsigned char *) &ip_in_addr.s_addr;
97 snprintf(ip_hex, sizeof ip_hex, "%02X%02X%02X%02X",
98 sa[0], sa[1], sa[2], sa[3]);
99 memcpy(edns_hex + EDNS_CLIENT_IP_OFFSET,
100 ip_hex, sizeof EDNS_CLIENT_IP - 1U);
101 } else if (ip_s_len == sizeof EDNS_CLIENT_IP - 1U) {
102 memcpy(edns_hex + EDNS_CLIENT_IP_OFFSET,
103 ip_s, sizeof EDNS_CLIENT_IP - 1U);
104 } else {
105 return -1;
107 return 0;
111 dcplugin_init(DCPlugin * const dcplugin, int argc, char *argv[])
113 char *edns_hex;
114 size_t edns_hex_size = sizeof EDNS_DATA;
116 ldns_init_random(NULL, 0U);
117 edns_hex = malloc(edns_hex_size);
118 dcplugin_set_user_data(dcplugin, edns_hex);
119 if (edns_hex == NULL) {
120 return -1;
122 memcpy(edns_hex, EDNS_DATA, edns_hex_size);
123 assert(sizeof EDNS_CLIENT_IP - 1U == (size_t) 8U);
124 if (argc > 1 && argv[1] != NULL) {
125 parse_client_ip(argv[1], edns_hex);
127 return 0;
131 dcplugin_destroy(DCPlugin *dcplugin)
133 free(dcplugin_get_user_data(dcplugin));
135 return 0;
138 static void
139 fill_with_random_hex_data(char * const str, size_t size)
141 size_t i = (size_t) 0U;
142 uint16_t rnd;
144 while (i < size) {
145 rnd = ldns_get_random();
146 str[i++] = "0123456789abcdef"[rnd & 0xf];
147 str[i++] = "0123456789abcdef"[(rnd >> 8) & 0xf];
151 DCPluginSyncFilterResult
152 dcplugin_sync_pre_filter(DCPlugin *dcplugin, DCPluginDNSPacket *dcp_packet)
154 uint8_t *new_packet;
155 ldns_rdf *edns_data;
156 char *edns_data_str;
157 ldns_pkt *packet;
158 size_t new_packet_size;
160 ldns_wire2pkt(&packet, dcplugin_get_wire_data(dcp_packet),
161 dcplugin_get_wire_data_len(dcp_packet));
163 edns_data_str = dcplugin_get_user_data(dcplugin);
164 fill_with_random_hex_data(edns_data_str + EDNS_FODDER_OFFSET,
165 sizeof EDNS_FODDER - 1U);
166 edns_data = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, edns_data_str);
167 ldns_pkt_set_edns_data(packet, edns_data);
169 ldns_pkt2wire(&new_packet, packet, &new_packet_size);
170 if (dcplugin_get_wire_data_max_len(dcp_packet) >= new_packet_size) {
171 dcplugin_set_wire_data(dcp_packet, new_packet, new_packet_size);
174 free(new_packet);
175 ldns_pkt_free(packet);
177 return DCP_SYNC_FILTER_RESULT_OK;