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 #include "plugin_hooks.h"
26 #include "bgp/bgp.h"
27 #include "bgp/bgp_lg.h"
28 #include "pmbgpd.h"
29 #include "pretag_handlers.h"
30 #include "pmacct-data.h"
31 #include "pkt_handlers.h"
32 #include "ip_flow.h"
33 #include "classifier.h"
34 #include "net_aggr.h"
35 #include "thread_pool.h"
36
37 /* global var */
38 extern struct channels_list_entry channels_list[MAX_N_PLUGINS]; /* communication channels: core <-> plugins */
39
40 /* Functions */
usage_daemon(char * prog_name)41 void usage_daemon(char *prog_name)
42 {
43 printf("%s %s (%s)\n", PMBGPD_USAGE_HEADER, PMACCT_VERSION, PMACCT_BUILD);
44 printf("Usage: %s [ -D | -d ] [ -L IP address ] [ -l port ] ]\n", prog_name);
45 printf(" %s [ -f config_file ]\n", prog_name);
46 printf(" %s [ -h ]\n", prog_name);
47 printf("\nGeneral options:\n");
48 printf(" -h \tShow this page\n");
49 printf(" -V \tShow version and compile-time options and exit\n");
50 printf(" -L \tBind to the specified IP address\n");
51 printf(" -l \tListen on the specified TCP port\n");
52 printf(" -f \tLoad configuration from the specified file\n");
53 printf(" -D \tDaemonize\n");
54 printf(" -d \tEnable debug\n");
55 printf(" -S \t[ auth | mail | daemon | kern | user | local[0-7] ] \n\tLog to the specified syslog facility\n");
56 printf(" -F \tWrite Core Process PID into the specified file\n");
57 printf(" -o \tOutput file to log real-time BGP messages\n");
58 printf(" -O \tOutput file to dump generated RIBs at regular time intervals\n");
59 printf(" -i \tInterval, in secs, to write to the dump output file (supplied by -O)\n");
60 printf(" -g \tEnable the Looking Glass server\n");
61 printf(" -m \tLoad a BGP xconnects map from the specified file\n");
62 printf("\n");
63 printf("For examples, see:\n");
64 printf(" https://github.com/pmacct/pmacct/blob/master/QUICKSTART or\n");
65 printf(" https://github.com/pmacct/pmacct/wiki\n");
66 printf("\n");
67 printf("For suggestions, critics, bugs, contact me: %s.\n", MANTAINER);
68 }
69
main(int argc,char ** argv,char ** envp)70 int main(int argc,char **argv, char **envp)
71 {
72 struct plugins_list_entry *list;
73 char config_file[SRVBUFLEN];
74 int logf;
75
76 /* getopt() stuff */
77 extern char *optarg;
78 extern int optind, opterr, optopt;
79 int errflag, cp;
80
81 #ifdef WITH_REDIS
82 struct p_redis_host redis_host;
83 #endif
84
85 #if defined HAVE_MALLOPT
86 mallopt(M_CHECK_ACTION, 0);
87 #endif
88
89 umask(077);
90
91 memset(cfg_cmdline, 0, sizeof(cfg_cmdline));
92 memset(&config, 0, sizeof(struct configuration));
93 memset(&config_file, 0, sizeof(config_file));
94 memset(empty_mem_area_256b, 0, sizeof(empty_mem_area_256b));
95
96 log_notifications_init(&log_notifications);
97 config.acct_type = ACCT_PMBGP;
98
99 find_id_func = NULL;
100 plugins_list = NULL;
101 errflag = 0;
102 rows = 0;
103
104 /* getting commandline values */
105 while (!errflag && ((cp = getopt(argc, argv, ARGS_PMBGPD)) != -1)) {
106 cfg_cmdline[rows] = malloc(SRVBUFLEN);
107 switch (cp) {
108 case 'L':
109 strlcpy(cfg_cmdline[rows], "bgp_daemon_ip: ", SRVBUFLEN);
110 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
111 rows++;
112 break;
113 case 'l':
114 strlcpy(cfg_cmdline[rows], "bgp_daemon_port: ", SRVBUFLEN);
115 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
116 rows++;
117 break;
118 case 'D':
119 strlcpy(cfg_cmdline[rows], "daemonize: true", SRVBUFLEN);
120 rows++;
121 break;
122 case 'd':
123 debug = TRUE;
124 strlcpy(cfg_cmdline[rows], "debug: true", SRVBUFLEN);
125 rows++;
126 break;
127 case 'f':
128 strlcpy(config_file, optarg, sizeof(config_file));
129 break;
130 case 'F':
131 strlcpy(cfg_cmdline[rows], "pidfile: ", SRVBUFLEN);
132 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
133 rows++;
134 break;
135 case 'S':
136 strlcpy(cfg_cmdline[rows], "syslog: ", SRVBUFLEN);
137 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
138 rows++;
139 break;
140 case 'o':
141 strlcpy(cfg_cmdline[rows], "bgp_daemon_msglog_file: ", SRVBUFLEN);
142 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
143 rows++;
144 break;
145 case 'O':
146 strlcpy(cfg_cmdline[rows], "bgp_table_dump_file: ", SRVBUFLEN);
147 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
148 rows++;
149 break;
150 case 'i':
151 strlcpy(cfg_cmdline[rows], "bgp_table_dump_refresh_time: ", SRVBUFLEN);
152 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
153 rows++;
154 break;
155 case 'g':
156 strlcpy(cfg_cmdline[rows], "bgp_daemon_lg: true", SRVBUFLEN);
157 rows++;
158 break;
159 case 'm':
160 strlcpy(cfg_cmdline[rows], "bgp_daemon_xconnect_map: ", SRVBUFLEN);
161 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
162 rows++;
163 break;
164 case 'h':
165 usage_daemon(argv[0]);
166 exit(0);
167 break;
168 case 'V':
169 version_daemon(PMBGPD_USAGE_HEADER);
170 exit(0);
171 break;
172 default:
173 usage_daemon(argv[0]);
174 exit(1);
175 break;
176 }
177 }
178
179 /* post-checks and resolving conflicts */
180 if (strlen(config_file)) {
181 if (parse_configuration_file(config_file) != SUCCESS)
182 exit(1);
183 }
184 else {
185 if (parse_configuration_file(NULL) != SUCCESS)
186 exit(1);
187 }
188
189 list = plugins_list;
190 while (list) {
191 list->cfg.acct_type = ACCT_PMBGP;
192 set_default_preferences(&list->cfg);
193 if (!strcmp(list->type.string, "core")) {
194 memcpy(&config, &list->cfg, sizeof(struct configuration));
195 config.name = list->name;
196 config.type = list->type.string;
197 }
198 list = list->next;
199 }
200
201 if (config.files_umask) umask(config.files_umask);
202
203 initsetproctitle(argc, argv, envp);
204 if (config.syslog) {
205 logf = parse_log_facility(config.syslog);
206 if (logf == ERR) {
207 config.syslog = NULL;
208 printf("WARN ( %s/core ): specified syslog facility is not supported. Logging to standard error (stderr).\n", config.name);
209 }
210 else openlog(NULL, LOG_PID, logf);
211 Log(LOG_INFO, "INFO ( %s/core ): Start logging ...\n", config.name);
212 }
213
214 if (config.logfile) {
215 config.logfile_fd = open_output_file(config.logfile, "a", FALSE);
216 while (list) {
217 list->cfg.logfile_fd = config.logfile_fd ;
218 list = list->next;
219 }
220 }
221
222 if (config.daemon) {
223 if (!config.syslog && !config.logfile) {
224 if (debug || config.debug) {
225 printf("WARN ( %s/core ): debug is enabled; forking in background. Logging to standard error (stderr) will get lost.\n", config.name);
226 }
227 }
228
229 daemonize();
230 }
231
232 if (config.proc_priority) {
233 int ret;
234
235 ret = setpriority(PRIO_PROCESS, 0, config.proc_priority);
236 if (ret) Log(LOG_WARNING, "WARN ( %s/core ): proc_priority failed (errno: %d)\n", config.name, errno);
237 else Log(LOG_INFO, "INFO ( %s/core ): proc_priority set to %d\n", config.name, getpriority(PRIO_PROCESS, 0));
238 }
239
240 Log(LOG_INFO, "INFO ( %s/core ): %s %s (%s)\n", config.name, PMBGPD_USAGE_HEADER, PMACCT_VERSION, PMACCT_BUILD);
241 Log(LOG_INFO, "INFO ( %s/core ): %s\n", config.name, PMACCT_COMPILE_ARGS);
242
243 if (strlen(config_file)) {
244 char canonical_path[PATH_MAX], *canonical_path_ptr;
245
246 canonical_path_ptr = realpath(config_file, canonical_path);
247 if (canonical_path_ptr) Log(LOG_INFO, "INFO ( %s/core ): Reading configuration file '%s'.\n", config.name, canonical_path);
248 }
249 else Log(LOG_INFO, "INFO ( %s/core ): Reading configuration from cmdline.\n", config.name);
250
251 pm_setproctitle("%s [%s]", "Core Process", config.proc_name);
252 if (config.pidfile) write_pid_file(config.pidfile);
253
254 /* signal handling we want to inherit to plugins (when not re-defined elsewhere) */
255 memset(&sighandler_action, 0, sizeof(sighandler_action)); /* To ensure the struct holds no garbage values */
256 sigemptyset(&sighandler_action.sa_mask); /* Within a signal handler all the signals are enabled */
257 sighandler_action.sa_flags = SA_RESTART; /* To enable re-entering a system call afer done with signal handling */
258
259 sighandler_action.sa_handler = startup_handle_falling_child;
260 sigaction(SIGCHLD, &sighandler_action, NULL);
261
262 /* handles reopening of syslog channel */
263 sighandler_action.sa_handler = reload;
264 sigaction(SIGHUP, &sighandler_action, NULL);
265
266 /* logs various statistics via Log() calls */
267 sighandler_action.sa_handler = SIG_IGN;
268 sigaction(SIGUSR1, &sighandler_action, NULL);
269
270 /* sets to true the reload_maps flag */
271 sighandler_action.sa_handler = reload_maps;
272 sigaction(SIGUSR2, &sighandler_action, NULL);
273
274 /* we want to exit gracefully when a pipe is broken */
275 sighandler_action.sa_handler = SIG_IGN;
276 sigaction(SIGPIPE, &sighandler_action, NULL);
277
278 sighandler_action.sa_handler = PM_sigint_handler;
279 sigaction(SIGINT, &sighandler_action, NULL);
280
281 sighandler_action.sa_handler = PM_sigint_handler;
282 sigaction(SIGTERM, &sighandler_action, NULL);
283
284 sighandler_action.sa_handler = handle_falling_child;
285 sigaction(SIGCHLD, &sighandler_action, NULL);
286
287 sighandler_action.sa_handler = PM_sigalrm_noop_handler;
288 sigaction(SIGALRM, &sighandler_action, NULL);
289
290 if (!config.bgp_daemon) config.bgp_daemon = BGP_DAEMON_ONLINE;
291 if (!config.bgp_daemon_port) config.bgp_daemon_port = BGP_TCP_PORT;
292
293 #if defined WITH_ZMQ
294 if (config.bgp_lg) bgp_lg_wrapper();
295 #else
296 if (config.bgp_lg) {
297 Log(LOG_ERR, "ERROR ( %s/core/lg ): 'bgp_daemon_lg' requires --enable-zmq. Exiting.\n", config.name);
298 exit_gracefully(1);
299 }
300 #endif
301
302 #ifdef WITH_REDIS
303 if (config.redis_host) {
304 char log_id[SHORTBUFLEN];
305
306 snprintf(log_id, sizeof(log_id), "%s/%s", config.name, config.type);
307 p_redis_init(&redis_host, log_id, p_redis_thread_produce_common_core_handler);
308 }
309 #endif
310
311 bgp_prepare_daemon();
312 skinny_bgp_daemon();
313
314 return 0;
315 }
316