1 /*
2 * Copyright (c) 2016-2021, OARC, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "config.h"
36
37 #include "bpft.h"
38 #include "iaddr.h"
39
40 #include <ldns/ldns.h>
41
prepare_bpft(void)42 void prepare_bpft(void)
43 {
44 unsigned udp10_mbs, udp10_mbc, udp11_mbc; //udp11_mbs
45 text_list bpfl;
46 text_ptr text;
47 size_t len;
48 char* p;
49
50 /* Prepare the must-be-set and must-be-clear tests. */
51 udp10_mbs = udp10_mbc = udp11_mbc = 0U; // udp11_mbs
52 if ((dir_wanted & DIR_INITIATE) != 0) {
53 if ((dir_wanted & DIR_RESPONSE) == 0)
54 udp10_mbc |= UDP10_QR_MASK;
55 } else if ((dir_wanted & DIR_RESPONSE) != 0) {
56 udp10_mbs |= UDP10_QR_MASK;
57 }
58 if ((msg_wanted & MSG_UPDATE) != 0) {
59 if ((msg_wanted & (MSG_QUERY | MSG_NOTIFY)) == 0)
60 udp10_mbs |= (LDNS_PACKET_UPDATE << UDP10_OP_SHIFT);
61 } else if ((msg_wanted & MSG_NOTIFY) != 0) {
62 if ((msg_wanted & (MSG_QUERY | MSG_UPDATE)) == 0)
63 udp10_mbs |= (LDNS_PACKET_NOTIFY << UDP10_OP_SHIFT);
64 } else if ((msg_wanted & MSG_QUERY) != 0) {
65 udp10_mbc |= UDP10_OP_MASK;
66 }
67 if (err_wanted == ERR_NO) {
68 udp10_mbc |= UDP10_TC_MASK;
69 udp11_mbc |= UDP11_RC_MASK;
70 }
71
72 /*
73 * Model
74 * (vlan) and (transport)
75 * (vlan) and ((icmp) or (frags) or (dns))
76 * (vlan) and ((icmp) or (frags) or ((ports) and (hosts)))
77 * (vlan) and ((icmp) or (frags) or (((tcp) or (udp)) and (hosts)))
78 * [(vlan) and] ( [(icmp) or] [(frags) or] ( ( [(tcp) or] (udp) ) [and (hosts)] ) )
79 */
80
81 /* Make a BPF program to do early course kernel-level filtering. */
82 INIT_LIST(bpfl);
83 len = 0;
84 if (!EMPTY(vlans_excl))
85 len += text_add(&bpfl, "vlan and ("); /* vlan and ( transports ... */
86 else
87 len += text_add(&bpfl, "("); /* ( transports ... */
88 if (wanticmp) {
89 len += text_add(&bpfl, " ( ip proto 1 or ip proto 58 ) or");
90 }
91 if (wantfrags) {
92 len += text_add(&bpfl, " ( ip[6:2] & 0x1fff != 0 or ip6[6] = 44 ) or");
93 }
94 len += text_add(&bpfl, " ("); /* ( dns ... */
95 len += text_add(&bpfl, " ("); /* ( ports ... */
96 if (wanttcp) {
97 len += text_add(&bpfl, " ( tcp port %d ) or", dns_port);
98 /* tcp packets can be filtered by initiators/responders, but
99 * not mbs/mbc. */
100 }
101 len += text_add(&bpfl, " ( udp port %d and ( ip6 or ( ip", dns_port);
102
103 if (udp10_mbc != 0)
104 len += text_add(&bpfl, " and udp[10] & 0x%x = 0",
105 udp10_mbc);
106 if (udp10_mbs != 0)
107 len += text_add(&bpfl, " and udp[10] & 0x%x = 0x%x",
108 udp10_mbs, udp10_mbs);
109 if (udp11_mbc != 0)
110 len += text_add(&bpfl, " and udp[11] & 0x%x = 0",
111 udp11_mbc);
112 /* Dead code, udp11_mbs never set
113 if (udp11_mbs != 0)
114 len += text_add(&bpfl, " and udp[11] & 0x%x = 0x%x",
115 udp11_mbs, udp11_mbs);
116 */
117
118 if (err_wanted != ERR_NO) {
119 len += text_add(&bpfl, " and (");
120 if ((err_wanted & ERR_TRUNC) != 0) {
121 len += text_add(&bpfl, " udp[10] & 0x%x = 0x%x or", UDP10_TC_MASK, UDP10_TC_MASK);
122 }
123 len += text_add(&bpfl, " 0x%x << (udp[11] & 0xf) & 0x%x != 0 )", ERR_RCODE_BASE, err_wanted);
124 }
125
126 len += text_add(&bpfl, " )))"); /* ... udp 53 ) */
127 len += text_add(&bpfl, " )"); /* ... ports ) */
128 if (options.bpf_hosts_apply_all) {
129 len += text_add(&bpfl, " )"); /* ... dns ) */
130 len += text_add(&bpfl, " )"); /* ... transport ) */
131 }
132 if (!EMPTY(initiators) || !EMPTY(responders)) {
133 const char* or = "or", *lp = "(", *sep;
134 endpoint_ptr ep;
135
136 len += text_add(&bpfl, " and host");
137 sep = lp;
138 for (ep = HEAD(initiators);
139 ep != NULL;
140 ep = NEXT(ep, link)) {
141 len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
142 sep = or ;
143 }
144 for (ep = HEAD(responders);
145 ep != NULL;
146 ep = NEXT(ep, link)) {
147 len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
148 sep = or ;
149 }
150 len += text_add(&bpfl, " )");
151 }
152 if (!EMPTY(not_initiators) || !EMPTY(not_responders)) {
153 const char* or = "or", *lp = "(", *sep;
154 endpoint_ptr ep;
155
156 len += text_add(&bpfl, " and not host");
157 sep = lp;
158 for (ep = HEAD(not_initiators);
159 ep != NULL;
160 ep = NEXT(ep, link)) {
161 len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
162 sep = or ;
163 }
164 for (ep = HEAD(not_responders);
165 ep != NULL;
166 ep = NEXT(ep, link)) {
167 len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
168 sep = or ;
169 }
170 len += text_add(&bpfl, " )");
171 }
172 if (!options.bpf_hosts_apply_all) {
173 len += text_add(&bpfl, " )"); /* ... dns ) */
174 len += text_add(&bpfl, " )"); /* ... transport ) */
175 }
176 if (extra_bpf)
177 len += text_add(&bpfl, " and ( %s )", extra_bpf);
178
179 bpft = calloc(len + 1, sizeof(char));
180 assert(bpft != NULL);
181 p = bpft;
182 for (text = HEAD(bpfl); text != NULL; text = NEXT(text, link)) {
183 memcpy(p, text->text, text->len);
184 p += text->len;
185 }
186 text_free(&bpfl);
187 if (!EMPTY(vlans_incl)) {
188 char* bpft_vlan;
189
190 len = (2 * len) + 64; /* add enough for the extra in snprintf() below */
191 bpft_vlan = calloc(len, sizeof(char));
192 assert(bpft_vlan != NULL);
193
194 snprintf(bpft_vlan, len, "( %s ) or ( vlan and ( %s ) )", bpft, bpft);
195 free(bpft);
196 bpft = bpft_vlan;
197 }
198 if (dumptrace >= 1)
199 fprintf(stderr, "%s: \"%s\"\n", ProgramName, bpft);
200 }
201
text_add(text_list * list,const char * fmt,...)202 size_t text_add(text_list* list, const char* fmt, ...)
203 {
204 text_ptr text;
205 va_list ap;
206 int len;
207
208 text = calloc(1, sizeof *text);
209 assert(text != NULL);
210 INIT_LINK(text, link);
211 va_start(ap, fmt);
212 len = vasprintf(&text->text, fmt, ap);
213 assert(len >= 0);
214 va_end(ap);
215 text->len = len;
216 APPEND(*list, text, link);
217 return (text->len);
218 }
219
text_free(text_list * list)220 void text_free(text_list* list)
221 {
222 text_ptr at, text;
223
224 for (at = HEAD(*list); at;) {
225 text = at;
226 at = NEXT(text, link);
227
228 UNLINK(*list, text, link);
229 free(text->text);
230 assert(text != (void*)-1);
231 free(text);
232 }
233 }
234