1 /*
2 pmacct (Promiscuous mode IP Accounting package)
3 pmacct is Copyright (C) 2003-2020 by Paolo Lucente
4 */
5
6 /*
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 /* includes */
23 #include "pmacct.h"
24 #include "addr.h"
25 #if defined WITH_ZMQ
26 #include "zmq_common.h"
27 #endif
28 #include "bgp.h"
29 #include "bgp_lg.h"
30 #include "pmacct-data.h"
31 #include "thread_pool.h"
32
33 /* global var */
34 thread_pool_t *bgp_lg_pool;
35 char bgp_lg_default_ip[] = "127.0.0.1";
36
37 #if defined WITH_ZMQ
bgp_lg_wrapper()38 void bgp_lg_wrapper()
39 {
40 /* initialize variables */
41 if (!config.bgp_lg_ip) config.bgp_lg_ip = bgp_lg_default_ip;
42 if (!config.bgp_lg_port) config.bgp_lg_port = BGP_LG_DEFAULT_TCP_PORT;
43 if (!config.bgp_lg_threads) config.bgp_lg_threads = BGP_LG_DEFAULT_THREADS;
44
45 /* initialize threads pool */
46 bgp_lg_pool = allocate_thread_pool(1);
47 assert(bgp_lg_pool);
48 Log(LOG_DEBUG, "DEBUG ( %s/core/lg ): Looking Glass thread initialized\n", config.name);
49
50 /* giving a kick to the BGP thread */
51 send_to_pool(bgp_lg_pool, bgp_lg_daemon, NULL);
52 }
53
bgp_lg_daemon()54 void bgp_lg_daemon()
55 {
56 char inproc_str[] = "inproc://lg_host_backend", log_id[SHORTBUFLEN];
57 struct p_zmq_host lg_host;
58
59 memset(&lg_host, 0, sizeof(lg_host));
60
61 snprintf(log_id, sizeof(log_id), "%s/core/lg", config.name);
62 p_zmq_set_log_id(&lg_host, log_id);
63
64 p_zmq_set_address(&lg_host, inproc_str);
65 if (config.bgp_lg_user) p_zmq_set_username(&lg_host, config.bgp_lg_user);
66 if (config.bgp_lg_passwd) p_zmq_set_password(&lg_host, config.bgp_lg_passwd);
67
68 p_zmq_router_setup(&lg_host, config.bgp_lg_ip, config.bgp_lg_port);
69 Log(LOG_INFO, "INFO ( %s/core/lg ): Looking Glass listening on %s:%u\n", config.name, config.bgp_lg_ip, config.bgp_lg_port);
70
71 // XXX: more encodings supported in future?
72 #ifdef WITH_JANSSON
73 lg_host.router_worker.func = &bgp_lg_daemon_worker_json;
74 #else
75 lg_host.router_worker.func = NULL;
76 Log(LOG_WARNING, "WARN ( %s/core/lg ): Looking Glass depends on missing --enable-jansson.\n", config.name);
77 exit_gracefully(1);
78 #endif
79
80 p_zmq_router_backend_setup(&lg_host, config.bgp_lg_threads);
81 }
82
83 #ifdef WITH_JANSSON
bgp_lg_daemon_worker_json(void * zh,void * zs)84 void bgp_lg_daemon_worker_json(void *zh, void *zs)
85 {
86 struct p_zmq_host *lg_host = (struct p_zmq_host *) zh;
87 struct p_zmq_sock *sock = zs;
88 struct bgp_lg_req req;
89 struct bgp_lg_rep ipl_rep, gp_rep;
90 int ret;
91
92 if (!lg_host || !sock) {
93 Log(LOG_ERR, "ERROR ( %s/core/lg ): bgp_lg_daemon_worker no lg_host or sock\nExiting.\n", config.name);
94 exit_gracefully(1);
95 }
96
97 memset(&ipl_rep, 0, sizeof(ipl_rep));
98 memset(&gp_rep, 0, sizeof(gp_rep));
99
100 for (;;) {
101 memset(&req, 0, sizeof(req));
102 ret = bgp_lg_daemon_decode_query_header_json(sock, &req);
103
104 switch(req.type) {
105 case BGP_LG_QT_IP_LOOKUP:
106 {
107 struct bgp_lg_req_ipl_data query_data;
108
109 req.data = &query_data;
110 memset(req.data, 0, sizeof(struct bgp_lg_req_ipl_data));
111 ret = bgp_lg_daemon_decode_query_ip_lookup_json(sock, req.data);
112
113 bgp_lg_rep_init(&ipl_rep);
114 if (!ret) ret = bgp_lg_daemon_ip_lookup(req.data, &ipl_rep, FUNC_TYPE_BGP);
115
116 bgp_lg_daemon_encode_reply_ip_lookup_json(sock, &ipl_rep, ret);
117 }
118 break;
119 case BGP_LG_QT_GET_PEERS:
120 bgp_lg_rep_init(&gp_rep);
121 ret = bgp_lg_daemon_get_peers(&gp_rep, FUNC_TYPE_BGP);
122 bgp_lg_daemon_encode_reply_get_peers_json(sock, &gp_rep, ret);
123
124 break;
125 case BGP_LG_QT_UNKNOWN:
126 default:
127 bgp_lg_daemon_encode_reply_unknown_json(sock);
128 break;
129 }
130 }
131 }
132
bgp_lg_daemon_decode_query_header_json(struct p_zmq_sock * sock,struct bgp_lg_req * req)133 int bgp_lg_daemon_decode_query_header_json(struct p_zmq_sock *sock, struct bgp_lg_req *req)
134 {
135 json_t *req_obj, *query_type_json, *queries_num_json;
136 json_error_t req_err;
137 char *req_str;
138 int ret = SUCCESS;
139
140 if (!sock || !req) return ERR;
141
142 req_str = p_zmq_recv_str(sock);
143 if (req_str) {
144 req_obj = json_loads(req_str, 0, &req_err);
145 free(req_str);
146 }
147 else {
148 req_obj = NULL;
149 ret = ERR;
150 }
151
152 if (req_obj) {
153 if (!json_is_object(req_obj)) {
154 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_header_json(): json_is_object() failed.\n", config.name);
155 ret = ERR;
156 goto exit_lane;
157 }
158 else {
159 query_type_json = json_object_get(req_obj, "query_type");
160 if (query_type_json == NULL) {
161 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_header_json(): no 'query_type' element.\n", config.name);
162 ret = ERR;
163 goto exit_lane;
164 }
165 else req->type = json_integer_value(query_type_json);
166
167 queries_num_json = json_object_get(req_obj, "queries");
168 if (queries_num_json == NULL) {
169 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_header_json(): no 'queries' element.\n", config.name);
170 ret = ERR;
171 goto exit_lane;
172 }
173 else req->num = json_integer_value(queries_num_json);
174
175 /* XXX: only one query per query message currently supported */
176 if (req->num != 1) {
177 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_header_json(): 'queries' element != 1.\n", config.name);
178 ret = ERR;
179 goto exit_lane;
180 }
181 }
182
183 exit_lane:
184 json_decref(req_obj);
185 }
186 else {
187 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_header_json(): invalid request received: %s.\n", config.name, req_err.text);
188 ret = ERR;
189 }
190
191 return ret;
192 }
193
bgp_lg_daemon_decode_query_ip_lookup_json(struct p_zmq_sock * sock,struct bgp_lg_req_ipl_data * req)194 int bgp_lg_daemon_decode_query_ip_lookup_json(struct p_zmq_sock *sock, struct bgp_lg_req_ipl_data *req)
195 {
196 json_error_t req_err;
197 json_t *req_obj, *peer_ip_src_json, *bgp_port_json, *ip_prefix_json, *rd_json;
198 const char *peer_ip_src_str, *ip_prefix_str, *rd_str;
199 char *req_str;
200 int ret = SUCCESS;
201 struct rd_as4 *rd_as4_ptr;
202 u_int16_t bgp_port = 0;
203
204 if (!sock || !req) return ERR;
205
206 req_str = p_zmq_recv_str(sock);
207
208 if (req_str) {
209 req_obj = json_loads(req_str, 0, &req_err);
210 free(req_str);
211 }
212 else {
213 req_obj = NULL;
214 ret = ERR;
215 }
216
217 if (req_obj) {
218 if (!json_is_object(req_obj)) {
219 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): json_is_object() failed.\n", config.name);
220 ret = ERR;
221 goto exit_lane;
222 }
223 else {
224 bgp_port_json = json_object_get(req_obj, "peer_tcp_port");
225 if (bgp_port_json) {
226 int bgp_port_int;
227
228 bgp_port_int = json_integer_value(bgp_port_json);
229 if (bgp_port_int >= 0 && bgp_port_int <= 65535) bgp_port = bgp_port_int;
230 else {
231 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): bogus 'peer_tcp_port' element.\n", config.name);
232 ret = ERR;
233 goto exit_lane;
234 }
235 }
236
237 peer_ip_src_json = json_object_get(req_obj, "peer_ip_src");
238 if (peer_ip_src_json == NULL) {
239 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): no 'peer_ip_src' element.\n", config.name);
240 ret = ERR;
241 goto exit_lane;
242 }
243 else {
244 struct host_addr peer_ip_src_ha;
245
246 peer_ip_src_str = json_string_value(peer_ip_src_json);
247 str_to_addr(peer_ip_src_str, &peer_ip_src_ha);
248 addr_to_sa(&req->peer, &peer_ip_src_ha, bgp_port);
249 if (!req->peer.sa_family) {
250 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): bogus 'peer_ip_src' element.\n", config.name);
251 ret = ERR;
252 goto exit_lane;
253 }
254 }
255
256 ip_prefix_json = json_object_get(req_obj, "ip_prefix");
257 if (ip_prefix_json == NULL) {
258 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): no 'ip_prefix' element.\n", config.name);
259 ret = ERR;
260 goto exit_lane;
261 }
262 else {
263 ip_prefix_str = json_string_value(ip_prefix_json);
264 str2prefix(ip_prefix_str, &req->pref);
265 if (!req->pref.family) {
266 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): bogus 'ip_prefix' element.\n", config.name);
267 ret = ERR;
268 goto exit_lane;
269 }
270 }
271
272 rd_json = json_object_get(req_obj, "rd");
273 if (rd_json) {
274 rd_str = json_string_value(rd_json);
275 bgp_str2rd(&req->rd, (char *) rd_str);
276 rd_as4_ptr = (struct rd_as4 *) &req->rd;
277 if (!rd_as4_ptr->as) {
278 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): bogus 'rd' element.\n", config.name);
279 ret = ERR;
280 goto exit_lane;
281 }
282 }
283 }
284
285 exit_lane:
286 json_decref(req_obj);
287 }
288 else {
289 Log(LOG_WARNING, "WARN ( %s/core/lg ): bgp_lg_daemon_decode_query_ip_lookup_json(): invalid request received: %s.\n", config.name, req_err.text);
290 ret = ERR;
291 }
292
293 return ret;
294 }
295
bgp_lg_daemon_encode_reply_results_json(struct p_zmq_sock * sock,struct bgp_lg_rep * rep,int res,int query_type)296 void bgp_lg_daemon_encode_reply_results_json(struct p_zmq_sock *sock, struct bgp_lg_rep *rep, int res, int query_type)
297 {
298 json_t *rep_results_obj;
299 char *rep_results_str;
300
301 rep_results_obj = json_object();
302 json_object_set_new_nocheck(rep_results_obj, "results", json_integer(rep->results));
303 json_object_set_new_nocheck(rep_results_obj, "query_type", json_integer(query_type));
304
305 if (!rep->results && res) {
306 switch (res) {
307 case BGP_LOOKUP_ERR:
308 json_object_set_new_nocheck(rep_results_obj, "text", json_string("lookup error"));
309 break;
310 case BGP_LOOKUP_NOPREFIX:
311 json_object_set_new_nocheck(rep_results_obj, "text", json_string("prefix not found"));
312 break;
313 case BGP_LOOKUP_NOPEER:
314 json_object_set_new_nocheck(rep_results_obj, "text", json_string("peer not found"));
315 break;
316 default:
317 json_object_set_new_nocheck(rep_results_obj, "text", json_string("unknown lookup error"));
318 break;
319 }
320 }
321
322 rep_results_str = json_dumps(rep_results_obj, JSON_PRESERVE_ORDER);
323 json_decref(rep_results_obj);
324
325 if (rep_results_str) {
326 if (!rep->results) p_zmq_send_str(sock, rep_results_str);
327 else p_zmq_sendmore_str(sock, rep_results_str);
328
329 free(rep_results_str);
330 }
331 }
332
bgp_lg_daemon_encode_reply_ip_lookup_json(struct p_zmq_sock * sock,struct bgp_lg_rep * rep,int res)333 void bgp_lg_daemon_encode_reply_ip_lookup_json(struct p_zmq_sock *sock, struct bgp_lg_rep *rep, int res)
334 {
335 if (!sock || !rep) return;
336
337 bgp_lg_daemon_encode_reply_results_json(sock, rep, res, BGP_LG_QT_IP_LOOKUP);
338
339 if (rep->results) {
340 struct bgp_lg_rep_data *data;
341 struct bgp_lg_rep_ipl_data *ipl_data;
342 char *rep_data_str;
343 u_int32_t idx;
344
345 for (idx = 0, data = rep->data; idx < rep->results; idx++) {
346 ipl_data = data->ptr;
347
348 rep_data_str = bgp_lg_daemon_encode_reply_ip_lookup_data_json(ipl_data);
349
350 if (rep_data_str) {
351 if (idx == (rep->results - 1)) p_zmq_send_str(sock, rep_data_str);
352 else p_zmq_sendmore_str(sock, rep_data_str);
353
354 free(rep_data_str);
355 }
356
357 data = data->next;
358 }
359 }
360 }
361
bgp_lg_daemon_encode_reply_ip_lookup_data_json(struct bgp_lg_rep_ipl_data * rep_data)362 char *bgp_lg_daemon_encode_reply_ip_lookup_data_json(struct bgp_lg_rep_ipl_data *rep_data)
363 {
364 struct bgp_node dummy_node;
365 char event_type[] = "lglass", *data_str = NULL;
366
367 if (rep_data && rep_data->pref) {
368 memset(&dummy_node, 0, sizeof(dummy_node));
369 memcpy(&dummy_node.p, rep_data->pref, sizeof(struct prefix));
370
371 bgp_peer_log_msg(&dummy_node, rep_data->info, rep_data->afi, rep_data->safi, event_type,
372 PRINT_OUTPUT_JSON, &data_str, BGP_LOG_TYPE_MISC);
373 }
374
375 return data_str;
376 }
377
bgp_lg_daemon_encode_reply_get_peers_json(struct p_zmq_sock * sock,struct bgp_lg_rep * rep,int res)378 void bgp_lg_daemon_encode_reply_get_peers_json(struct p_zmq_sock *sock, struct bgp_lg_rep *rep, int res)
379 {
380 if (!sock || !rep) return;
381
382 bgp_lg_daemon_encode_reply_results_json(sock, rep, res, BGP_LG_QT_GET_PEERS);
383
384 if (rep->results) {
385 struct bgp_lg_rep_data *data;
386 struct bgp_lg_rep_gp_data *gp_data;
387 char *rep_data_str;
388 u_int32_t idx;
389
390 for (idx = 0, data = rep->data; idx < rep->results; idx++) {
391 gp_data = data->ptr;
392
393 rep_data_str = bgp_lg_daemon_encode_reply_get_peers_data_json(gp_data);
394
395 if (rep_data_str) {
396 if (idx == (rep->results - 1)) p_zmq_send_str(sock, rep_data_str);
397 else p_zmq_sendmore_str(sock, rep_data_str);
398
399 free(rep_data_str);
400 }
401
402 data = data->next;
403 }
404 }
405 }
406
bgp_lg_daemon_encode_reply_get_peers_data_json(struct bgp_lg_rep_gp_data * rep_data)407 char *bgp_lg_daemon_encode_reply_get_peers_data_json(struct bgp_lg_rep_gp_data *rep_data)
408 {
409 struct bgp_misc_structs *bms;
410 char ip_address[INET6_ADDRSTRLEN], *data_str = NULL;
411 json_t *obj = json_object();
412
413 if (rep_data) {
414 struct bgp_peer *peer = rep_data->peer;
415
416 bms = bgp_select_misc_db(peer->type);
417 if (!bms) return NULL;
418
419 addr_to_str(ip_address, &peer->addr);
420 json_object_set_new_nocheck(obj, bms->peer_str, json_string(ip_address));
421
422 addr_to_str(ip_address, &peer->id);
423 json_object_set_new_nocheck(obj, "peer_id", json_string(ip_address));
424
425 json_object_set_new_nocheck(obj, "peer_tcp_port", json_integer((json_int_t)peer->tcp_port));
426 json_object_set_new_nocheck(obj, "peer_as", json_integer((json_int_t)peer->as));
427
428 data_str = compose_json_str(obj);
429 }
430
431 return data_str;
432 }
433
bgp_lg_daemon_encode_reply_unknown_json(struct p_zmq_sock * sock)434 void bgp_lg_daemon_encode_reply_unknown_json(struct p_zmq_sock *sock)
435 {
436 json_t *rep_results_obj;
437 char *rep_results_str;
438
439 if (!sock) return;
440
441 rep_results_obj = json_object();
442 json_object_set_new_nocheck(rep_results_obj, "results", json_integer(FALSE));
443 json_object_set_new_nocheck(rep_results_obj, "query_type", json_integer(BGP_LG_QT_UNKNOWN));
444 json_object_set_new_nocheck(rep_results_obj, "text", json_string("unsupported query_type"));
445
446 rep_results_str = json_dumps(rep_results_obj, JSON_PRESERVE_ORDER);
447 json_decref(rep_results_obj);
448
449 p_zmq_send_str(sock, rep_results_str);
450 }
451 #endif
452 #endif /* WITH_ZMQ */
453