static int itf_sd_init() { unsigned long hd = 0; if ((hd = CfgInitialize(cfgfile)) == 0ul) { LOGERROR("Parsing configuration file [%s] failed.", cfgfile); return -1; } call_adap_to = adapter_register_archive(hd, (char *)"Call.Archive", CallOutputCallback); sms_adap_to = adapter_register_archive(hd, (char *)"SMS.Archive", SMSOutputCallback); power_adap_to = adapter_register_archive(hd, (char *)"Power.Archive", PowerOutputCallback); switch_adap_to = adapter_register_archive(hd, (char *)"Switch.Archive", SwitchOutputCallback); location_adap_to = adapter_register_archive(hd, (char *)"Location.Archive", LocationOutputCallback); if ((call_adap_to == NULL) || (power_adap_to == NULL) || (sms_adap_to == NULL) || (switch_adap_to == NULL) || (location_adap_to == NULL)) { CfgInvalidate(hd); return -1; } itf_sd_init_lacci_mapping(hd); CfgInvalidate(hd); if (!InitDbus(PKTTYPE_CDR, PKTTYPE_CDR_BSSAP, g_dbus_cdr)) return -1; if (!InitDbus(PKTTYPE_EVENT, PKTTYPE_EVENT_BSSAP, g_dbus_event)) return -1; swdbus_update_filter( g_dbus_event, filter_parse((char *)"(PROTOCOL IN [1, 2])")); g_timer = timer_mgr_create_timerlist(NULL, TIMERMGR_SOURCE_LOCAL, TimerCallback, NULL, "SendCDRConvertStatistics"); timer_mgr_add_timer_periodic(g_timer, 300, NULL); return 0; }
cache_entry * load_cache_table (char *file_name) { cache_entry *cache = NULL; cache_entry **last = &cache; table *file = table_open (file_name); table_entry *entry; while ((entry = table_read (file)) != NULL) { cache_entry *new_rule = ZALLOC (cache_entry); new_rule->line = entry->line; new_rule->entry_type = name2i (entry->field[ca_type], cache_type_map); new_rule->name = entry->field[ca_derived_name]; filter_parse (&new_rule->original_fields, entry->field[ca_field_name]); new_rule->type = entry->field[ca_type_def]; /* expression is the concatenation of the remaining fields */ if (entry->nr_fields > ca_expression) { int len = 0; int chi; for (chi = ca_expression; chi < entry->nr_fields; chi++) { len += strlen (" : ") + strlen (entry->field[chi]); } new_rule->expression = NZALLOC (char, len); strcpy (new_rule->expression, entry->field[ca_expression]); for (chi = ca_expression + 1; chi < entry->nr_fields; chi++) { strcat (new_rule->expression, " : "); strcat (new_rule->expression, entry->field[chi]); } } /* insert it */ *last = new_rule; last = &new_rule->next; }
int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *s, int len) { int argc; char *argv[256]; int i, rc; /* make it null-terminated for our string processing */ char *e = s + len; *e = 0; hlog(LOG_DEBUG, "%s: login string: '%s' (%d)", c->addr_rem, s, len); /* parse to arguments */ if ((argc = parse_args_noshell(argv, s)) == 0 || *argv[0] == '#') return 0; if (argc < 2) { hlog(LOG_WARNING, "%s: Invalid login string, too few arguments: '%s'", c->addr_rem, s); rc = client_printf(self, c, "# Invalid login string, too few arguments\r\n"); goto failed_login; } if (strcasecmp(argv[0], "user") != 0) { if (strcasecmp(argv[0], "GET") == 0) c->failed_cmds = 10; /* bail out right away for a HTTP client */ c->failed_cmds++; hlog(LOG_WARNING, "%s: Invalid login string, no 'user': '******'", c->addr_rem, s); rc = client_printf(self, c, "# Invalid login command\r\n"); goto failed_login; } char *username = argv[1]; /* limit username length */ if (strlen(username) > CALLSIGNLEN_MAX) { hlog(LOG_WARNING, "%s: Invalid login string, too long 'user' username: '******'", c->addr_rem, c->username); username[CALLSIGNLEN_MAX] = 0; rc = client_printf(self, c, "# Invalid username format\r\n"); goto failed_login; } #ifndef FIXED_IOBUFS c->username = hstrdup(username); #else strncpy(c->username, username, sizeof(c->username)); c->username[sizeof(c->username)-1] = 0; #endif c->username_len = strlen(c->username); /* check the username against a static list of disallowed usernames */ for (i = 0; (disallow_login_usernames[i]); i++) { if (strcasecmp(c->username, disallow_login_usernames[i]) == 0) { hlog(LOG_WARNING, "%s: Login by user '%s' not allowed", c->addr_rem, c->username); rc = client_printf(self, c, "# Login by user not allowed\r\n"); goto failed_login; } } /* make sure the callsign is OK on the APRS-IS */ if (check_invalid_q_callsign(c->username, c->username_len)) { hlog(LOG_WARNING, "%s: Invalid login string, invalid 'user': '******'", c->addr_rem, c->username); rc = client_printf(self, c, "# Invalid username format\r\n"); goto failed_login; } int given_passcode = -1; for (i = 2; i < argc; i++) { if (strcasecmp(argv[i], "pass") == 0) { if (++i >= argc) { hlog(LOG_WARNING, "%s/%s: No passcode after pass command", c->addr_rem, username); break; } given_passcode = atoi(argv[i]); if (given_passcode >= 0) if (given_passcode == aprs_passcode(c->username)) c->validated = 1; } else if (strcasecmp(argv[i], "vers") == 0) { /* Collect application name and version separately. * Some clients only give out application name but * no version. If those same applications do try to * use filter or udp, the filter/udp keyword will end * up as the version number. So good luck with that. */ if (i+1 >= argc) { hlog(LOG_INFO, "%s/%s: No application name after 'vers' in login", c->addr_rem, username); break; } login_set_app_name(c, argv[i+1], (i+2 < argc) ? argv[i+2] : ""); i += 2; } else if (strcasecmp(argv[i], "udp") == 0) { if (++i >= argc) { hlog(LOG_WARNING, "%s/%s: Missing UDP port number after UDP command", c->addr_rem, username); break; } int udp_port = atoi(argv[i]); if (udp_port < 1024 || udp_port > 65535) { hlog(LOG_WARNING, "%s/%s: UDP port number %s is out of range", c->addr_rem, username, argv[i]); break; } if (login_setup_udp_feed(c, udp_port) != 0) { /* Sorry, no UDP service for this port.. */ hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, username); rc = client_printf(self, c, "# No UDP service available on this port\r\n"); if (rc < -2) return rc; // client got destroyed } } else if (strstr(argv[i], "filter")) { /* Follows javaaprssrvr's example - any command having 'filter' in the * end is OK. */ if (!(c->flags & CLFLAGS_USERFILTEROK)) { rc = client_printf(self, c, "# No user-specified filters on this port\r\n"); if (rc < -2) return rc; // client got destroyed break; } /* copy the null-separated filter arguments back to a space-separated * string, for the status page to show */ char *fp = c->filter_s; char *fe = c->filter_s + FILTER_S_SIZE; int f_non_first = 0; while (++i < argc) { int l = strlen(argv[i]); if (fp + l + 2 < fe) { if (f_non_first) { *fp++ = ' '; } memcpy(fp, argv[i], l); fp += l; *fp = 0; f_non_first = 1; } /* parse filters in argv[i] */ rc = filter_parse(c, argv[i], 1); if (rc) { rc = client_printf( self, c, "# Parse errors on filter spec: '%s'\r\n", argv[i]); if (rc < -2) return rc; // The client probably got destroyed! } } } } /* ok, login succeeded, switch handler */ c->handler = &incoming_handler; /* handler of all incoming APRS-IS data during a connection */ rc = client_printf( self, c, "# logresp %s %s, server %s\r\n", username, (c->validated) ? "verified" : "unverified", serverid ); if (rc < -2) return rc; // The client probably got destroyed! c->keepalive = now + keepalive_interval/2 + random() % keepalive_interval; c->state = CSTATE_CONNECTED; hlog(LOG_DEBUG, "%s: login '%s'%s%s%s%s%s%s%s%s", c->addr_rem, username, (c->validated) ? " pass_ok" : "", (!c->validated && given_passcode >= 0) ? " pass_invalid" : "", (given_passcode < 0) ? " pass_none" : "", (c->udp_port) ? " UDP" : "", (c->app_name) ? " app " : "", (c->app_name) ? c->app_name : "", (c->app_version) ? " ver " : "", (c->app_version) ? c->app_version : "" ); /* Add the client to the client list. * * If the client logged in with a valid passcode, check if there are * other validated clients logged in with the same username. * If one is found, it needs to be disconnected. * * The lookup is done while holding the write lock to the clientlist, * instead of a separate lookup call, so that two clients logging in * at exactly the same time won't make it. */ int old_fd = clientlist_add(c); if (c->validated && old_fd != -1) { hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, username); /* The other client may be on another thread, so cannot client_close() it. * There is a small potential race here, if the old client disconnected and * the fd was recycled for another client right after the clientlist check. */ shutdown(old_fd, SHUT_RDWR); } return 0; failed_login: /* if we already lost the client, just return */ if (rc < -2) return rc; c->failed_cmds++; if (c->failed_cmds >= 3) { client_close(self, c, CLIERR_LOGIN_RETRIES); return -3; } return rc; }
static void parse_options(struct ts *ts, int argc, char **argv) { int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, ident_err = 0, port_set = 0; while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { if (j == '?') exit(EXIT_FAILURE); switch (j) { case 'i': // -- ident ts->ident = optarg; break; case 'd': // --daemon ts->pidfile = optarg; break; case 'N': // --notify-program ts->notify_program = optarg; break; case 'S': // --syslog ts->syslog_active = 1; ts->syslog_remote = 0; break; case 'l': // --syslog-host ts->syslog_host = optarg; ts->syslog_active = 1; ts->syslog_remote = 1; break; case 'L': // --syslog-port ts->syslog_port = atoi(optarg); break; case 'F': // --log-file log_filename = optarg; break; case 'I': // --input input_addr_err = !parse_io_param(&ts->input, optarg, O_RDONLY, 0); break; case '1': // --input-source if (!inet_aton(optarg, &ts->input.isrc)) { fprintf(stderr, "ERROR: Can't parse input-source IP address: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'R': // --input-rtp ts->rtp_input = !ts->rtp_input; break; case 'z': // --input-ignore-disc ts->ts_discont = !ts->ts_discont; break; case 'M': // --input-service ts->forced_service_id = strtoul(optarg, NULL, 0) & 0xffff; break; case 'T': // --input-buffer ts->input_buffer_time = strtoul(optarg, NULL, 0); break; case 'W': // --input-dump ts->input_dump_filename = optarg; break; case 'O': // --output output_addr_err = !parse_io_param(&ts->output, optarg, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); break; case 'o': // --output-intf if (strchr(optarg, '.')) inet_aton(optarg, &ts->output.intf); else ts->output.v6_if_index = atoi(optarg); break; case 't': // --output-ttl ts->output.ttl = atoi(optarg); break; case 'r': // --output-rtp ts->rtp_output = 1; break; case 'k': // --output-rtp-ssrc ts->rtp_ssrc = strtoul(optarg, NULL, 0); break; case 'g': // --output-tos ts->output.tos = (uint8_t)strtol(optarg, NULL, 0); break; case 'u': // --no-output-on-error ts->no_output_on_error = !ts->no_output_on_error; break; case 'p': // --no-output-filter ts->pid_filter = !ts->pid_filter; break; case 'y': // --output-nit-pass ts->nit_passthrough = !ts->nit_passthrough; break; case 'w': // --output-eit-pass ts->eit_passthrough = !ts->eit_passthrough; break; case 'x': // --output-tdt-pass ts->tdt_passthrough = !ts->tdt_passthrough; break; case 'c': // --ca-system if (strcasecmp("IRDETO", optarg) == 0) ts->req_CA_sys = CA_IRDETO; else if (strcasecmp("CONNAX", optarg) == 0 || strcasecmp("CONAX", optarg) == 0) ts->req_CA_sys = CA_CONAX; else if (strcasecmp("CRYPTOWORKS", optarg) == 0) ts->req_CA_sys = CA_CRYPTOWORKS; else if (strcasecmp("SECA", optarg) == 0 || strcasecmp("MEDIAGUARD", optarg) == 0) ts->req_CA_sys = CA_SECA; else if (strcasecmp("VIACCESS", optarg) == 0) ts->req_CA_sys = CA_VIACCESS; else if (strcasecmp("VIDEOGUARD", optarg) == 0 || strcasecmp("NDS", optarg) == 0) ts->req_CA_sys = CA_VIDEOGUARD; else if (strcasecmp("NAGRA", optarg) == 0) ts->req_CA_sys = CA_NAGRA; else if (strcasecmp("DRE-CRYPT", optarg) == 0 || strcasecmp("DRECRYPT", optarg) == 0) ts->req_CA_sys = CA_DRECRYPT; else if (strcasecmp("BULCRYPT", optarg) == 0) ts->req_CA_sys = CA_BULCRYPT; else if (strcasecmp("GRIFFIN", optarg) == 0) ts->req_CA_sys = CA_GRIFFIN; else if (strcasecmp("DGCRYPT", optarg) == 0) ts->req_CA_sys = CA_DGCRYPT; else ca_err = 1; break; case 'C': // --caid ts->forced_caid = strtoul(optarg, NULL, 0) & 0xffff; break; case 'Y': // --const-cw ts->camd.constant_codeword = 1; if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x') optarg += 2; if (strlen(optarg) != CODEWORD_LENGTH * 2) { fprintf(stderr, "ERROR: Constant code word should be %u characters long.\n", CODEWORD_LENGTH * 2); exit(EXIT_FAILURE); } if (decode_hex_string(optarg, ts->camd.key->cw, strlen(optarg)) < 0) { fprintf(stderr, "ERROR: Invalid hex string for constant code word: %s\n", optarg); exit(EXIT_FAILURE); } camd_set_cw(ts, ts->camd.key->cw, 0); ts->camd.key->is_valid_cw = 1; break; case 'Q': // --biss-key ts->camd.constant_codeword = 1; if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x') optarg += 2; uint8_t *key = ts->camd.key->cw; // Sometimes the BISS keys are entered with their checksums already calculated (16 symbols, 8 bytes) // This is the same as constant cw with the same key for even and odd if (strlen(optarg) == (BISSKEY_LENGTH + 2) * 2) { if (decode_hex_string(optarg, key, strlen(optarg)) < 0) { fprintf(stderr, "ERROR: Invalid hex string for BISS key: %s\n", optarg); exit(EXIT_FAILURE); } } else { // BISS key without checksum (12 symbols, 6 bytes) if (strlen(optarg) != BISSKEY_LENGTH * 2) { fprintf(stderr, "ERROR: BISS key should be %u characters long.\n", BISSKEY_LENGTH * 2); exit(EXIT_FAILURE); } if (decode_hex_string(optarg, key, strlen(optarg)) < 0) { fprintf(stderr, "ERROR: Invalid hex string for BISS key: %s\n", optarg); exit(EXIT_FAILURE); } // Calculate BISS KEY crc memmove(key + 4, key + 3, 3); key[3] = (uint8_t)(key[0] + key[1] + key[2]); key[7] = (uint8_t)(key[4] + key[5] + key[6]); } // Even and odd keys are the same memcpy(key + 8, key, 8); camd_set_cw(ts, ts->camd.key->cw, 0); ts->camd.key->is_valid_cw = 1; break; case 'A': // --camd-proto if (strcasecmp(optarg, "cs378x") == 0) { camd_proto_cs378x(&ts->camd.ops); } else if (strcasecmp(optarg, "newcamd") == 0) { camd_proto_newcamd(&ts->camd.ops); } else { fprintf(stderr, "Unknown CAMD protocol: %s\n", optarg); exit(EXIT_FAILURE); } break; case 's': // --camd-server server_err = !parse_host_and_port(optarg, &ts->camd.hostname, &ts->camd.service, &port_set); break; case 'U': // --camd-user if (strlen(optarg) < 64) ts->camd.user = optarg; break; case 'P': // --camd-pass ts->camd.pass = optarg; break; case 'B': // --camd-des-key if (strlen(optarg) > 2 && optarg[0] == '0' && optarg[1] == 'x') optarg += 2; if (strlen(optarg) != DESKEY_LENGTH) { fprintf(stderr, "ERROR: des key should be %u characters long.\n", DESKEY_LENGTH); exit(EXIT_FAILURE); } strncpy(ts->camd.newcamd.hex_des_key, optarg, sizeof(ts->camd.newcamd.hex_des_key) - 1); ts->camd.newcamd.hex_des_key[sizeof(ts->camd.newcamd.hex_des_key) - 1] = 0; break; case '4': // --ipv4 ai_family = AF_INET; break; case '6': // --ipv6 ai_family = AF_INET6; break; case 'e': // --emm ts->process_emm = !ts->process_emm; break; case 'Z': // --emm-pid ts->forced_emm_pid = strtoul(optarg, NULL, 0) & 0x1fff; break; case 'E': // --emm-only ts->process_emm = 1; ts->process_ecm = 0; ts->output_stream = 0; break; case 'f': // --emm-report-time ts->emm_report_interval = strtoul(optarg, NULL, 10); if (ts->emm_report_interval > 86400) ts->emm_report_interval = 86400; break; case 'a': // --emm-filter if (ts->emm_filters_num + 1 > MAX_FILTERS) { fprintf(stderr, "ERROR: Maximum allowed filters are %d.\n", MAX_FILTERS); exit(EXIT_FAILURE); } if (filter_parse(optarg, &ts->emm_filters[ts->emm_filters_num])) { ts->emm_filters_num++; } else { fprintf(stderr, "ERROR: Can't parse EMM filter: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'X': // --ecm-pid ts->forced_ecm_pid = strtoul(optarg, NULL, 0) & 0x1fff; break; case 'v': // --ecm-only ts->process_emm = 0; ts->process_ecm = 1; ts->output_stream = 0; break; case 'H': // --ecm-report-time ts->ecm_report_interval = strtoul(optarg, NULL, 10); if (ts->ecm_report_interval > 86400) ts->ecm_report_interval = 86400; break; case 'G': // --ecm-irdeto-type ts->irdeto_ecm_idx = strtoul(optarg, NULL, 0); ts->irdeto_ecm_filter_type = IRDETO_FILTER_IDX; break; case '2': // --ecm-irdeto-chid ts->irdeto_ecm_chid = strtoul(optarg, NULL, 0); ts->irdeto_ecm_filter_type = IRDETO_FILTER_CHID; break; case 'K': // --ecm-no-log ts->ecm_cw_log = !ts->ecm_cw_log; break; case 'J': // --cw-warn-time ts->cw_warn_sec = strtoul(optarg, NULL, 10); if (ts->cw_warn_sec > 86400) ts->cw_warn_sec = 86400; ts->cw_last_warn= ts->cw_last_warn + ts->cw_warn_sec; break; case 'q': // --ecm-and-emm-only ts->process_emm = 1; ts->process_ecm = 1; ts->output_stream = 0; break; case 'D': // --debug ts->debug_level = atoi(optarg); if (ts->debug_level > 0) ts->pid_report = 1; break; case 'j': // --pid-report ts->pid_report = 1; break; case 'b': // --bench csa_benchmark(); exit(EXIT_SUCCESS); case 'n': // --ecm-file case 'm': // --emm-file packet_from_file = 1; packet_buflen = file_hex2buf(optarg, packet_buf, sizeof(packet_buf)); if (!packet_buflen) { fprintf(stderr, "ERROR: Can't init packet from file.\n"); exit(1); } packet_type = j == 'n' ? ECM_MSG : EMM_MSG; break; case 'h': // --help show_help(ts); exit(EXIT_SUCCESS); case 'V': // --version printf("%s\n", program_id); exit(EXIT_SUCCESS); } } if (!ts->ident) { if (ts->syslog_active || ts->notify_program) ident_err = 1; } if (packet_from_file) { int err = 0; if (!ts->forced_caid) { fprintf(stderr, "ERROR: CAID was not set. Use --caid option.\n"); err++; } if (!ts->forced_service_id) { fprintf(stderr, "ERROR: Service id was not set. Use --input-service option.\n"); err++; } if (err) exit(EXIT_FAILURE); ts->threaded = 0; input_addr_err = 0; output_addr_err = 0; ts->input.type = FILE_IO; ts->input.fd = 0; ts->output.type = FILE_IO; ts->output.fd = 1; ts->pid_filter = 0; ts->process_ecm = 0; ts->process_emm = 0; ts->output_stream = 0; ts->camd.no_reconnect = 1; ts->camd.check_emm_errors = 1; ts->emm_filters_num = 0; } // Constant codeword is special. Disable conflicting options if (ts->camd.constant_codeword) { server_err = 0; // No server settings are required ts->process_ecm = 0; ts->process_emm = 0; ts->output_stream = 1; } if (ident_err || ca_err || server_err || input_addr_err || output_addr_err || ts->input.type == WTF_IO || ts->output.type == WTF_IO) { show_help(ts); if (ident_err) fprintf(stderr, "ERROR: Ident is not set, please use --ident option.\n"); if (ca_err) fprintf(stderr, "ERROR: Requested CA system is unsupported.\n"); if (server_err) fprintf(stderr, "ERROR: CAMD server address is not set or it is invalid.\n"); if (input_addr_err) fprintf(stderr, "ERROR: Input address is invalid.\n"); if (output_addr_err) fprintf(stderr, "ERROR: Output address is invalid.\n"); exit(EXIT_FAILURE); } if (decode_hex_string(ts->camd.newcamd.hex_des_key, ts->camd.newcamd.bin_des_key, DESKEY_LENGTH) < 0) { fprintf(stderr, "ERROR: Invalid hex string for des key: %s\n", ts->camd.newcamd.hex_des_key); exit(EXIT_FAILURE); } if (ts->camd.ops.proto == CAMD_NEWCAMD && !port_set) { fprintf(stderr, "ERROR: CAMD server port is not set. Use --camd-server %s:xxxx to set the port.\n", ts->camd.hostname); exit(EXIT_FAILURE); } if (log_filename) { log_file = fopen(log_filename, "a"); if (!log_file) { fprintf(stderr, "ERROR: Can't open log file %s: %s\n", log_filename, strerror(errno)); exit(EXIT_FAILURE); } } if (ts->ident) ts_LOGf("Ident : %s\n", ts->ident); if (ts->notify_program) ts_LOGf("Notify prg : %s\n", ts->notify_program); if (ts->pidfile) ts_LOGf("Daemonize : %s pid file.\n", ts->pidfile); if (ts->syslog_active) { if (ts->syslog_remote) ts_LOGf("Syslog : %s:%d\n", ts->syslog_host, ts->syslog_port); else ts_LOGf("Syslog : enabled\n"); } else { if (!packet_from_file) ts_LOGf("Syslog : disabled\n"); } if (!ts->camd.constant_codeword) { if (ts->forced_caid) ts->req_CA_sys = ts_get_CA_sys(ts->forced_caid); if (!ts->forced_caid) ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(ts->req_CA_sys)); else ts_LOGf("CA System : %s | CAID: 0x%04x (%d)\n", ts_get_CA_sys_txt(ts->req_CA_sys), ts->forced_caid, ts->forced_caid); } else { char cw_even[64], cw_odd[64]; ts_hex_dump_buf(cw_even, sizeof(cw_even), ts->key.cw , 8, 0); ts_hex_dump_buf(cw_odd , sizeof(cw_odd ), ts->key.cw + 8, 8, 0); ts_LOGf("Constant CW: even = %s\n", cw_even); ts_LOGf("Constant CW: odd = %s\n", cw_odd); } if (ts->input.type == NET_IO) { ts_LOGf("Input addr : %s://%s:%s/\n", ts->rtp_input ? "rtp" : "udp", ts->input.hostname, ts->input.service); ts_LOGf("Input src : %s\n", inet_ntoa(ts->input.isrc)); if (ts->input_buffer_time) { ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time); } } else if (ts->input.type == FILE_IO) { if (!packet_from_file) ts_LOGf("Input file : %s\n", ts->input.fd == 0 ? "STDIN" : ts->input.fname); } if (ts->input_dump_filename) { ts->input_dump_file = fopen(ts->input_dump_filename, "w"); if (ts->input_dump_file) ts_LOGf("Input dump : %s\n", ts->input_dump_filename); else ts_LOGf("Input dump : %s | ERROR: %s\n", ts->input_dump_filename, strerror(errno)); } if (ts->forced_service_id) ts_LOGf("Service id : 0x%04x (%d)\n", ts->forced_service_id, ts->forced_service_id); if (ts->req_CA_sys == CA_IRDETO) { switch (ts->irdeto_ecm_filter_type) { case IRDETO_FILTER_IDX : ts_LOGf("Irdeto ECM : Index: 0x%02x (%d)\n", ts->irdeto_ecm_idx, ts->irdeto_ecm_idx); break; case IRDETO_FILTER_CHID: ts_LOGf("Irdeto ECM : CHID: 0x%04x (%d)\n", ts->irdeto_ecm_chid, ts->irdeto_ecm_chid); break; } } if (ts->output_stream) { if (ts->output.type == NET_IO) { ts_LOGf("Output addr: %s://%s:%s/\n", ts->rtp_output ? "rtp" : "udp", ts->output.hostname, ts->output.service); ts_LOGf("Output intf: %s (IPv6 intf index:%d)\n", inet_ntoa(ts->output.intf), ts->output.v6_if_index); ts_LOGf("Output ttl : %d\n", ts->output.ttl); if (ts->output.tos > -1) ts_LOGf("Output TOS : %u (0x%02x)\n", ts->output.tos, ts->output.tos); if (ts->rtp_output) { ts_LOGf("RTP SSRC : %u (0x%04x)\n", ts->rtp_ssrc, ts->rtp_ssrc); // It is recommended that RTP seqnum starts with random number RAND_bytes((unsigned char *)&(ts->rtp_seqnum), 2); } } else if (ts->output.type == FILE_IO) { ts_LOGf("Output file: %s\n", ts->output.fd == 1 ? "STDOUT" : ts->output.fname); } ts_LOGf("Out filter : %s (%s)%s\n", ts->pid_filter ? "enabled" : "disabled", ts->pid_filter ? "output only service related PIDs" : "output everything", ts->no_output_on_error ? " (No output on CW error)" : "" ); if (ts->pid_filter) { if (ts->nit_passthrough) ts_LOGf("Out filter : Pass through NIT.\n"); if (ts->eit_passthrough) ts_LOGf("Out filter : Pass through EIT (EPG).\n"); if (ts->tdt_passthrough) ts_LOGf("Out filter : Pass through TDT/TOT.\n"); } ts_LOGf("TS discont : %s\n", ts->ts_discont ? "report" : "ignore"); ts->threaded = !(ts->input.type == FILE_IO && ts->input.fd != 0); ts_LOGf("Decoding : %s\n", ts->threaded ? "threaded" : "single thread"); } else { ts_LOGf("Decoding : disabled\n"); } if (!ts->camd.constant_codeword) { ts_LOGf("CAMD proto : %s\n", ts->camd.ops.ident); ts_LOGf("CAMD addr : %s:%s%s\n", ts->camd.hostname, ts->camd.service, ai_family == AF_INET ? " (IPv4 only)" : ai_family == AF_INET6 ? " (IPv6 only)" : " (IPv4/IPv6)" ); ts_LOGf("CAMD user : %s\n", ts->camd.user); ts_LOGf("CAMD pass : %s\n", ts->camd.pass); if (ts->camd.ops.proto == CAMD_NEWCAMD) ts_LOGf("CAMD deskey: %s\n", ts->camd.newcamd.hex_des_key); } if (!packet_from_file) ts_LOGf("EMM process: %s\n", ts->process_emm ? "Yes" : "No"); if (ts->process_emm) { if (ts->forced_emm_pid) ts_LOGf("EMM pid : 0x%04x (%d)\n", ts->forced_emm_pid, ts->forced_emm_pid); if (ts->emm_report_interval) ts_LOGf("EMM report : %d sec\n", ts->emm_report_interval); else ts_LOGf("EMM report : disabled\n"); for (i = 0; i < ts->emm_filters_num; i++) { char tmp[512]; filter_dump(&ts->emm_filters[i], tmp, sizeof(tmp)); ts_LOGf("EMM filter : [%2d] %s\n", i + 1, tmp); } } if (!packet_from_file) ts_LOGf("ECM process: %s\n", ts->process_ecm ? "Yes" : "No"); if (ts->process_ecm) { if (ts->forced_ecm_pid) ts_LOGf("ECM pid : 0x%04x (%d)\n", ts->forced_ecm_pid, ts->forced_ecm_pid); if (ts->ecm_report_interval) ts_LOGf("ECM report : %d sec\n", ts->emm_report_interval); else ts_LOGf("ECM report : disabled\n"); if (ts->cw_warn_sec) ts_LOGf("CW warning : %d sec\n", ts->cw_warn_sec); else ts_LOGf("CW warning : disabled\n"); if (!ts->ecm_cw_log) ts_LOGf("ECM/CW log : disabled\n"); } if (ts->ident) { int len = strlen(ts->ident); for (i = 0; i < len; i++) { if (ts->ident[i] == '/') ts->ident[i] = '-'; } } }
int main (int argc, char **argv, char **envp) { cache_entry *cache_rules = NULL; lf_file_references file_references = lf_include_references; decode_table *decode_rules = NULL; insn_table *isa = NULL; gen_table *gen = NULL; char *real_file_name = NULL; int is_header = 0; int ch; lf *standard_out = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "igen"); INIT_OPTIONS (); if (argc == 1) { printf ("Usage:\n"); printf ("\n"); printf (" igen <config-opts> ... <input-opts>... <output-opts>...\n"); printf ("\n"); printf ("Config options:\n"); printf ("\n"); printf (" -B <bit-size>\n"); printf ("\t Set the number of bits in an instruction (depreciated).\n"); printf ("\t This option can now be set directly in the instruction table.\n"); printf ("\n"); printf (" -D <data-structure>\n"); printf ("\t Dump the specified data structure to stdout. Valid structures include:\n"); printf ("\t processor-names - list the names of all the processors (models)\n"); printf ("\n"); printf (" -F <filter-list>\n"); printf ("\t Filter out any instructions with a non-empty flags field that contains\n"); printf ("\t a flag not listed in the <filter-list>.\n"); printf ("\n"); printf (" -H <high-bit>\n"); printf ("\t Set the number of the high (most significant) instruction bit (depreciated).\n"); printf ("\t This option can now be set directly in the instruction table.\n"); printf ("\n"); printf (" -I <directory>\n"); printf ("\t Add <directory> to the list of directories searched when opening a file\n"); printf ("\n"); printf (" -M <model-list>\n"); printf ("\t Filter out any instructions that do not support at least one of the listed\n"); printf ("\t models (An instructions with no model information is considered to support\n"); printf ("\t all models.).\n"); printf ("\n"); printf (" -N <nr-cpus>\n"); printf ("\t Generate a simulator supporting <nr-cpus>\n"); printf ("\t Specify `-N 0' to disable generation of the SMP. Specifying `-N 1' will\n"); printf ("\t still generate an SMP enabled simulator but will only support one CPU.\n"); printf ("\n"); printf (" -T <mechanism>\n"); printf ("\t Override the decode mechanism specified by the decode rules\n"); printf ("\n"); printf (" -P <prefix>\n"); printf ("\t Prepend global names (except itable) with the string <prefix>.\n"); printf ("\t Specify -P <module>=<prefix> to set a specific <module>'s prefix.\n"); printf ("\n"); printf (" -S <suffix>\n"); printf ("\t Replace a global name (suffix) (except itable) with the string <suffix>.\n"); printf ("\t Specify -S <module>=<suffix> to change a specific <module>'s name (suffix).\n"); printf ("\n"); printf (" -Werror\n"); printf ("\t Make warnings errors\n"); printf (" -Wnodiscard\n"); printf ("\t Suppress warnings about discarded functions and instructions\n"); printf (" -Wnowidth\n"); printf ("\t Suppress warnings about instructions with invalid widths\n"); printf (" -Wnounimplemented\n"); printf ("\t Suppress warnings about unimplemented instructions\n"); printf ("\n"); printf (" -G [!]<gen-option>\n"); printf ("\t Any of the following options:\n"); printf ("\n"); printf ("\t decode-duplicate - Override the decode rules, forcing the duplication of\n"); printf ("\t semantic functions\n"); printf ("\t decode-combine - Combine any duplicated entries within a table\n"); printf ("\t decode-zero-reserved - Override the decode rules, forcing reserved bits to be\n"); printf ("\t treated as zero.\n"); printf ("\t decode-switch-is-goto - Overfide the padded-switch code type as a goto-switch\n"); printf ("\n"); printf ("\t gen-conditional-issue - conditionally issue each instruction\n"); printf ("\t gen-delayed-branch - need both cia and nia passed around\n"); printf ("\t gen-direct-access - use #defines to directly access values\n"); printf ("\t gen-zero-r<N> - arch assumes GPR(<N>) == 0, keep it that way\n"); printf ("\t gen-icache[=<N> - generate an instruction cracking cache of size <N>\n"); printf ("\t Default size is %d\n", options.gen.icache_size); printf ("\t gen-insn-in-icache - save original instruction when cracking\n"); printf ("\t gen-multi-sim[=MODEL] - generate multiple simulators - one per model\n"); printf ("\t If specified MODEL is made the default architecture.\n"); printf ("\t By default, a single simulator that will\n"); printf ("\t execute any instruction is generated\n"); printf ("\t gen-multi-word - generate code allowing for multi-word insns\n"); printf ("\t gen-semantic-icache - include semantic code in cracking functions\n"); printf ("\t gen-slot-verification - perform slot verification as part of decode\n"); printf ("\t gen-nia-invalid - NIA defaults to nia_invalid\n"); printf ("\t gen-nia-void - do not compute/return NIA\n"); printf ("\n"); printf ("\t trace-combine - report combined entries a rule application\n"); printf ("\t trace-entries - report entries after a rules application\n"); printf ("\t trace-rule-rejection - report each rule as rejected\n"); printf ("\t trace-rule-selection - report each rule as selected\n"); printf ("\t trace-insn-insertion - report each instruction as it is inserted into a decode table\n"); printf ("\t trace-rule-expansion - report each instruction as it is expanded (before insertion into a decode table)\n"); printf ("\t trace-all - enable all trace options\n"); printf ("\n"); printf ("\t field-widths - instruction formats specify widths (depreciated)\n"); printf ("\t By default, an instruction format specifies bit\n"); printf ("\t positions\n"); printf ("\t This option can now be set directly in the\n"); printf ("\t instruction table\n"); printf ("\t jumps - use jumps instead of function calls\n"); printf ("\t omit-line-numbers - do not include line number information in the output\n"); printf ("\n"); printf ("Input options:\n"); printf ("\n"); printf (" -k <cache-rules> (depreciated)\n"); printf (" -o <decode-rules>\n"); printf (" -i <instruction-table>\n"); printf ("\n"); printf ("Output options:\n"); printf ("\n"); printf (" -x Perform expansion (required)\n"); printf (" -n <real-name> Specify the real name of the next output file\n"); printf (" -h Generate the header (.h) file rather than the body (.c)\n"); printf (" -c <output-file> output icache\n"); printf (" -d <output-file> output idecode\n"); printf (" -e <output-file> output engine\n"); printf (" -f <output-file> output support functions\n"); printf (" -m <output-file> output model\n"); printf (" -r <output-file> output multi-sim run\n"); printf (" -s <output-file> output schematic\n"); printf (" -t <output-file> output itable\n"); } while ((ch = getopt(argc, argv, "B:D:F:G:H:I:M:N:P:T:W:o:k:i:n:hc:d:e:m:r:s:t:f:x")) != -1) { fprintf (stderr, " -%c ", ch); if (optarg) fprintf (stderr, "%s ", optarg); fprintf (stderr, "\\\n"); switch(ch) { case 'M': filter_parse (&options.model_filter, optarg); break; case 'D': if (strcmp (optarg, "processor-names")) { char *processor; for (processor = filter_next (options.model_filter, ""); processor != NULL; processor = filter_next (options.model_filter, processor)) lf_printf (standard_out, "%s\n", processor); } else error (NULL, "Unknown data structure %s, not dumped\n", optarg); break; case 'F': filter_parse (&options.flags_filter, optarg); break; case 'I': { table_include **dir = &options.include; while ((*dir) != NULL) dir = &(*dir)->next; (*dir) = ZALLOC (table_include); (*dir)->dir = strdup (optarg); } break; case 'B': options.insn_bit_size = a2i (optarg); if (options.insn_bit_size <= 0 || options.insn_bit_size > max_insn_bit_size) { error (NULL, "Instruction bitsize must be in range 1..%d\n", max_insn_bit_size); } if (options.hi_bit_nr != options.insn_bit_size - 1 && options.hi_bit_nr != 0) { error (NULL, "Conflict betweem hi-bit-nr and insn-bit-size\n"); } break; case 'H': options.hi_bit_nr = a2i (optarg); if (options.hi_bit_nr != options.insn_bit_size - 1 && options.hi_bit_nr != 0) { error (NULL, "Conflict between hi-bit-nr and insn-bit-size\n"); } break; case 'N': options.gen.smp = a2i (optarg); break; case 'P': case 'S': { igen_module *names; igen_name *name; char *chp; chp = strchr (optarg, '='); if (chp == NULL) { names = &options.module.global; chp = optarg; } else { chp = chp + 1; /* skip `=' */ names = NULL; if (strncmp (optarg, "global=", chp - optarg) == 0) { names = &options.module.global; } if (strncmp (optarg, "engine=", chp - optarg) == 0) { names = &options.module.engine; } if (strncmp (optarg, "icache=", chp - optarg) == 0) { names = &options.module.icache; } if (strncmp (optarg, "idecode=", chp - optarg) == 0) { names = &options.module.idecode; } if (strncmp (optarg, "itable=", chp - optarg) == 0) { names = &options.module.itable; } if (strncmp (optarg, "semantics=", chp - optarg) == 0) { names = &options.module.semantics; } if (strncmp (optarg, "support=", chp - optarg) == 0) { names = &options.module.support; } if (names == NULL) { error (NULL, "Prefix `%s' unreconized\n", optarg); } } switch (ch) { case 'P': name = &names->prefix; break; case 'S': name = &names->suffix; break; } name->u = strdup (chp); name->l = strdup (chp); chp = name->u; while (*chp) { if (islower(*chp)) *chp = toupper(*chp); chp++; } if (name == &options.module.global.prefix) { options.module.engine.prefix = options.module.global.prefix; options.module.icache.prefix = options.module.global.prefix; options.module.idecode.prefix = options.module.global.prefix; /* options.module.itable.prefix = options.module.global.prefix; */ options.module.semantics.prefix = options.module.global.prefix; options.module.support.prefix = options.module.global.prefix; } if (name == &options.module.global.suffix) { options.module.engine.suffix = options.module.global.suffix; options.module.icache.suffix = options.module.global.suffix; options.module.idecode.suffix = options.module.global.suffix; /* options.module.itable.suffix = options.module.global.suffix; */ options.module.semantics.suffix = options.module.global.suffix; options.module.support.suffix = options.module.global.suffix; } break; } case 'W': { if (strcmp (optarg, "error") == 0) options.warning = error; else if (strcmp (optarg, "nodiscard") == 0) options.warn.discard = 0; else if (strcmp (optarg, "discard") == 0) options.warn.discard = 1; else if (strcmp (optarg, "nowidth") == 0) options.warn.width = 0; else if (strcmp (optarg, "width") == 0) options.warn.width = 1; else if (strcmp (optarg, "nounimplemented") == 0) options.warn.unimplemented = 0; else if (strcmp (optarg, "unimplemented") == 0) options.warn.unimplemented = 1; else error (NULL, "Unknown -W argument `%s'\n", optarg); break; } case 'G': { int enable_p; char *argp; if (strncmp (optarg, "no-", strlen ("no-")) == 0) { argp = optarg + strlen ("no-"); enable_p = 0; } else if (strncmp (optarg, "!", strlen ("!")) == 0) { argp = optarg + strlen ("no-"); enable_p = 0; } else { argp = optarg; enable_p = 1; } if (strcmp (argp, "decode-duplicate") == 0) { options.decode.duplicate = enable_p; } else if (strcmp (argp, "decode-combine") == 0) { options.decode.combine = enable_p; } else if (strcmp (argp, "decode-zero-reserved") == 0) { options.decode.zero_reserved = enable_p; } else if (strcmp (argp, "gen-conditional-issue") == 0) { options.gen.conditional_issue = enable_p; } else if (strcmp (argp, "conditional-issue") == 0) { options.gen.conditional_issue = enable_p; options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n"); } else if (strcmp (argp, "gen-delayed-branch") == 0) { options.gen.delayed_branch = enable_p; } else if (strcmp (argp, "delayed-branch") == 0) { options.gen.delayed_branch = enable_p; options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n"); } else if (strcmp (argp, "gen-direct-access") == 0) { options.gen.direct_access = enable_p; } else if (strcmp (argp, "direct-access") == 0) { options.gen.direct_access = enable_p; options.warning (NULL, "Option direct-access replaced by gen-direct-access\n"); } else if (strncmp (argp, "gen-zero-r", strlen ("gen-zero-r")) == 0) { options.gen.zero_reg = enable_p; options.gen.zero_reg_nr = atoi (argp + strlen ("gen-zero-r")); } else if (strncmp (argp, "zero-r", strlen ("zero-r")) == 0) { options.gen.zero_reg = enable_p; options.gen.zero_reg_nr = atoi (argp + strlen ("zero-r")); options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n"); } else if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0) { switch (argp[strlen ("gen-icache")]) { case '=': options.gen.icache_size = atoi (argp + strlen ("gen-icache") + 1); options.gen.icache = enable_p; break; case '\0': options.gen.icache = enable_p; break; default: error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n"); } } else if (strcmp (argp, "gen-insn-in-icache") == 0) { options.gen.insn_in_icache = enable_p; } else if (strncmp (argp, "gen-multi-sim", strlen ("gen-multi-sim")) == 0) { char *arg = &argp[strlen ("gen-multi-sim")]; switch (arg[0]) { case '=': options.gen.multi_sim = enable_p; options.gen.default_model = arg + 1; if (! filter_is_member (options.model_filter, options.gen.default_model)) error (NULL, "multi-sim model %s unknown\n", options.gen.default_model); break; case '\0': options.gen.multi_sim = enable_p; options.gen.default_model = NULL; break; default: error (NULL, "Expecting -Ggen-multi-sim or -Ggen-multi-sim=<MODEL>\n"); break; } } else if (strcmp (argp, "gen-multi-word") == 0) { options.gen.multi_word = enable_p; } else if (strcmp (argp, "gen-semantic-icache") == 0) { options.gen.semantic_icache = enable_p; } else if (strcmp (argp, "gen-slot-verification") == 0) { options.gen.slot_verification = enable_p; } else if (strcmp (argp, "verify-slot") == 0) { options.gen.slot_verification = enable_p; options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n"); } else if (strcmp (argp, "gen-nia-invalid") == 0) { options.gen.nia = nia_is_invalid; } else if (strcmp (argp, "default-nia-minus-one") == 0) { options.gen.nia = nia_is_invalid; options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n"); } else if (strcmp (argp, "gen-nia-void") == 0) { options.gen.nia = nia_is_void; } else if (strcmp (argp, "trace-all") == 0) { memset (&options.trace, enable_p, sizeof (options.trace)); } else if (strcmp (argp, "trace-combine") == 0) { options.trace.combine = enable_p; } else if (strcmp (argp, "trace-entries") == 0) { options.trace.entries = enable_p; } else if (strcmp (argp, "trace-rule-rejection") == 0) { options.trace.rule_rejection = enable_p; } else if (strcmp (argp, "trace-rule-selection") == 0) { options.trace.rule_selection = enable_p; } else if (strcmp (argp, "trace-insn-insertion") == 0) { options.trace.insn_insertion = enable_p; } else if (strcmp (argp, "trace-insn-expansion") == 0) { options.trace.insn_expansion = enable_p; } else if (strcmp (argp, "jumps") == 0) { options.gen.code = generate_jumps; } else if (strcmp (argp, "field-widths") == 0) { options.insn_specifying_widths = enable_p; } else if (strcmp (argp, "omit-line-numbers") == 0) { file_references = lf_omit_references; } else { error (NULL, "Unknown option %s\n", optarg); } break; } case 'i': isa = load_insn_table (optarg, cache_rules); if (isa->illegal_insn == NULL) error (NULL, "illegal-instruction missing from insn table\n"); break; case 'x': gen = do_gen (isa, decode_rules); break; case 'o': decode_rules = load_decode_table (optarg); break; case 'k': if (isa != NULL) error (NULL, "Cache file must appear before the insn file\n"); cache_rules = load_cache_table (optarg); break; case 'n': real_file_name = strdup(optarg); break; case 'h': is_header = 1; break; case 'c': case 'd': case 'e': case 'f': case 'm': case 'r': case 's': case 't': { lf *file = lf_open(optarg, real_file_name, file_references, (is_header ? lf_is_h : lf_is_c), argv[0]); if (gen == NULL && ch != 't' && ch != 'm' && ch != 'f') { options.warning (NULL, "Explicitly generate tables with -x option\n"); gen = do_gen (isa, decode_rules); } lf_print__file_start(file); switch (ch) { case 'm': if (is_header) gen_model_h (file, isa); else gen_model_c (file, isa); break; case 't': if (is_header) gen_itable_h (file, isa); else gen_itable_c (file, isa); break; case 'f': if (is_header) gen_support_h (file, isa); else gen_support_c (file, isa); break; case 'r': if (is_header) options.warning (NULL, "-hr option ignored\n"); else gen_run_c (file, gen); break; case 's': if(is_header) gen_semantics_h (file, gen->semantics, isa->max_nr_words); else gen_semantics_c (file, gen->semantics, isa->caches); break; case 'd': if (is_header) gen_idecode_h (file, gen, isa, cache_rules); else gen_idecode_c (file, gen, isa, cache_rules); break; case 'e': if (is_header) gen_engine_h (file, gen, isa, cache_rules); else gen_engine_c (file, gen, isa, cache_rules); break; case 'c': if (is_header) gen_icache_h (file, gen->semantics, isa->functions, isa->max_nr_words); else gen_icache_c (file, gen->semantics, isa->functions, cache_rules); break; } lf_print__file_finish(file); lf_close(file); is_header = 0; } real_file_name = NULL; break; default: ERROR ("Bad switch"); } } return (0); }
struct client_t *accept_client_for_listener(struct listen_t *l, int fd, char *addr_s, union sockaddr_u *sa, unsigned addr_len) { struct client_t *c; char *s; int i; union sockaddr_u sa_loc; /* local address */ socklen_t addr_len_loc = sizeof(sa_loc); c = client_alloc(); if (!c) return NULL; c->fd = fd; c->listener_id = l->listener_id; c->addr = *sa; c->ai_protocol = l->ai_protocol; c->portnum = l->portnum; c->hidden = l->hidden; c->flags = l->client_flags; c->udpclient = client_udp_find(udpclients, sa->sa.sa_family, l->portnum); c->portaccount = l->portaccount; c->last_read = tick; /* not simulated time */ inbound_connects_account(1, c->portaccount); /* account all ports + port-specifics */ /* text format of client's IP address + port */ strncpy(c->addr_rem, addr_s, sizeof(c->addr_rem)); c->addr_rem[sizeof(c->addr_rem)-1] = 0; /* hex format of client's IP address + port */ s = hexsockaddr( &sa->sa, addr_len ); strncpy(c->addr_hex, s, sizeof(c->addr_hex)); c->addr_hex[sizeof(c->addr_hex)-1] = 0; hfree(s); /* text format of servers' connected IP address + port */ if (getsockname(fd, &sa_loc.sa, &addr_len_loc) == 0) { /* Fails very rarely.. */ if (addr_len_loc > sizeof(sa_loc)) hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s truncated local address of %d to %d bytes", c->addr_rem, addr_len_loc, sizeof(sa_loc)); /* present my socket end address as a malloced string... */ s = strsockaddr( &sa_loc.sa, addr_len_loc ); } else { s = hstrdup( l->addr_s ); /* Server's bound IP address */ hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s failed: %s (using '%s' instead)", c->addr_rem, strerror(errno), s); } strncpy(c->addr_loc, s, sizeof(c->addr_loc)); c->addr_loc[sizeof(c->addr_loc)-1] = 0; hfree(s); /* apply predefined filters */ for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) { if (l->filters[i]) { if (filter_parse(c, l->filters[i], 0) < 0) { /* system filters */ hlog(LOG_ERR, "Bad system filter definition: %s", l->filters[i]); } } } if (l->filter_s) { strncpy(c->filter_s, l->filter_s, sizeof(c->filter_s)); c->filter_s[FILTER_S_SIZE-1] = 0; } return c; }
static int accept_liveupgrade_single(cJSON *client, int *rxerr_map, int rxerr_map_len) { cJSON *fd, *listener_id, *username, *time_connect, *tick_connect; cJSON *state; cJSON *addr_loc; cJSON *udp_port; cJSON *app_name, *app_version; cJSON *verified; cJSON *obuf_q; cJSON *bytes_rx, *bytes_tx; cJSON *pkts_rx, *pkts_tx, *pkts_ign; cJSON *rx_errs; cJSON *filter; cJSON *ibuf, *obuf; cJSON *client_heard; cJSON *lat, *lng; unsigned addr_len; union sockaddr_u sa; char *argv[256]; int i, argc; const char *username_s = "unknown"; /* get username first, so we can log it later */ username = accept_liveupgrade_cJSON_get(client, "username", cJSON_String, username_s); if (username) username_s = username->valuestring; fd = accept_liveupgrade_cJSON_get(client, "fd", cJSON_Number, username_s); int fd_i = -1; if (fd) fd_i = fd->valueint; if (fd_i < 0) { hlog(LOG_INFO, "Live upgrade: Client '%s' has negative fd %d, ignoring (corepeer?)", username_s, fd_i); return -1; } listener_id = accept_liveupgrade_cJSON_get(client, "listener_id", cJSON_Number, username_s); state = accept_liveupgrade_cJSON_get(client, "state", cJSON_String, username_s); time_connect = accept_liveupgrade_cJSON_get(client, "t_connect", cJSON_Number, username_s); addr_loc = accept_liveupgrade_cJSON_get(client, "addr_loc", cJSON_String, username_s); app_name = accept_liveupgrade_cJSON_get(client, "app_name", cJSON_String, username_s); app_version = accept_liveupgrade_cJSON_get(client, "app_version", cJSON_String, username_s); verified = accept_liveupgrade_cJSON_get(client, "verified", cJSON_Number, username_s); obuf_q = accept_liveupgrade_cJSON_get(client, "obuf_q", cJSON_Number, username_s); bytes_rx = accept_liveupgrade_cJSON_get(client, "bytes_rx", cJSON_Number, username_s); bytes_tx = accept_liveupgrade_cJSON_get(client, "bytes_tx", cJSON_Number, username_s); pkts_rx = accept_liveupgrade_cJSON_get(client, "pkts_rx", cJSON_Number, username_s); pkts_tx = accept_liveupgrade_cJSON_get(client, "pkts_tx", cJSON_Number, username_s); pkts_ign = accept_liveupgrade_cJSON_get(client, "pkts_ign", cJSON_Number, username_s); rx_errs = accept_liveupgrade_cJSON_get(client, "rx_errs", cJSON_Array, username_s); filter = accept_liveupgrade_cJSON_get(client, "filter", cJSON_String, username_s); /* optional */ tick_connect = cJSON_GetObjectItem(client, "t_connect_tick"); udp_port = cJSON_GetObjectItem(client, "udp_port"); ibuf = cJSON_GetObjectItem(client, "ibuf"); obuf = cJSON_GetObjectItem(client, "obuf"); client_heard = cJSON_GetObjectItem(client, "client_heard"); lat = cJSON_GetObjectItem(client, "lat"); lng = cJSON_GetObjectItem(client, "lng"); if (!( (fd) && (listener_id) && (state) && (username) && (time_connect) && (addr_loc) && (app_name) && (app_version) && (verified) && (obuf_q) && (bytes_rx) && (bytes_tx) && (pkts_rx) && (pkts_tx) && (pkts_ign) && (rx_errs) && (filter) )) { hlog(LOG_ERR, "Live upgrade: Fields missing from client JSON, discarding client fd %d", fd_i); if (fd_i >= 0) close(fd_i); return -1; } hlog(LOG_DEBUG, "Old client on fd %d: %s", fd->valueint, username->valuestring); /* fetch peer address from the fd instead of parsing it from text */ addr_len = sizeof(sa); if (getpeername(fd->valueint, &sa.sa, &addr_len) != 0) { /* Sometimes clients disconnect during upgrade, especially on slow RPi servers... */ if (errno == ENOTCONN) hlog(LOG_INFO, "Live upgrade: Client %s on fd %d has disconnected during upgrade (%s)", username->valuestring, fd->valueint, strerror(errno)); else hlog(LOG_ERR, "Live upgrade: getpeername client fd %d failed: %s", fd->valueint, strerror(errno)); close(fd->valueint); return -1; } /* convert client address to string */ char *client_addr_s = strsockaddr( &sa.sa, addr_len ); /* find the right listener for this client, for configuration and accounting */ struct listen_t *l = liveupgrade_find_listener(listener_id->valueint); if (!l) { hlog(LOG_INFO, "Live upgrade: Listener has been removed for fd %d (%s - local %s): disconnecting %s", fd->valueint, client_addr_s, addr_loc->valuestring, username->valuestring); close(fd->valueint); hfree(client_addr_s); return -1; } struct client_t *c = accept_client_for_listener(l, fd->valueint, client_addr_s, &sa, addr_len); if (!c) { hlog(LOG_ERR, "Live upgrade - client_alloc returned NULL, too many clients. Denied client %s on fd %d from %s", username->valuestring, fd->valueint, client_addr_s); close(fd->valueint); hfree(client_addr_s); return -1; } hfree(client_addr_s); if (strcmp(state->valuestring, "connected") == 0) { c->state = CSTATE_CONNECTED; c->handler_line_in = &incoming_handler; strncpy(c->username, username->valuestring, sizeof(c->username)); c->username[sizeof(c->username)-1] = 0; c->username_len = strlen(c->username); } else if (strcmp(state->valuestring, "login") == 0) { c->state = CSTATE_LOGIN; c->handler_line_in = &login_handler; } else { hlog(LOG_ERR, "Live upgrade: Client %s is in invalid state '%s' (fd %d)", l->addr_s, state->valuestring, l->fd); goto err; } /* distribute keepalive intervals for the existing old clients * but send them rather sooner than later */ // coverity[dont_call] // squelch warning: not security sensitive use of random(): load distribution c->keepalive = tick + (random() % (keepalive_interval/2)); /* distribute cleanup intervals over the next 2 minutes */ // coverity[dont_call] // squelch warning: not security sensitive use of random(): load distribution c->cleanup = tick + (random() % 120); c->connect_time = time_connect->valueint; /* live upgrade / backward compatibility: upgrading from <= 1.8.2 requires the 'else' path' */ if (tick_connect && tick_connect->type == cJSON_Number) c->connect_tick = tick_connect->valueint; else /* convert to monotonic time */ c->connect_tick = tick - (now - c->connect_time); c->validated = verified->valueint; c->localaccount.rxbytes = bytes_rx->valuedouble; c->localaccount.txbytes = bytes_tx->valuedouble; c->localaccount.rxpackets = pkts_rx->valuedouble; c->localaccount.txpackets = pkts_tx->valuedouble; c->localaccount.rxdrops = pkts_ign->valuedouble; login_set_app_name(c, app_name->valuestring, app_version->valuestring); // handle client's filter setting if (c->flags & CLFLAGS_USERFILTEROK && (filter) && (filter->valuestring) && *(filter->valuestring)) { // archive a copy of the filters, for status display strncpy(c->filter_s, filter->valuestring, FILTER_S_SIZE); c->filter_s[FILTER_S_SIZE-1] = 0; sanitize_ascii_string(c->filter_s); char *f = hstrdup(filter->valuestring); argc = parse_args(argv, f); for (i = 0; i < argc; ++i) { filter_parse(c, argv[i], 1); } hfree(f); } // set up UDP downstream if necessary if (udp_port && udp_port->type == cJSON_Number && udp_port->valueint > 1024 && udp_port->valueint < 65536) { if (login_setup_udp_feed(c, udp_port->valueint) != 0) { hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, c->username); } } // fill up ibuf if (ibuf && ibuf->type == cJSON_String && ibuf->valuestring) { int l = hex_decode(c->ibuf, c->ibuf_size, ibuf->valuestring); if (l < 0) { hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode ibuf: %s", c->addr_rem, c->username, ibuf->valuestring); } else { c->ibuf_end = l; hlog(LOG_DEBUG, "Live upgrade: Decoded ibuf %d bytes: '%.*s'", l, l, c->ibuf); hlog(LOG_DEBUG, "Hex: %s", ibuf->valuestring); } } // fill up obuf if (obuf && obuf->type == cJSON_String && obuf->valuestring) { int l = hex_decode(c->obuf, c->obuf_size, obuf->valuestring); if (l < 0) { hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode obuf: %s", c->addr_rem, c->username, obuf->valuestring); } else { c->obuf_start = 0; c->obuf_end = l; hlog(LOG_DEBUG, "Live upgrade: Decoded obuf %d bytes: '%.*s'", l, l, c->obuf); hlog(LOG_DEBUG, "Hex: %s", obuf->valuestring); } } /* load list of stations heard by this client, to immediately support * messaging */ if (client_heard && client_heard->type == cJSON_Array) client_heard_json_load(c, client_heard); /* load rxerrs counters, with error name string mapping to support * adding/reordering of error counters */ if (rx_errs && rx_errs->type == cJSON_Array && rxerr_map && rxerr_map_len > 0) accept_rx_err_load(c, rx_errs, rxerr_map, rxerr_map_len); /* set client lat/lon, if they're given */ if (lat && lng && lat->type == cJSON_Number && lng->type == cJSON_Number) { c->loc_known = 1; c->lat = lat->valuedouble; c->lng = lng->valuedouble; } hlog(LOG_DEBUG, "%s - Accepted live upgrade client on fd %d from %s", c->addr_loc, c->fd, c->addr_rem); /* set client socket options, return -1 on serious errors */ if (set_client_sockopt(c) != 0) goto err; /* Add the client to the client list. */ int old_fd = clientlist_add(c); if (c->validated && old_fd != -1) { /* TODO: If old connection is SSL validated, and this one is not, do not disconnect it. */ hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, c->username); shutdown(old_fd, SHUT_RDWR); } /* ok, found it... lock the new client queue and pass the client */ if (pass_client_to_worker(pick_next_worker(), c)) goto err; return 0; err: close(c->fd); inbound_connects_account(0, c->portaccount); /* something failed, remove this from accounts.. */ client_free(c); return -1; }