/** * Set argument defaults, read and validate command line options */ void process_args(int argc, char *argv[]) { int c, i, listidx; long tmpval; struct hostent *hp; struct in_addr addr, *paddr; char line[1000], *servername, *fingerprint, *p; FILE *serverfile; const char opts[] = "dv:nL:P:I:p:T:D:M:B:Q:EU:S:R:k:K:m"; set_defaults(); // read lettered arguments while ((c = getopt(argc, argv, opts)) != EOF) { switch (c) { case 'd': debug = 1; break; case 'n': noname = 1; break; case 'v': verbose = atoi(optarg); break; case 'L': strncpy(logfile, optarg, sizeof(logfile)-1); logfile[sizeof(logfile)-1] = '\x0'; break; case 'P': strncpy(pidfile, optarg, sizeof(pidfile)-1); pidfile[sizeof(pidfile)-1] = '\x0'; break; case 'I': p = strtok(optarg, ","); while (p != NULL) { if ((listidx = getifbyname(p, ifl, ifl_len)) != -1) { m_interface[interface_count++] = ifl[listidx]; p = strtok(NULL, ","); continue; } if (inet_addr(p) == INADDR_NONE) { if ((hp = gethostbyname(p)) == NULL) { fprintf(stderr, "Invalid host name: %s\n", p); exit(1); } else { paddr = (struct in_addr *)hp->h_addr_list[0]; } } else { addr.s_addr = inet_addr(p); paddr = &addr; } if ((listidx = getifbyaddr(*paddr, ifl, ifl_len)) != -1) { m_interface[interface_count++] = ifl[listidx]; } else { fprintf(stderr, "Interface %s not found\n", p); exit(1); } p = strtok(NULL, ","); } break; case 'p': port = atoi(optarg); if (port == 0) { fprintf(stderr, "Invalid port\n"); exit(1); } break; case 'T': strncpy(tempdir, optarg, sizeof(tempdir)-1); tempdir[sizeof(tempdir)-1] = '\x0'; break; case 'D': strncpy(destdir, optarg, sizeof(destdir)-1); destdir[sizeof(destdir)-1] = '\x0'; break; case 'M': p = strtok(optarg, ","); while (p != NULL) { pub_multi[pub_multi_count].s_addr = inet_addr(p); if ((pub_multi[pub_multi_count].s_addr == INADDR_NONE) || (!is_multicast(pub_multi[pub_multi_count], 0))) { fprintf(stderr, "Invalid multicast address: %s\n", p); exit(1); } pub_multi_count++; p = strtok(NULL, ","); } break; case 'B': buffer = atoi(optarg); if ((buffer < 65536) || (buffer > 104857600)) { fprintf(stderr, "Invalid buffer size\n"); exit(1); } break; case 'Q': tmpval = strtol(optarg, NULL, 0); if ((tmpval < 0) || (tmpval > 63)) { fprintf(stderr, "Invalid dscp\n"); exit(1); } dscp = (tmpval & 0xFF) << 2; break; case 'E': encrypted_only = 1; break; case 'U': if ((uid = inet_addr(optarg)) != 0) { if (ntohl(uid) > 0xffffff) { fprintf(stderr, "Invalid UID\n"); exit(1); } } else { uid = strtol(optarg, NULL, 16); if ((uid > 0xffffff) || (uid <= 0)) { fprintf(stderr, "Invalid UID\n"); exit(1); } uid = htonl(uid); } break; case 'S': if ((serverfile = fopen(optarg, "r")) == NULL) { fprintf(stderr, "Couldn't open server list %s: %s\n", optarg, strerror(errno)); exit(1); } while (fgets(line, sizeof(line), serverfile)) { while (line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n') { line[strlen(line)-1] = '\x0'; } servername = strtok(line, " \t"); if (!servername) continue; if (servername[0] == '#') continue; if (strlen(servername) > DESTNAME_LEN) { fprintf(stderr, "Server list: name too long\n"); exit(1); } fingerprint = strtok(NULL, " \t"); add_server_by_name(servername, fingerprint); } if (!feof(serverfile) && ferror(serverfile)) { perror("Failed to read from server list file"); exit(1); } fclose(serverfile); break; case 'R': strncpy(line, optarg, sizeof(line)); line[sizeof(line)-1] = '\x0'; servername = strtok(line, "/"); if (!servername) { fprintf(stderr, "Invalid host name\n"); exit(1); } fingerprint = strtok(NULL, "/"); if (inet_addr(servername) == INADDR_NONE) { if ((hp = gethostbyname(servername)) == NULL) { fprintf(stderr, "Invalid host name: %s\n", servername); exit(1); } else { paddr = (struct in_addr *)hp->h_addr_list[0]; proxy_info.addr = *paddr; proxy_info.has_fingerprint = parse_fingerprint(proxy_info.fingerprint, fingerprint); has_proxy = 1; } } else { proxy_info.addr.s_addr = inet_addr(servername); proxy_info.has_fingerprint = parse_fingerprint(proxy_info.fingerprint, fingerprint); has_proxy = 1; } break; case 'k': p = strtok(optarg, ","); while (p != NULL) { strncpy(keyfile[keyfile_count], p, sizeof(keyfile[0])-1); keyfile[keyfile_count][sizeof(keyfile[0])-1] = '\x0'; keyfile_count++; p = strtok(NULL, ","); } break; case 'K': newkeylen = atoi(optarg); if ((newkeylen < 512) || (newkeylen > 2048)) { fprintf(stderr, "Invalid new key length\n"); exit(1); } break; case 'm': sys_keys = 1; break; case '?': fprintf(stderr, USAGE); exit(1); } } if (server_count) { for (i = 0; i < pub_multi_count; i++) { if (!is_multicast(pub_multi[i], 1)) { fprintf(stderr, "Invalid source specific " "multicast address: %s\n", inet_ntoa(pub_multi[i])); exit(1); } } if (pub_multi_count == 0) { fprintf(stderr, "Default multicast address %s invalid " "for source specific multicast\n", DEF_PUB_MULTI); exit(1); } } }
/** * Set argument defaults, read and validate command line options */ void process_args(int argc, char *argv[]) { int c, i, listidx, hbport; long tmpval; struct hostent *hp; struct in_addr addr, *paddr; char line[1000], *servername, *fingerprint, *p, *p2, *hoststr, *portstr; FILE *serverfile; const char opts[] = "dx:nL:P:I:p:tT:D:A:M:B:Q:EU:S:R:k:K:mN:h:H:"; set_defaults(); // read lettered arguments while ((c = getopt(argc, argv, opts)) != EOF) { switch (c) { case 'd': debug = 1; break; case 'n': noname = 1; break; case 'x': log_level = atoi(optarg); if (log_level < 0) { fprintf(stderr, "Invalid log level\n"); exit(1); } break; case 'L': strncpy(logfile, optarg, sizeof(logfile)-1); logfile[sizeof(logfile)-1] = '\x0'; break; case 'P': strncpy(pidfile, optarg, sizeof(pidfile)-1); pidfile[sizeof(pidfile)-1] = '\x0'; break; case 'I': p = strtok(optarg, ","); while (p != NULL) { if ((listidx = getifbyname(p, ifl, ifl_len)) != -1) { m_interface[interface_count++] = ifl[listidx]; p = strtok(NULL, ","); continue; } if (inet_addr(p) == INADDR_NONE) { if ((hp = gethostbyname(p)) == NULL) { fprintf(stderr, "Invalid host name: %s\n", p); exit(1); } else { paddr = (struct in_addr *)hp->h_addr_list[0]; } } else { addr.s_addr = inet_addr(p); paddr = &addr; } if ((listidx = getifbyaddr(*paddr, ifl, ifl_len)) != -1) { m_interface[interface_count++] = ifl[listidx]; } else { fprintf(stderr, "Interface %s not found\n", p); exit(1); } p = strtok(NULL, ","); } break; case 'p': port = atoi(optarg); if (port == 0) { fprintf(stderr, "Invalid port\n"); exit(1); } break; case 't': tempfile = 1; break; case 'T': strncpy(tempdir, optarg, sizeof(tempdir)-1); tempdir[sizeof(tempdir)-1] = '\x0'; break; case 'D': p = strtok(optarg, ","); while (p != NULL) { strncpy(destdir[destdircnt], p, sizeof(destdir[destdircnt])-1); destdir[destdircnt][sizeof(destdir[destdircnt])-1] = '\x0'; destdircnt++; p = strtok(NULL, ","); } break; case 'A': p = strtok(optarg, ","); while (p != NULL) { strncpy(backupdir[backupcnt],p,sizeof(backupdir[backupcnt])-1); backupdir[backupcnt][sizeof(backupdir[backupcnt])-1] = '\x0'; backupcnt++; p = strtok(NULL, ","); } break; case 'M': p = strtok(optarg, ","); while (p != NULL) { pub_multi[pub_multi_count].s_addr = inet_addr(p); if ((pub_multi[pub_multi_count].s_addr == INADDR_NONE) || (!is_multicast(pub_multi[pub_multi_count], 0))) { fprintf(stderr, "Invalid multicast address: %s\n", p); exit(1); } pub_multi_count++; p = strtok(NULL, ","); } break; case 'B': buffer = atoi(optarg); if ((buffer < 65536) || (buffer > 104857600)) { fprintf(stderr, "Invalid buffer size\n"); exit(1); } break; case 'Q': tmpval = strtol(optarg, NULL, 0); if ((tmpval < 0) || (tmpval > 63)) { fprintf(stderr, "Invalid dscp\n"); exit(1); } dscp = (tmpval & 0xFF) << 2; break; case 'E': encrypted_only = 1; break; case 'U': if ((uid = inet_addr(optarg)) != 0) { if (ntohl(uid) > 0xffffff) { fprintf(stderr, "Invalid UID\n"); exit(1); } } else { uid = strtol(optarg, NULL, 16); if ((uid > 0xffffff) || (uid <= 0)) { fprintf(stderr, "Invalid UID\n"); exit(1); } uid = htonl(uid); } break; case 'S': if ((serverfile = fopen(optarg, "r")) == NULL) { fprintf(stderr, "Couldn't open server list %s: %s\n", optarg, strerror(errno)); exit(1); } while (fgets(line, sizeof(line), serverfile)) { while ((strlen(line) != 0) && ((line[strlen(line)-1] == '\r') || (line[strlen(line)-1] == '\n'))) { line[strlen(line)-1] = '\x0'; } servername = strtok(line, " \t"); if (!servername) continue; if (servername[0] == '#') continue; if (strlen(servername) > DESTNAME_LEN) { fprintf(stderr, "Server list: name too long\n"); exit(1); } fingerprint = strtok(NULL, " \t"); add_server_by_name(servername, fingerprint); } if (!feof(serverfile) && ferror(serverfile)) { perror("Failed to read from server list file"); exit(1); } fclose(serverfile); break; case 'R': strncpy(line, optarg, sizeof(line)); line[sizeof(line)-1] = '\x0'; servername = strtok(line, "/"); if (!servername) { fprintf(stderr, "Invalid host name\n"); exit(1); } fingerprint = strtok(NULL, "/"); if (inet_addr(servername) == INADDR_NONE) { if ((hp = gethostbyname(servername)) == NULL) { fprintf(stderr, "Invalid host name: %s\n", servername); exit(1); } else { paddr = (struct in_addr *)hp->h_addr_list[0]; proxy_info.addr = *paddr; proxy_info.has_fingerprint = parse_fingerprint(proxy_info.fingerprint, fingerprint); has_proxy = 1; } } else { proxy_info.addr.s_addr = inet_addr(servername); proxy_info.has_fingerprint = parse_fingerprint(proxy_info.fingerprint, fingerprint); has_proxy = 1; } break; case 'k': p = strtok(optarg, ","); while (p != NULL) { strncpy(keyfile[keyfile_count], p, sizeof(keyfile[0])-1); keyfile[keyfile_count][sizeof(keyfile[0])-1] = '\x0'; keyfile_count++; p = strtok(NULL, ","); } break; case 'K': newkeylen = atoi(optarg); if ((newkeylen < 512) || (newkeylen > 2048)) { fprintf(stderr, "Invalid new key length\n"); exit(1); } break; case 'm': sys_keys = 1; break; case 'N': priority = atoi(optarg); if (!valid_priority(priority)) { fprintf(stderr, "Invalid priority value\n"); exit(1); } break; case 'H': p = strtok(optarg, ","); while (p != NULL) { p2 = strchr(p, ':'); if (p2) { hoststr = strdup(p); hoststr[p2 - p] = '\x0'; portstr = p2 + 1; } else { hoststr = p; portstr = NULL; } hb_hosts[hbhost_count].sin_family = AF_INET; if (inet_addr(hoststr) == INADDR_NONE) { if ((hp = gethostbyname(hoststr)) == NULL) { fprintf(stderr, "Invalid host name: %s\n", hoststr); exit(1); } else { paddr = (struct in_addr *)hp->h_addr_list[0]; hb_hosts[hbhost_count].sin_addr.s_addr = paddr->s_addr; } } else { hb_hosts[hbhost_count].sin_addr.s_addr = inet_addr(hoststr); } if (portstr) { free(hoststr); hbport = atoi(portstr); if ((hbport <= 0) || (hbport > 65535)) { hbport = DEF_PORT; } } else { hbport = DEF_PORT; } hb_hosts[hbhost_count++].sin_port = htons(hbport); p = strtok(NULL, ","); } break; case 'h': hb_interval = atoi(optarg); if ((hb_interval <= 0) || (hb_interval > 3600)) { fprintf(stderr, "Invalid hearbeat interval\n"); exit(1); } break; case '?': fprintf(stderr, USAGE); exit(1); } } if (server_count) { for (i = 0; i < pub_multi_count; i++) { if (!is_multicast(pub_multi[i], 1)) { fprintf(stderr, "Invalid source specific " "multicast address: %s\n", inet_ntoa(pub_multi[i])); exit(1); } } if (pub_multi_count == 0) { fprintf(stderr, "Default multicast address %s invalid " "for source specific multicast\n", DEF_PUB_MULTI); exit(1); } } if (destdircnt == 0) { strncpy(destdir[0], DEF_DESTDIR, sizeof(destdir[0])-1); destdir[0][sizeof(destdir[0])-1] = '\x0'; destdircnt++; } if ((backupcnt > 0) && (backupcnt != destdircnt)) { fprintf(stderr, "Must specify same number of backup directories " "as destination directories\n"); exit(1); } if (tempfile && (strcmp(tempdir, ""))) { fprintf(stderr, "Cannot specify both -t and -T\n"); exit(1); } }
/** * Set argument defaults, read and validate command line options */ void process_args(int argc, char *argv[]) { int c, i, listidx, read_restart, rval; long tmpval; char line[1000], *dest, *destname, filename[MAXPATHNAME], *fingerprint, *p; char keylenstr[50]; struct addrinfo ai_hints, *ai_rval; FILE *destfile, *excludefile, *listfile; const char opts[] = "x:R:L:B:g:n:m:Y:h:w:e:ck:K:lTb:t:Q:" "zZI:p:u:j:qfyU:H:F:X:M:P:C:D:oE:S:r:s:i:W:N:"; set_defaults(); memset(keylenstr, 0, sizeof(keylenstr)); read_restart = 0; // read lettered arguments while ((c = getopt(argc, argv, opts)) != EOF) { switch (c) { case 'x': log_level = atoi(optarg); if (log_level < 0) { fprintf(stderr,"Invalid log level\n"); exit(ERR_PARAM); } break; case 'R': // Expecting rate as Kbps, translate to B/s rate = atoi(optarg); if ((rate <= 0) && (rate != -1)) { fprintf(stderr,"Invalid rate\n"); exit(ERR_PARAM); } if (rate != -1) { rate = rate * 1024 / 8; } break; case 'L': strncpy(logfile, optarg, sizeof(logfile)-1); logfile[sizeof(logfile)-1] = '\x0'; break; case 'B': rcvbuf = atoi(optarg); if ((rcvbuf < 65536) || (rcvbuf > 104857600)) { fprintf(stderr, "Invalid receive buffer size\n"); exit(ERR_PARAM); } break; case 'g': max_log_size = atoi(optarg); if ((max_log_size < 1) || (max_log_size > 1024)) { fprintf(stderr, "Invalid max log size\n"); exit(ERR_PARAM); } max_log_size *= 1000000; break; case 'n': max_log_count = atoi(optarg); if ((max_log_count < 1) || (max_log_count > 1000)) { fprintf(stderr, "Invalid max log count\n"); exit(ERR_PARAM); } break; case 'm': max_nak_cnt = atoi(optarg); if ((max_nak_cnt < 1) || (max_nak_cnt > 1000)) { fprintf(stderr, "Invalid max nak count\n"); exit(ERR_PARAM); } break; case 'Y': if ((keytype = get_keytype(optarg)) == -1) { fprintf(stderr, "Invalid keytype\n"); exit(ERR_PARAM); } if (keytype != KEY_NONE && !cipher_supported(keytype)) { fprintf(stderr, "Keytype not supported\n"); exit(ERR_PARAM); } break; case 'h': if ((hashtype = get_hashtype(optarg)) == -1) { fprintf(stderr, "Invalid hashtype\n"); exit(ERR_PARAM); } if (!hash_supported(hashtype)) { fprintf(stderr, "Hashtype not supported\n"); exit(ERR_PARAM); } break; case 'w': if (!strcmp(optarg, "hmac")) { sigtype = SIG_HMAC; } else if (!strcmp(optarg, "keyex")) { sigtype = SIG_KEYEX; } else { fprintf(stderr, "Invalid sigtype\n"); exit(ERR_PARAM); } break; case 'e': p = strtok(optarg, ":"); if (!p) { fprintf(stderr, "Error reading keyextype\n"); exit(ERR_PARAM); } if (!strcmp(p, "rsa")) { keyextype = KEYEX_RSA; } else if (!strcmp(p, "ecdh_rsa")) { keyextype = KEYEX_ECDH_RSA; } else if (!strcmp(p, "ecdh_ecdsa")) { keyextype = KEYEX_ECDH_ECDSA; } else { fprintf(stderr, "Invalid keyextype\n"); exit(ERR_PARAM); } if ((keyextype == KEYEX_ECDH_RSA) || (keyextype == KEYEX_ECDH_ECDSA)) { p = strtok(NULL, ":"); if (p) { ecdh_curve = get_curve(p); if (ecdh_curve == 0) { fprintf(stderr, "Invalid curve\n"); exit(ERR_PARAM); } } else { ecdh_curve = DEF_CURVE; } } break; case 'c': client_auth = 1; break; case 'k': strncpy(keyfile, optarg, sizeof(keyfile)-1); keyfile[sizeof(keyfile)-1] = '\x0'; break; case 'K': strncpy(keylenstr, optarg, sizeof(keylenstr)-1); keylenstr[sizeof(keylenstr)-1] = '\x0'; break; case 'l': follow_links = 1; break; case 'T': showtime = 1; break; case 'b': blocksize = atoi(optarg); if ((blocksize < 512) || (blocksize > (MAXMTU - 200))) { fprintf(stderr, "Invalid blocksize\n"); exit(ERR_PARAM); } break; case 't': tmpval = atoi(optarg); if ((tmpval <= 0) || (tmpval > 255)) { fprintf(stderr, "Invalid ttl\n"); exit(ERR_PARAM); } ttl = (char)tmpval; break; case 'Q': tmpval = strtol(optarg, NULL, 0); if ((tmpval < 0) || (tmpval > 63)) { fprintf(stderr, "Invalid dscp\n"); exit(ERR_PARAM); } dscp = (tmpval & 0xFF) << 2; break; case 'I': if ((listidx = getifbyname(optarg, ifl, ifl_len)) != -1) { out_if = ifl[listidx]; break; } memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(optarg, NULL, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid name/address %s: %s\n", optarg, gai_strerror(rval)); exit(ERR_PARAM); } // Just use the first addrinfo entry if ((listidx = getifbyaddr((union sockaddr_u *)ai_rval->ai_addr, ifl, ifl_len)) == -1) { fprintf(stderr, "Interface %s not found", optarg); exit(ERR_PARAM); } out_if = ifl[listidx]; freeaddrinfo(ai_rval); break; case 'z': sync_mode = 1; break; case 'Z': sync_preview = 1; sync_mode = 1; break; case 'p': strncpy(port, optarg, sizeof(port)-1); port[sizeof(port)-1] = '\x0'; break; case 'u': strncpy(srcport, optarg, sizeof(srcport)-1); srcport[sizeof(srcport)-1] = '\x0'; break; case 'j': if (read_restart) { fprintf(stderr,"Can't specify both -j and -F\n"); exit(ERR_PARAM); } if ((destfile = fopen(optarg, "rt")) == NULL) { fprintf(stderr,"Couldn't open proxy list %s: %s\n", optarg, strerror(errno)); exit(ERR_PARAM); } while (fgets(line, sizeof(line), destfile)) { while ((strlen(line) > 0) && ((line[strlen(line)-1] == '\r') || (line[strlen(line)-1] == '\n'))) { line[strlen(line)-1] = '\x0'; } destname = strtok(line, "|"); if (!destname) continue; if (destname[0] == '#') continue; if (strlen(destname) >= DESTNAME_LEN) { fprintf(stderr, "Proxylist: name too long\n"); exit(ERR_PARAM); } fingerprint = strtok(NULL, " \t"); add_dest_by_name(destname, fingerprint, 1); } if (!feof(destfile) && ferror(destfile)) { perror("Failed to read from proxylist file"); exit(ERR_PARAM); } fclose(destfile); break; case 'q': quit_on_error = 1; break; case 'f': save_fail = 1; break; case 'y': sys_keys = 1; break; case 'U': errno = 0; server_id = strtoul(optarg, NULL, 16); if (errno) { perror("Invalid UID\n"); exit(ERR_PARAM); } server_id = htonl(server_id); break; case 'H': if (read_restart) { fprintf(stderr,"Can't specify both -H and -F\n"); exit(ERR_PARAM); } if (optarg[0] == '@') { dest = &optarg[1]; if ((destfile = fopen(dest, "rt")) == NULL) { fprintf(stderr,"Couldn't open destination list %s: %s\n", dest, strerror(errno)); exit(ERR_PARAM); } while (fgets(line, sizeof(line), destfile)) { while ((strlen(line) > 0) && ((line[strlen(line)-1] == '\r') || (line[strlen(line)-1] == '\n'))) { line[strlen(line)-1] = '\x0'; } destname = strtok(line, "|"); if (!destname) continue; if (destname[0] == '#') continue; if (strlen(destname) >= DESTNAME_LEN) { fprintf(stderr, "Hostlist: name too long\n"); exit(ERR_PARAM); } fingerprint = strtok(NULL, " \t"); add_dest_by_name(destname, fingerprint, 0); } if (!feof(destfile) && ferror(destfile)) { perror("Failed to read from hostlist file"); exit(ERR_PARAM); } fclose(destfile); } else { dest = strtok(optarg, ","); while (dest != NULL) { add_dest_by_name(dest, NULL, 0); dest = strtok(NULL, ","); } } break; case 'F': if (destcount != 0) { fprintf(stderr,"Can't specify both -H and -F\n"); exit(ERR_PARAM); } read_restart = 1; save_fail = 1; read_restart_file(optarg); break; case 'X': if ((excludefile = fopen(optarg, "rt")) == NULL) { fprintf(stderr,"Couldn't open exclude list %s: %s\n", optarg, strerror(errno)); exit(ERR_PARAM); } while (fgets(filename, sizeof(filename), excludefile)) { while ((strlen(filename) > 0) && ((filename[strlen(filename)-1] == '\r') || (filename[strlen(filename)-1] == '\n'))) { filename[strlen(filename)-1] = '\x0'; } if (strlen(filename) == 0) continue; if (excludecount == MAXEXCLUDE) { fprintf(stderr,"Exceeded maximum exclude file count\n"); exit(ERR_PARAM); } strncpy(exclude[excludecount], filename, sizeof(exclude[0])); exclude[excludecount][sizeof(exclude[0])-1] = '\x0'; excludecount++; } if (!feof(excludefile) && ferror(excludefile)) { perror("Failed to read from exclude file"); exit(ERR_PARAM); } fclose(excludefile); break; case 'M': strncpy(pub_multi, optarg, sizeof(pub_multi)-1); pub_multi[sizeof(pub_multi)-1] = '\x0'; break; case 'P': strncpy(priv_multi, optarg, sizeof(priv_multi)-1); priv_multi[sizeof(priv_multi)-1] = '\x0'; break; case 'C': p = strtok(optarg, ":"); if (!p) { fprintf(stderr, "Error reading cc_type\n"); exit(ERR_PARAM); } if (!strcmp(p, "none")) { cc_type = CC_NONE; } else if (!strcmp(p, "tfmcc")) { cc_type = CC_TFMCC; p = strtok(NULL, ":"); if (p) { max_rate = atoi(p); if (max_rate <= 0) { fprintf(stderr,"Invalid max rate\n"); exit(ERR_PARAM); } max_rate = max_rate * 1024 / 8; } } else { // PGMCC not currently supported fprintf(stderr, "Invalid congestion control type\n"); exit(ERR_PARAM); } break; case 'D': strncpy(destfname, optarg, sizeof(destfname)-1); destfname[sizeof(destfname)-1] = '\x0'; while (destfname[strlen(destfname)-1] == PATH_SEP) { destfname[strlen(destfname)-1] = '\x0'; } break; case 'o': dest_is_dir = 1; break; case 'E': p = strtok(optarg, ","); while (p != NULL) { strncpy(basedir[basedircount], p, sizeof(basedir[basedircount])-1); basedir[basedircount][sizeof(basedir[basedircount])-1] = '\x0'; basedircount++; p = strtok(NULL, ","); } break; case 'S': strncpy(statusfilename, optarg, sizeof(statusfilename)-1); statusfilename[sizeof(statusfilename)-1] = '\x0'; break; case 'r': p = strtok(optarg, ":"); if (!p) { fprintf(stderr, "Error reading cc_type\n"); exit(ERR_PARAM); } errno = 0; grtt = atof(p); if (errno) { perror("Invalid grtt"); exit(ERR_PARAM); } else if ((grtt < CLIENT_RTT_MIN) || (grtt > 1000)) { fprintf(stderr, "Invalid grtt\n"); exit(ERR_PARAM); } p = strtok(NULL, ":"); if (p) { errno = 0; min_grtt = atof(p); if (errno) { perror("Invalid min_grtt"); exit(ERR_PARAM); } else if ((min_grtt < CLIENT_RTT_MIN) || (min_grtt > 1000)) { fprintf(stderr, "Invalid min_grtt\n"); exit(ERR_PARAM); } p = strtok(NULL, ":"); if (!p) { fprintf(stderr, "Missing max_grtt\n"); exit(ERR_PARAM); } errno = 0; max_grtt = atof(p); if (errno) { perror("Invalid max_grtt"); exit(ERR_PARAM); } else if ((max_grtt < CLIENT_RTT_MIN) || (max_grtt > 1000)) { fprintf(stderr, "Invalid max_grtt\n"); exit(ERR_PARAM); } if (min_grtt > max_grtt) { fprintf(stderr, "Invalid min_grtt/max_grtt\n"); exit(ERR_PARAM); } else if ((grtt > max_grtt) || (grtt < min_grtt)) { fprintf(stderr, "Invalid grtt\n"); exit(ERR_PARAM); } } break; case 's': robust = atoi(optarg); if ((robust < 10) || (robust > 50)) { fprintf(stderr,"Invalid robustness factor\n"); exit(ERR_PARAM); } break; case 'i': if (filecount != 0) { fprintf(stderr,"Can't specify both -i and -F\n"); exit(ERR_PARAM); } if (strcmp(optarg, "-") == 0) { listfile = stdin; } else if ((listfile = fopen(optarg, "rt")) == NULL) { fprintf(stderr,"Couldn't open file list %s: %s\n", optarg, strerror(errno)); exit(ERR_PARAM); } while (fgets(filename, sizeof(filename), listfile)) { if (filecount == MAXFILES) { fprintf(stderr, "Exceeded maximum file count\n"); exit(ERR_PARAM); } while ((strlen(filename) > 0) && ((filename[strlen(filename)-1] == '\r') || (filename[strlen(filename)-1] == '\n'))) { filename[strlen(filename)-1] = '\x0'; } if (strlen(filename) == 0) continue; strncpy(filelist[filecount], filename, sizeof(filelist[0])-1); filelist[filecount][sizeof(filelist[0])-1] = '\x0'; filecount++; } if (!feof(listfile) && ferror(listfile)) { perror("Failed to read from file list"); exit(ERR_PARAM); } fclose(listfile); break; case 'W': txweight = atoi(optarg); if ((txweight < 110) || (txweight > 10000)) { fprintf(stderr, "Invalid txweight\n"); exit(ERR_PARAM); } break; case 'N': max_nak_pct = atoi(optarg); if ((max_nak_pct < 0) || (max_nak_pct > 100)) { fprintf(stderr, "Invalid max_nak_pct\n"); exit(ERR_PARAM); } break; case '?': fprintf(stderr, USAGE); exit(ERR_PARAM); } } argc -= optind; argv += optind; if ((argc == 0) && (filecount == 0)) { fprintf(stderr, USAGE); exit(ERR_PARAM); } if (save_fail && sync_mode) { fprintf(stderr, "Error: Cannot use restart mode " "and sync mode together\n"); exit(ERR_PARAM); } if (keytype == KEY_NONE) { hashtype = HASH_NONE; sigtype = SIG_NONE; keyextype = KEYEX_NONE; } if (is_auth_enc(keytype)) { sigtype = SIG_AUTHENC; } if (strcmp(keylenstr, "")) { if (keyextype == KEYEX_ECDH_ECDSA) { ecdsa_curve = get_curve(keylenstr); if (ecdsa_curve == 0) { fprintf(stderr, "Invalid curve\n"); exit(ERR_PARAM); } } else if ((keyextype == KEYEX_RSA) || (keyextype == KEYEX_ECDH_RSA)) { newkeylen = atoi(keylenstr); if ((newkeylen < 512) || (newkeylen > 2048)) { fprintf(stderr, "Invalid new key length\n"); exit(ERR_PARAM); } } } if (filecount != 0) { if (argc > 0) { fprintf(stderr, "Warning: ignoring paths " "specified on command line\n"); } return; } // Read list of files. for (i = 0; i < argc; i++) { if (filecount == MAXFILES) { fprintf(stderr, "Exceeded maximum file count\n"); exit(ERR_PARAM); } strncpy(filelist[filecount], argv[i], sizeof(filelist[0])-1); filelist[filecount][sizeof(filelist[0])-1] = '\x0'; filecount++; } }
/** * Set argument defaults, read and validate command line options */ void process_args(int argc, char *argv[]) { struct addrinfo ai_hints, *ai_rval; int c, i, listidx, rval; long tmpval; char *p, *p2, *hoststr, *portstr, pubname[INET6_ADDRSTRLEN]; const char opts[] = "s:crdx:p:t:Q:N:O:U:q:mh:H:g:n:B:L:P:C:S:e:k:K:I:M:"; set_defaults(); srand((unsigned int)time(NULL) ^ getpid()); // read lettered arguments while ((c = getopt(argc, argv, opts)) != EOF) { switch (c) { case 's': if (proxy_type != UNDEF_PROXY) { fprintf(stderr, "Only one of -s, -c, -r may be specified\n"); exit(ERR_PARAM); } proxy_type = SERVER_PROXY; memset(&down_addr, 0, sizeof(down_addr)); if (!strncmp(optarg, "fp=", 3)) { have_down_fingerprint = parse_fingerprint(down_fingerprint, optarg + 3); if (!have_down_fingerprint) { fprintf(stderr, "Failed to parse downstream fingerprint\n"); exit(ERR_PARAM); } down_nonce = rand32(); } else { have_down_fingerprint = 0; memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(optarg, NULL, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid host name: %s: %s\n", optarg, gai_strerror(rval)); exit(ERR_PARAM); } memcpy(&down_addr, ai_rval->ai_addr, ai_rval->ai_addrlen); freeaddrinfo(ai_rval); } break; case 'c': if (proxy_type != UNDEF_PROXY) { fprintf(stderr, "Only one of -s, -c, -r may be specified\n"); exit(ERR_PARAM); } proxy_type = CLIENT_PROXY; break; case 'r': if (proxy_type != UNDEF_PROXY) { fprintf(stderr, "Only one of -s, -c, -r may be specified\n"); exit(ERR_PARAM); } proxy_type = RESPONSE_PROXY; break; case 'd': debug = 1; break; case 'x': log_level = atoi(optarg); if (log_level < 0) { fprintf(stderr, "Invalid log level\n"); exit(ERR_PARAM); } break; case 'p': strncpy(portname, optarg, sizeof(portname)-1); portname[sizeof(portname)-1] = '\x0'; port = atoi(portname); if (port == 0) { fprintf(stderr, "Invalid port\n"); exit(ERR_PARAM); } break; case 't': tmpval = atoi(optarg); if ((tmpval <= 0) || (tmpval > 255)) { fprintf(stderr, "Invalid ttl\n"); exit(ERR_PARAM); } ttl = (char)tmpval; break; case 'Q': tmpval = strtol(optarg, NULL, 0); if ((tmpval < 0) || (tmpval > 63)) { fprintf(stderr, "Invalid dscp\n"); exit(ERR_PARAM); } dscp = (tmpval & 0xFF) << 2; break; case 'N': priority = atoi(optarg); if (!valid_priority(priority)) { fprintf(stderr, "Invalid priority value\n"); exit(ERR_PARAM); } break; case 'O': if ((listidx = getifbyname(optarg, ifl, ifl_len)) != -1) { out_if = ifl[listidx]; break; } memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(optarg, NULL, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid name/address %s: %s\n", optarg, gai_strerror(rval)); exit(ERR_PARAM); } // Just use the first addrinfo entry if ((listidx = getifbyaddr((union sockaddr_u *)ai_rval->ai_addr, ifl, ifl_len)) == -1) { fprintf(stderr, "Interface %s not found", optarg); exit(ERR_PARAM); } out_if = ifl[listidx]; freeaddrinfo(ai_rval); break; case 'U': errno = 0; uid = strtoul(optarg, NULL, 16); if (errno) { perror("Invalid UID\n"); exit(ERR_PARAM); } uid = htonl(uid); break; case 'q': strncpy(out_portname, optarg, sizeof(out_portname)-1); out_portname[sizeof(out_portname)-1] = '\x0'; out_port = atoi(out_portname); if (out_port == 0) { fprintf(stderr, "Invalid outgoing port\n"); exit(ERR_PARAM); } break; case 'm': sys_keys = 1; break; case 'H': p = strtok(optarg, ","); while (p != NULL) { p2 = strchr(p, ':'); if (p2) { hoststr = strdup(p); hoststr[p2 - p] = '\x0'; portstr = p2 + 1; } else { hoststr = p; portstr = NULL; } memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(hoststr, portstr ? portstr : DEF_PORT, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid name/address %s: %s\n", hoststr, gai_strerror(rval)); exit(ERR_PARAM); } memcpy(&hb_hosts[hbhost_count++], ai_rval->ai_addr, ai_rval->ai_addrlen); p = strtok(NULL, ","); } break; case 'h': hb_interval = atoi(optarg); if ((hb_interval <= 0) || (hb_interval > 3600)) { fprintf(stderr, "Invalid heartbeat interval\n"); exit(ERR_PARAM); } break; case 'g': max_log_size = atoi(optarg); if ((max_log_size < 1) || (max_log_size > 1024)) { fprintf(stderr, "Invalid max log size\n"); exit(ERR_PARAM); } max_log_size *= 1000000; break; case 'n': max_log_count = atoi(optarg); if ((max_log_count < 1) || (max_log_count > 1000)) { fprintf(stderr, "Invalid max log count\n"); exit(ERR_PARAM); } break; case 'B': rcvbuf = atoi(optarg); if ((rcvbuf < 65536) || (rcvbuf > 104857600)) { fprintf(stderr, "Invalid buffer size\n"); exit(ERR_PARAM); } break; case 'L': strncpy(logfile, optarg, sizeof(logfile)-1); logfile[sizeof(logfile)-1] = '\x0'; break; case 'P': strncpy(pidfile, optarg, sizeof(pidfile)-1); pidfile[sizeof(pidfile)-1] = '\x0'; break; case 'C': add_hosts_by_name(client_fp, &client_fp_count, optarg, 0); break; case 'S': add_hosts_by_name(server_fp, &server_fp_count, optarg, 1); break; case 'e': ecdh_curve = get_curve(optarg); if (ecdh_curve == 0) { fprintf(stderr, "Invalid curve\n"); exit(ERR_PARAM); } break; case 'k': p = strtok(optarg, ","); while (p != NULL) { strncpy(keyfile[keyfile_count], p, sizeof(keyfile[0])-1); keyfile[keyfile_count][sizeof(keyfile[0])-1] = '\x0'; keyfile_count++; p = strtok(NULL, ","); } break; case 'K': p = strtok(optarg, ","); while (p != NULL) { strncpy(keyinfo[keyinfo_count], p, sizeof(keyinfo[0])-1); keyinfo[keyinfo_count][sizeof(keyinfo[0])-1] = '\x0'; keyinfo_count++; p = strtok(NULL, ","); } break; case 'I': p = strtok(optarg, ","); while (p != NULL) { if ((listidx = getifbyname(p, ifl, ifl_len)) != -1) { m_interface[interface_count++] = ifl[listidx]; p = strtok(NULL, ","); continue; } memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(p, NULL, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid name/address %s: %s\n", p, gai_strerror(rval)); exit(ERR_PARAM); } if ((listidx = getifbyaddr((union sockaddr_u *)ai_rval->ai_addr, ifl, ifl_len)) == -1) { fprintf(stderr, "Interface %s not found\n", p); exit(ERR_PARAM); } m_interface[interface_count++] = ifl[listidx]; freeaddrinfo(ai_rval); p = strtok(NULL, ","); } break; case 'M': p = strtok(optarg, ","); while (p != NULL) { memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_DGRAM; ai_hints.ai_protocol = 0; ai_hints.ai_flags = 0; if ((rval = getaddrinfo(p, NULL, &ai_hints, &ai_rval)) != 0) { fprintf(stderr, "Invalid multicast address %s: %s\n", p, gai_strerror(rval)); exit(ERR_PARAM); } memcpy(&pub_multi[pub_multi_count], ai_rval->ai_addr, ai_rval->ai_addrlen); pub_multi_count++; freeaddrinfo(ai_rval); p = strtok(NULL, ","); } break; case '?': fprintf(stderr, USAGE); exit(ERR_PARAM); } } if (proxy_type == UNDEF_PROXY) { fprintf(stderr, "Either -s, -c, or -r must be specified\n"); fprintf(stderr, USAGE); exit(ERR_PARAM); } if (proxy_type == RESPONSE_PROXY) { out_port = port; } if (proxy_type == SERVER_PROXY) { if (down_addr.ss.ss_family == AF_INET6) { down_addr.sin6.sin6_port = htons(out_port); } else { down_addr.sin.sin_port = htons(out_port); } } if (proxy_type != CLIENT_PROXY) { if (server_fp_count) { for (i = 0; i < pub_multi_count; i++) { if (!is_multicast(&pub_multi[i], 1)) { if ((rval = getnameinfo((struct sockaddr *)&pub_multi[i], family_len(pub_multi[i]), pubname, sizeof(pubname), NULL, 0, NI_NUMERICHOST)) != 0) { fprintf(stderr,"getnameinfo failed: %s", gai_strerror(rval)); } fprintf(stderr, "Invalid source specific " "multicast address: %s\n", pubname); exit(ERR_PARAM); } } if (pub_multi_count == 0) { fprintf(stderr, "Default multicast address %s invalid " "for source specific multicast\n", DEF_PUB_MULTI); exit(ERR_PARAM); } } } if ((keyfile_count != 0) && (keyinfo_count != 0) && (keyfile_count != keyinfo_count)) { fprintf(stderr, "Must list same number of items for -k and -K\n"); exit(ERR_PARAM); } for (i = 0; i < pub_multi_count; i++) { if (pub_multi[i].ss.ss_family == AF_INET6) { pub_multi[i].sin6.sin6_port = htons(out_port); } else { pub_multi[i].sin.sin_port = htons(out_port); } } }