options.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*
  2. * options.c
  3. * ptunnel is licensed under the BSD license:
  4. *
  5. * Copyright (c) 2017-2019, Toni Uhlig <matzeton@googlemail.com>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * - Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. *
  13. * - Redistributions in binary form must reproduce the above copyright notice,
  14. * this list of conditions and the following disclaimer in the documentation
  15. * and/or other materials provided with the distribution.
  16. *
  17. * - Neither the name of the Yellow Lemon Software nor the names of its
  18. * contributors may be used to endorse or promote products derived from this
  19. * software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  25. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. * POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #include <stdio.h>
  34. #include <unistd.h>
  35. #include <stdint.h>
  36. #include <string.h>
  37. #include <getopt.h>
  38. #include <ctype.h>
  39. #include <assert.h>
  40. #ifdef WIN32
  41. #include <ws2tcpip.h>
  42. #endif
  43. #ifdef ENABLE_SHA512
  44. #include <openssl/sha.h>
  45. #endif
  46. #ifdef HAVE_CONFIG_H
  47. #include "config.h"
  48. #endif
  49. #include "options.h"
  50. #include "utils.h"
  51. #include "ptunnel.h"
  52. #include "md5.h"
  53. struct options opts;
  54. enum option_type {
  55. OPT_BOOL, OPT_DEC32, OPT_HEX32, OPT_STR
  56. };
  57. struct option_usage {
  58. const char *short_help;
  59. int required;
  60. enum option_type otype;
  61. union {
  62. int32_t num;
  63. uint32_t unum;
  64. const char *str;
  65. };
  66. const char *long_help;
  67. };
  68. static const struct option_usage usage[] = {
  69. /** --magic */
  70. {"magic", 0, OPT_HEX32, {.unum = 0xdeadc0de},
  71. "Set ptunnel magic hexadecimal number. (32-bit unsigned)\n"
  72. "It is an identifier for all ICMP/UDP packets\n"
  73. "and can be used to bypass Cisco IPS fingerprint scan.\n"
  74. "This value has to be the same on the server and client!\n"
  75. },
  76. /** --proxy */
  77. {"address", 1, OPT_STR, {.str = NULL},
  78. "Set address of peer running packet forwarder. This causes\n"
  79. "ptunnel to operate in forwarding mode (Client) - the absence of this\n"
  80. "option causes ptunnel to operate in proxy mode (Server).\n"
  81. },
  82. /** --listen */
  83. {"port", 0, OPT_DEC32, {.unum = 2222},
  84. "Set TCP listening port (only used when operating in forward mode)\n"
  85. },
  86. /** --remote-addr */
  87. {"address", 1, OPT_STR, {.str = "127.0.0.1"},
  88. "Set remote proxy destination address if client\n"
  89. "Restrict to only this destination address if server\n"
  90. },
  91. /** --remote-port */
  92. {"port", 1, OPT_DEC32, {.unum = 22},
  93. "Set remote proxy destination port if client\n"
  94. "Restrict to only this destination port if server\n"
  95. },
  96. /** --connections */
  97. {"connections", 0, OPT_DEC32, {.unum = kMax_tunnels},
  98. "Set maximum number of concurrent tunnels\n"
  99. },
  100. /** --verbosity */
  101. {"level", 0, OPT_DEC32, {.num = kLog_event},
  102. "Verbosity level (-1 to 4, where -1 is no output, and 4 is all output)\n"
  103. "The special level 5 (or higher) includes xfer logging (lots of output)\n"
  104. },
  105. /** --libpcap */
  106. {"interface", 0, OPT_STR, {.str = NULL},
  107. #ifndef HAVE_PCAP
  108. "(Not available on this platform.)\n"
  109. #endif
  110. "Enable libpcap on the given device.\n"
  111. },
  112. /** --list-libpcap-devices */
  113. {NULL, 0, OPT_BOOL, {.num = 0},
  114. #ifndef HAVE_PCAP
  115. "(Not available on this platform.)\n"
  116. #endif
  117. "List all available pcap devices.\n"
  118. },
  119. /** --logfile */
  120. {"file", 0, OPT_STR, {.str = "/var/log/ptunnel.log"},
  121. "Specify a file to log to, rather than printing to standard out.\n"
  122. },
  123. /** --statistics */
  124. {NULL, 0, OPT_BOOL, {.num = 0},
  125. "Client only. Enables continuous output of statistics (packet loss, etc.)\n"
  126. },
  127. /** --passwd */
  128. {"password", 0, OPT_STR, {.str = NULL},
  129. "Set a password (must be same on client and proxy)\n"
  130. "DEPRECATED: Will be removed/replaced soon!\n"
  131. },
  132. /** --udp */
  133. {NULL, 0, OPT_BOOL, {.num = 0},
  134. "Toggle use of UDP instead of ICMP. Proxy will listen on port 53 (must be root).\n"
  135. },
  136. /** --unprivileged */
  137. {NULL, 0, OPT_BOOL, {.num = 0},
  138. "Run proxy in unprivileged mode. This causes the proxy to forward\n"
  139. "packets using standard echo requests, instead of crafting custom echo replies.\n"
  140. "Unprivileged mode will only work on some systems, and is in general less reliable\n"
  141. "than running in privileged mode.\n"
  142. },
  143. /** --force-sha512 */
  144. {"force-sha512", 0, OPT_BOOL, {.num = 0},
  145. "Force SHA512 as challenge response checksum generator.\n"
  146. #ifdef ENABLE_SHA512
  147. "This is the default for this configuration.\n"
  148. #else
  149. "SHA512 is not available for this configuration.\n"
  150. #endif
  151. },
  152. /** --daemon */
  153. {"pidfile", 0, OPT_STR, {.str = "/run/ptunnel.pid"},
  154. #ifdef WIN32
  155. "(Not available on this platform.)\n"
  156. #endif
  157. "Run in background, the PID will be written in the file supplied as argument\n"
  158. },
  159. /** --syslog */
  160. {NULL, 0, OPT_BOOL, {.num = 0},
  161. #ifdef WIN32
  162. "(Not available on this platform.)\n"
  163. #endif
  164. "Output debug to syslog instead of standard out.\n"
  165. },
  166. /** --user */
  167. {"user", 0, OPT_STR, {.str = "nobody"},
  168. #ifdef WIN32
  169. "(Not available on this platform.)\n"
  170. #endif
  171. "When started in privileged mode, drop down to user's rights as soon as possible\n"
  172. },
  173. /** --group */
  174. {"group", 0, OPT_STR, {.str = "nogroup"},
  175. #ifdef WIN32
  176. "(Not available on this platform.)\n"
  177. #endif
  178. "When started in privileged mode, drop down to group's rights as soon as possible\n"
  179. },
  180. /** --chroot */
  181. {"directory", 0, OPT_STR, {.str = "/var/lib/ptunnel"},
  182. #ifdef WIN32
  183. "(Not available on this platform.)\n"
  184. #endif
  185. "When started in privileged mode, restrict file access to the specified directory\n"
  186. },
  187. /** --setcon */
  188. {"context", 0, OPT_STR, {.str = "ptunnel"},
  189. #ifndef HAVE_SELINUX
  190. "(Not available on this platform.)\n"
  191. #endif
  192. "Set SELinux context when all there is left to do are network I/O operations\n"
  193. "To combine with --chroot you will have to `mount --bind /proc /chrootdir/proc`\n"
  194. },
  195. /** --help */
  196. {NULL, 0, OPT_STR, {.str = NULL}, "this\n"},
  197. {NULL,0,OPT_BOOL,{.unum=0},NULL}
  198. };
  199. static struct option long_options[] = {
  200. {"magic", required_argument, 0, 'm'},
  201. {"proxy", required_argument, 0, 'p'},
  202. {"listen", required_argument, 0, 'l'},
  203. {"remote-addr", optional_argument, 0, 'r'},
  204. {"remote-port", optional_argument, 0, 'R'},
  205. {"connections", required_argument, 0, 'c'},
  206. {"verbosity", required_argument, 0, 'v'},
  207. {"libpcap", required_argument, 0, 'L'},
  208. {"list-libpcap-devices", no_argument, &opts.list_pcap_devices, 1},
  209. {"logfile", optional_argument, 0, 'o'},
  210. {"statistics", no_argument, 0, 's'},
  211. {"passwd", required_argument, 0, 'P'},
  212. {"udp", no_argument, &opts.udp, 1},
  213. {"unprivileged", no_argument, &opts.unprivileged, 1},
  214. {"force-sha512", no_argument, &opts.force_sha512, 1},
  215. {"daemon", optional_argument, 0, 'd'},
  216. {"syslog", no_argument, 0, 'S'},
  217. {"user", optional_argument, 0, 'u'},
  218. {"group", optional_argument, 0, 'g'},
  219. {"chroot", optional_argument, 0, 'C'},
  220. {"setcon", optional_argument, 0, 'e'},
  221. {"help", no_argument, 0, 'h'},
  222. {NULL,0,0,0}
  223. };
  224. static const void *get_default_optval(enum option_type opttype, const char *optname) {
  225. (void) opttype;
  226. for (unsigned i = 0; i < ARRAY_SIZE(long_options); ++i) {
  227. if (strncmp(long_options[i].name, optname, BUFSIZ /* not optimal */) == 0 &&
  228. strlen(long_options[i].name) == strlen(optname))
  229. {
  230. assert(usage[i].otype == opttype &&
  231. (usage[i].otype != OPT_STR || usage[i].str));
  232. return &usage[i].str;
  233. }
  234. }
  235. assert(NULL);
  236. return NULL;
  237. }
  238. static void set_options_defaults(void) {
  239. #ifndef WIN32
  240. char *tmp;
  241. struct passwd *pwnam;
  242. struct group *grnam;
  243. #endif
  244. memset(&opts, 0, sizeof(opts));
  245. opts.magic = *(uint32_t *) get_default_optval(OPT_HEX32, "magic");
  246. opts.mode = kMode_proxy;
  247. opts.tcp_listen_port = *(uint32_t *) get_default_optval(OPT_DEC32, "listen");
  248. opts.given_dst_hostname = strdup(*(char **) get_default_optval(OPT_STR, "remote-addr"));
  249. opts.given_dst_port = *(uint32_t *) get_default_optval(OPT_DEC32, "remote-port");
  250. opts.max_tunnels = *(uint32_t *) get_default_optval(OPT_DEC32, "connections");
  251. opts.log_level = *(int *) get_default_optval(OPT_DEC32, "verbosity");
  252. opts.log_path = strdup(*(char **)get_default_optval(OPT_STR, "logfile"));
  253. opts.log_file = stdout;
  254. opts.print_stats = *(int *) get_default_optval(OPT_BOOL, "statistics");
  255. #ifndef WIN32
  256. opts.pid_path = strdup(*(char **)get_default_optval(OPT_STR, "daemon"));
  257. errno = 0;
  258. tmp = *(char **) get_default_optval(OPT_STR, "user");
  259. if (NULL == (pwnam = getpwnam(tmp)))
  260. pt_log(kLog_error, "%s: %s\n", tmp, errno ? strerror(errno) : "unknown user");
  261. else {
  262. opts.uid = pwnam->pw_uid;
  263. if (!opts.gid)
  264. opts.gid = pwnam->pw_gid;
  265. }
  266. errno = 0;
  267. tmp = *(char **) get_default_optval(OPT_STR, "group");
  268. if (NULL != (grnam = getgrnam(tmp)))
  269. opts.gid = grnam->gr_gid;
  270. opts.root_dir = strdup(*(char **)get_default_optval(OPT_STR, "chroot"));
  271. #endif
  272. #ifdef HAVE_SELINUX
  273. opts.selinux_context = strdup(*(char **)get_default_optval(OPT_STR, "setcon"));
  274. #endif
  275. }
  276. static void print_multiline(const char *prefix, const char *multiline) {
  277. const char sep[] = "\n";
  278. const char *start, *end;
  279. start = multiline;
  280. end = NULL;
  281. do {
  282. if (start) {
  283. end = strstr(start, sep);
  284. if (end && *end != '\0') {
  285. printf("%s%.*s\n", prefix, (int)(end-start), start);
  286. start = end + strnlen(sep, BUFSIZ /* not optimal */);
  287. }
  288. }
  289. } while (start && end);
  290. }
  291. static void print_long_help(unsigned index, int required_state) {
  292. const char spaces[] = " ";
  293. if (usage[index].required != required_state)
  294. return;
  295. if (!long_options[index].name)
  296. return;
  297. if (isalpha(long_options[index].val)) {
  298. printf("%.*s-%c --%s\n", 4, spaces, long_options[index].val, long_options[index].name);
  299. } else {
  300. printf("%.*s--%s\n", 4, spaces, long_options[index].name);
  301. }
  302. if (usage[index].long_help) {
  303. print_multiline(&spaces[4], usage[index].long_help);
  304. }
  305. switch (usage[index].otype) {
  306. case OPT_BOOL:
  307. break;
  308. case OPT_DEC32:
  309. printf("%s(default: %d)\n", spaces, usage[index].num);
  310. break;
  311. case OPT_HEX32:
  312. printf("%s(default: 0x%X)\n", spaces, usage[index].unum);
  313. break;
  314. case OPT_STR:
  315. if (usage[index].str)
  316. printf("%s(default: %s)\n", spaces, usage[index].str);
  317. break;
  318. }
  319. }
  320. static void print_short_help(unsigned index, int required_state) {
  321. const char *ob = (required_state == 0 ? "[" : "");
  322. const char *cb = (required_state == 0 ? "]" : "");
  323. const char *ov = (long_options[index].has_arg != optional_argument ? " " : "");
  324. if (usage[index].required != required_state)
  325. return;
  326. if (!long_options[index].name)
  327. return;
  328. if (!usage[index].short_help && isalpha(long_options[index].val)) {
  329. printf(" %s-%c%s", ob, long_options[index].val, cb);
  330. }
  331. else if (!usage[index].short_help) {
  332. printf(" %s--%s%s", ob, long_options[index].name, cb);
  333. }
  334. else if (isalpha(long_options[index].val)) {
  335. printf(" %s-%c%s<%s>%s", ob, long_options[index].val, ov, usage[index].short_help, cb);
  336. }
  337. else {
  338. printf(" %s--%s <%s>%s", ob, long_options[index].name, usage[index].short_help, cb);
  339. }
  340. }
  341. void print_usage(const char *arg0) {
  342. unsigned i;
  343. printf("%s\n\nUsage: %s", PACKAGE_STRING, arg0);
  344. /* print (short)help argument line */
  345. for (i = 0; i < ARRAY_SIZE(usage); ++i) {
  346. print_short_help(i, 1);
  347. }
  348. for (i = 0; i < ARRAY_SIZE(usage); ++i) {
  349. print_short_help(i, 0);
  350. }
  351. printf("%s", "\n\n");
  352. /* print (long)help lines */
  353. for (i = 0; i < ARRAY_SIZE(usage); ++i) {
  354. print_long_help(i, 1);
  355. }
  356. for (i = 0; i < ARRAY_SIZE(usage); ++i) {
  357. print_long_help(i, 0);
  358. }
  359. }
  360. int parse_options(int argc, char **argv) {
  361. int c = 0, oidx = -1, has_logfile = 0, ret;
  362. md5_state_t state;
  363. #ifndef WIN32
  364. struct passwd *pwnam;
  365. struct group *grnam;
  366. #endif
  367. FILE *tmp_log;
  368. assert( ARRAY_SIZE(long_options) == ARRAY_SIZE(usage) );
  369. /* set defaults */
  370. set_options_defaults();
  371. /* parse command line arguments */
  372. while (1) {
  373. /* FIXME: We are using '::' (optional argument values). This is not optimal
  374. * since you have to pass long options as '--option=value'. Commonly used
  375. * '--option value' is *NOT* allowed for some libc implementations.
  376. */
  377. c = getopt_long(argc, argv, "m:p:l:r::R::c:v:L:o::sP:d::Su::g::C::e::h", &long_options[0], &oidx);
  378. if (c == -1) break;
  379. switch (c) {
  380. case 'm':
  381. if (!optarg)
  382. break;
  383. opts.magic = strtoul(optarg, NULL, 16);
  384. break;
  385. case 'p':
  386. if (!optarg)
  387. break;
  388. opts.mode = kMode_forward;
  389. if (opts.given_proxy_hostname)
  390. free(opts.given_proxy_hostname);
  391. opts.given_proxy_hostname = strdup(optarg);
  392. break;
  393. case 'l':
  394. if (!optarg)
  395. break;
  396. opts.tcp_listen_port = strtoul(optarg, NULL, 10);
  397. break;
  398. case 'r':
  399. opts.restrict_dst_ip = 1;
  400. if (!optarg)
  401. break;
  402. if (opts.given_dst_hostname)
  403. free(opts.given_dst_hostname);
  404. opts.given_dst_hostname = strdup(optarg);
  405. break;
  406. case 'R':
  407. opts.restrict_dst_port = 1;
  408. if (optarg)
  409. opts.given_dst_port = strtoul(optarg, NULL, 10);
  410. break;
  411. case 'c':
  412. if (!optarg)
  413. break;
  414. opts.max_tunnels = strtoul(optarg, NULL,10);
  415. if (opts.max_tunnels > kMax_tunnels)
  416. opts.max_tunnels = kMax_tunnels;
  417. break;
  418. case 'v':
  419. if (!optarg)
  420. break;
  421. opts.log_level = strtol(optarg, NULL, 10);
  422. break;
  423. case 'L':
  424. #ifdef HAVE_PCAP
  425. opts.pcap = 1;
  426. if (!optarg)
  427. break;
  428. if (opts.pcap_device)
  429. free(opts.pcap_device);
  430. opts.pcap_device = strdup(optarg);
  431. break;
  432. #else
  433. pt_log(kLog_error, "pcap: %s\n", "feature not supported");
  434. exit(1);
  435. #endif
  436. case 'o':
  437. has_logfile = 1;
  438. if (!optarg)
  439. break;
  440. if (opts.log_path)
  441. free(opts.log_path);
  442. opts.log_path = strdup(optarg);
  443. break;
  444. case 's':
  445. opts.print_stats = !opts.print_stats;
  446. break;
  447. case 'P':
  448. if (!optarg)
  449. break;
  450. if (opts.password)
  451. free(opts.password);
  452. opts.password = strdup(optarg);
  453. pt_log(kLog_debug, "%s\n", "Password set - unauthenicated connections will be refused.");
  454. /* Compute the md5 password digest */
  455. md5_init(&state);
  456. md5_append(&state, (md5_byte_t *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */));
  457. md5_finish(&state, &opts.md5_password_digest[0]);
  458. #ifdef ENABLE_SHA512
  459. pt_log(kLog_debug, "%s\n", "Password set - sha512 authentication enabled.");
  460. SHA512((const unsigned char *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */), &opts.sha512_password_digest[0]);
  461. #endif
  462. // Hide the password in process listing
  463. memset(optarg, '*', strnlen(optarg, BUFSIZ /* not optimal */));
  464. break;
  465. #ifndef WIN32
  466. case 'd':
  467. opts.daemonize = true;
  468. if (!optarg)
  469. break;
  470. if (opts.pid_path)
  471. free(opts.pid_path);
  472. opts.pid_path = strdup(optarg);
  473. break;
  474. case 'S':
  475. opts.use_syslog = 1;
  476. break;
  477. case 'u':
  478. if (!optarg)
  479. break;
  480. errno = 0;
  481. if (NULL == (pwnam = getpwnam(optarg))) {
  482. pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown user");
  483. exit(1);
  484. }
  485. opts.uid = pwnam->pw_uid;
  486. if (!opts.gid)
  487. opts.gid = pwnam->pw_gid;
  488. break;
  489. case 'g':
  490. if (!optarg)
  491. break;
  492. errno = 0;
  493. if (NULL == (grnam = getgrnam(optarg))) {
  494. pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown group");
  495. exit(1);
  496. }
  497. opts.gid = grnam->gr_gid;
  498. break;
  499. case 'C':
  500. opts.chroot = 1;
  501. if (!optarg)
  502. break;
  503. if (opts.root_dir)
  504. free(opts.root_dir);
  505. opts.root_dir = strdup(optarg);
  506. break;
  507. #else
  508. case 'd':
  509. case 'S':
  510. case 'u':
  511. case 'g':
  512. case 'C':
  513. pt_log(kLog_error, "-%c: %s\n", c, "feature not supported");
  514. exit(1);
  515. #endif
  516. case 'e':
  517. #ifdef HAVE_SELINUX
  518. opts.selinux = 1;
  519. if (!optarg)
  520. break;
  521. if (opts.selinux_context)
  522. free(opts.selinux_context);
  523. opts.selinux_context = strdup(optarg);
  524. break;
  525. #else
  526. pt_log(kLog_error, "SeLinux: %s\n", "feature not supported");
  527. exit(1);
  528. #endif
  529. case 'h':
  530. print_usage(argv[0]);
  531. exit(EXIT_SUCCESS);
  532. case 0: /* long opt only */
  533. default:
  534. break;
  535. }
  536. }
  537. if (optind != argc) {
  538. pt_log(kLog_error, "Unknown argument: '%s'\n", argv[optind]);
  539. exit(1);
  540. }
  541. #ifndef ENABLE_SHA512
  542. if (opts.force_sha512) {
  543. pt_log(kLog_error, "%s\n", "You are forcing sha512 but it isn't available.");
  544. return 1;
  545. }
  546. #endif
  547. if (opts.given_proxy_hostname) {
  548. if ((ret = host_to_addr(opts.given_proxy_hostname, &opts.given_proxy_ip)) != 0) {
  549. pt_log(kLog_error, "Failed to look up %s as destination address: %s\n",
  550. opts.given_proxy_hostname, gai_strerror(ret));
  551. return 1;
  552. }
  553. }
  554. if ((ret = host_to_addr(opts.given_dst_hostname, &opts.given_dst_ip)) != 0) {
  555. pt_log(kLog_error, "Failed to look up %s as destination address: %s\n",
  556. opts.given_dst_hostname, gai_strerror(ret));
  557. return 1;
  558. }
  559. #ifndef WIN32
  560. if (NULL == (opts.pid_file = fopen(opts.pid_path, "w")))
  561. pt_log(kLog_error, "Failed to open pidfile: \"%s\", Cause: %s\n", opts.pid_path, strerror(errno));
  562. #endif
  563. if (has_logfile && opts.log_path) {
  564. pt_log(kLog_info, "Open Logfile: \"%s\"\n", opts.log_path);
  565. tmp_log = fopen(opts.log_path, "a");
  566. if (!tmp_log) {
  567. pt_log(kLog_error, "Failed to open log file: \"%s\", Cause: %s\n", opts.log_path, strerror(errno));
  568. pt_log(kLog_error, "Reverting log to standard out.\n");
  569. } else opts.log_file = tmp_log;
  570. }
  571. return 0;
  572. }