config.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. /* enumeration of types which option values can take */
  6. #define CONFIG_TYPE_STRING 0
  7. #define CONFIG_TYPE_CHAR 1
  8. #define CONFIG_TYPE_INT 2
  9. #define CONFIG_TYPE_LONG 3
  10. #define CONFIG_TYPE_DOUBLE 4
  11. #define CONFIG_TYPE_BOOL 5
  12. #define CONFIG_LINE_MAXLEN 4096
  13. struct config_line {
  14. char *key;
  15. char *value;
  16. struct config_line *next;
  17. };
  18. static FILE *config_open(const unsigned char *filename);
  19. static int config_close(FILE *f);
  20. static struct config_line *config_get_commandlines(int argc, char **argv);
  21. static struct config_line *config_get_lines(FILE *f);
  22. static void config_free_lines(struct config_line *front);
  23. static int config_compare(struct config_line *c, char *key, int type, void *arg);
  24. static void config_assign(or_options_t *options, struct config_line *list);
  25. /* open configuration file for reading */
  26. static FILE *config_open(const unsigned char *filename) {
  27. assert(filename);
  28. if (strspn(filename,CONFIG_LEGAL_FILENAME_CHARACTERS) != strlen(filename)) {
  29. /* filename has illegal letters */
  30. return NULL;
  31. }
  32. return fopen(filename, "r");
  33. }
  34. /* close configuration file */
  35. static int config_close(FILE *f) {
  36. assert(f);
  37. return fclose(f);
  38. }
  39. static struct config_line *config_get_commandlines(int argc, char **argv) {
  40. struct config_line *new;
  41. struct config_line *front = NULL;
  42. char *s;
  43. int i = 1;
  44. while(i < argc-1) {
  45. if(!strcmp(argv[i],"-f")) {
  46. // log(LOG_DEBUG,"Commandline: skipping over -f.");
  47. i+=2; /* this is the config file option. ignore it. */
  48. continue;
  49. }
  50. new = tor_malloc(sizeof(struct config_line));
  51. s = argv[i];
  52. while(*s == '-')
  53. s++;
  54. new->key = tor_strdup(s);
  55. new->value = tor_strdup(argv[i+1]);
  56. log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
  57. new->key, new->value);
  58. new->next = front;
  59. front = new;
  60. i += 2;
  61. }
  62. return front;
  63. }
  64. /* parse the config file and strdup into key/value strings. Return list,
  65. * or NULL if parsing the file failed.
  66. * Warn and ignore mangled lines. */
  67. static struct config_line *config_get_lines(FILE *f) {
  68. struct config_line *new;
  69. struct config_line *front = NULL;
  70. char line[CONFIG_LINE_MAXLEN];
  71. int result;
  72. char *key, *value;
  73. while( (result=parse_line_from_file(line,sizeof(line),f,&key,&value)) > 0) {
  74. new = tor_malloc(sizeof(struct config_line));
  75. new->key = tor_strdup(key);
  76. new->value = tor_strdup(value);
  77. new->next = front;
  78. front = new;
  79. }
  80. if(result < 0)
  81. return NULL;
  82. return front;
  83. }
  84. static void config_free_lines(struct config_line *front) {
  85. struct config_line *tmp;
  86. while(front) {
  87. tmp = front;
  88. front = tmp->next;
  89. free(tmp->key);
  90. free(tmp->value);
  91. free(tmp);
  92. }
  93. }
  94. static int config_compare(struct config_line *c, char *key, int type, void *arg) {
  95. int i;
  96. if(strncasecmp(c->key,key,strlen(c->key)))
  97. return 0;
  98. /* it's a match. cast and assign. */
  99. log_fn(LOG_DEBUG,"Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
  100. switch(type) {
  101. case CONFIG_TYPE_INT:
  102. *(int *)arg = atoi(c->value);
  103. break;
  104. case CONFIG_TYPE_BOOL:
  105. i = atoi(c->value);
  106. if (i != 0 && i != 1) {
  107. log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1", c->key);
  108. return 0;
  109. }
  110. *(int *)arg = i;
  111. break;
  112. case CONFIG_TYPE_STRING:
  113. tor_free(*(char **)arg);
  114. *(char **)arg = tor_strdup(c->value);
  115. break;
  116. case CONFIG_TYPE_DOUBLE:
  117. *(double *)arg = atof(c->value);
  118. break;
  119. }
  120. return 1;
  121. }
  122. static void config_assign(or_options_t *options, struct config_line *list) {
  123. /* iterate through list. for each item convert as appropriate and assign to 'options'. */
  124. while(list) {
  125. if(
  126. /* order matters here! abbreviated arguments use the first match. */
  127. /* string options */
  128. config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) ||
  129. config_compare(list, "BandwidthRate", CONFIG_TYPE_INT, &options->BandwidthRate) ||
  130. config_compare(list, "BandwidthBurst", CONFIG_TYPE_INT, &options->BandwidthBurst) ||
  131. config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) ||
  132. config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
  133. config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
  134. config_compare(list, "DirBindAddress", CONFIG_TYPE_STRING, &options->DirBindAddress) ||
  135. config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) ||
  136. config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
  137. config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) ||
  138. config_compare(list, "ExitPolicy", CONFIG_TYPE_STRING, &options->ExitPolicy) ||
  139. config_compare(list, "ExitPolicyPrepend",CONFIG_TYPE_STRING, &options->ExitPolicyPrepend) ||
  140. config_compare(list, "ExcludedNodes", CONFIG_TYPE_STRING, &options->ExcludedNodes) ||
  141. config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) ||
  142. config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
  143. config_compare(list, "KeepalivePeriod",CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
  144. config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
  145. config_compare(list, "LogFile", CONFIG_TYPE_STRING, &options->LogFile) ||
  146. config_compare(list, "LinkPadding", CONFIG_TYPE_BOOL, &options->LinkPadding) ||
  147. config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
  148. config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
  149. config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
  150. config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
  151. config_compare(list, "NumCpus", CONFIG_TYPE_INT, &options->NumCpus) ||
  152. config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
  153. config_compare(list, "ORBindAddress", CONFIG_TYPE_STRING, &options->ORBindAddress) ||
  154. config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) ||
  155. config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
  156. config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
  157. config_compare(list, "RunAsDaemon", CONFIG_TYPE_BOOL, &options->RunAsDaemon) ||
  158. config_compare(list, "RecommendedVersions",CONFIG_TYPE_STRING, &options->RecommendedVersions) ||
  159. config_compare(list, "SocksPort", CONFIG_TYPE_INT, &options->SocksPort) ||
  160. config_compare(list, "SocksBindAddress",CONFIG_TYPE_STRING,&options->SocksBindAddress) ||
  161. config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
  162. config_compare(list, "User", CONFIG_TYPE_STRING, &options->User)
  163. ) {
  164. /* then we're ok. it matched something. */
  165. } else {
  166. log_fn(LOG_WARN,"Ignoring unknown keyword '%s'.",list->key);
  167. }
  168. list = list->next;
  169. }
  170. }
  171. /* prints the usage of tor. */
  172. void print_usage(void) {
  173. printf("tor -f <torrc> [args]\n"
  174. "See man page for more options.\n\n"
  175. "-b <bandwidth>\t\tbytes/second rate limiting\n"
  176. "-d <file>\t\tDebug file\n"
  177. "-m <max>\t\tMax number of connections\n"
  178. "-l <level>\t\tLog level\n"
  179. "-r <file>\t\tList of known routers\n");
  180. printf("\nClient options:\n"
  181. "-e \"nick1 nick2 ...\"\t\tExit nodes\n"
  182. "-s <IP>\t\t\tPort to bind to for Socks\n"
  183. );
  184. printf("\nServer options:\n"
  185. "-n <nick>\t\tNickname of router\n"
  186. "-o <port>\t\tOR port to bind to\n"
  187. "-p <file>\t\tPID file\n"
  188. );
  189. }
  190. void free_options(or_options_t *options) {
  191. tor_free(options->LogLevel);
  192. tor_free(options->LogFile);
  193. tor_free(options->DebugLogFile);
  194. tor_free(options->DataDirectory);
  195. tor_free(options->RouterFile);
  196. tor_free(options->Nickname);
  197. tor_free(options->Address);
  198. tor_free(options->PidFile);
  199. tor_free(options->ExitNodes);
  200. tor_free(options->EntryNodes);
  201. tor_free(options->ExcludedNodes);
  202. tor_free(options->ExitPolicy);
  203. tor_free(options->ExitPolicyPrepend);
  204. tor_free(options->SocksBindAddress);
  205. tor_free(options->ORBindAddress);
  206. tor_free(options->DirBindAddress);
  207. tor_free(options->RecommendedVersions);
  208. tor_free(options->User);
  209. tor_free(options->Group);
  210. }
  211. void init_options(or_options_t *options) {
  212. /* give reasonable values for each option. Defaults to zero. */
  213. memset(options,0,sizeof(or_options_t));
  214. options->LogLevel = tor_strdup("warn");
  215. options->ExitNodes = tor_strdup("");
  216. options->EntryNodes = tor_strdup("");
  217. options->ExcludedNodes = tor_strdup("");
  218. options->ExitPolicy = tor_strdup("reject 0.0.0.0/8,reject 169.254.0.0/16,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-80,accept *:110,accept *:143,accept *:443,accept *:873,accept *:993,accept *:995,accept *:1024-65535,reject *:*");
  219. options->ExitPolicyPrepend = tor_strdup("");
  220. options->SocksBindAddress = tor_strdup("127.0.0.1");
  221. options->ORBindAddress = tor_strdup("0.0.0.0");
  222. options->DirBindAddress = tor_strdup("0.0.0.0");
  223. options->RecommendedVersions = tor_strdup("none");
  224. options->loglevel = LOG_INFO;
  225. options->PidFile = NULL; // tor_strdup("tor.pid");
  226. options->DataDirectory = NULL;
  227. options->PathlenCoinWeight = 0.3;
  228. options->MaxConn = 900;
  229. options->DirFetchPostPeriod = 600;
  230. options->KeepalivePeriod = 300;
  231. options->MaxOnionsPending = 100;
  232. options->NewCircuitPeriod = 30; /* twice a minute */
  233. options->BandwidthRate = 800000; /* at most 800kB/s total sustained incoming */
  234. options->BandwidthBurst = 10000000; /* max burst on the token bucket */
  235. options->NumCpus = 1;
  236. }
  237. /* return 0 if success, <0 if failure. */
  238. int getconfig(int argc, char **argv, or_options_t *options) {
  239. struct config_line *cl;
  240. FILE *cf;
  241. char *fname;
  242. int i;
  243. int result = 0;
  244. static int first_load = 1;
  245. static char **backup_argv;
  246. static int backup_argc;
  247. char *previous_pidfile = NULL;
  248. int previous_runasdaemon = 0;
  249. if(first_load) { /* first time we're called. save commandline args */
  250. backup_argv = argv;
  251. backup_argc = argc;
  252. first_load = 0;
  253. } else { /* we're reloading. need to clean up old ones first. */
  254. argv = backup_argv;
  255. argc = backup_argc;
  256. /* record some previous values, so we can fail if they change */
  257. if(options->PidFile)
  258. previous_pidfile = tor_strdup(options->PidFile);
  259. previous_runasdaemon = options->RunAsDaemon;
  260. free_options(options);
  261. }
  262. init_options(options);
  263. if(argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
  264. print_usage();
  265. exit(0);
  266. }
  267. /* learn config file name, get config lines, assign them */
  268. i = 1;
  269. while(i < argc-1 && strcmp(argv[i],"-f")) {
  270. i++;
  271. }
  272. if(i < argc-1) { /* we found one */
  273. fname = argv[i+1];
  274. } else { /* didn't find one, try CONFDIR */
  275. fname = CONFDIR "/torrc";
  276. }
  277. log(LOG_DEBUG,"Opening config file '%s'",fname);
  278. cf = config_open(fname);
  279. if(!cf) {
  280. log(LOG_WARN, "Unable to open configuration file '%s'.",fname);
  281. return -1;
  282. }
  283. cl = config_get_lines(cf);
  284. if(!cl) return -1;
  285. config_assign(options,cl);
  286. config_free_lines(cl);
  287. config_close(cf);
  288. /* go through command-line variables too */
  289. cl = config_get_commandlines(argc,argv);
  290. config_assign(options,cl);
  291. config_free_lines(cl);
  292. /* Validate options */
  293. /* first check if any of the previous options have changed but aren't allowed to */
  294. if(previous_pidfile && strcmp(previous_pidfile,options->PidFile)) {
  295. log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.",
  296. previous_pidfile, options->PidFile);
  297. return -1;
  298. }
  299. tor_free(previous_pidfile);
  300. if(previous_runasdaemon && !options->RunAsDaemon) {
  301. log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
  302. return -1;
  303. }
  304. if(options->LogLevel) {
  305. if(!strcmp(options->LogLevel,"err"))
  306. options->loglevel = LOG_ERR;
  307. else if(!strcmp(options->LogLevel,"warn"))
  308. options->loglevel = LOG_WARN;
  309. else if(!strcmp(options->LogLevel,"info"))
  310. options->loglevel = LOG_INFO;
  311. else if(!strcmp(options->LogLevel,"debug"))
  312. options->loglevel = LOG_DEBUG;
  313. else {
  314. log(LOG_WARN,"LogLevel must be one of err|warn|info|debug.");
  315. result = -1;
  316. }
  317. }
  318. if(options->RouterFile == NULL) {
  319. log(LOG_WARN,"RouterFile option required, but not found.");
  320. result = -1;
  321. }
  322. if(options->ORPort < 0) {
  323. log(LOG_WARN,"ORPort option can't be negative.");
  324. result = -1;
  325. }
  326. if(options->ORPort && options->DataDirectory == NULL) {
  327. log(LOG_WARN,"DataDirectory option required if ORPort is set, but not found.");
  328. result = -1;
  329. }
  330. if(options->ORPort && options->Nickname == NULL) {
  331. log_fn(LOG_WARN,"Nickname required if ORPort is set, but not found.");
  332. result = -1;
  333. }
  334. if(options->SocksPort < 0) {
  335. log(LOG_WARN,"SocksPort option can't be negative.");
  336. result = -1;
  337. }
  338. if(options->SocksPort == 0 && options->ORPort == 0) {
  339. log(LOG_WARN,"SocksPort and ORPort are both undefined? Quitting.");
  340. result = -1;
  341. }
  342. if(options->DirPort < 0) {
  343. log(LOG_WARN,"DirPort option can't be negative.");
  344. result = -1;
  345. }
  346. if(options->SocksPort > 1 &&
  347. (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
  348. log(LOG_WARN,"PathlenCoinWeight option must be >=0.0 and <1.0.");
  349. result = -1;
  350. }
  351. if(options->MaxConn < 1) {
  352. log(LOG_WARN,"MaxConn option must be a non-zero positive integer.");
  353. result = -1;
  354. }
  355. if(options->MaxConn >= MAXCONNECTIONS) {
  356. log(LOG_WARN,"MaxConn option must be less than %d.", MAXCONNECTIONS);
  357. result = -1;
  358. }
  359. if(options->DirFetchPostPeriod < 1) {
  360. log(LOG_WARN,"DirFetchPostPeriod option must be positive.");
  361. result = -1;
  362. }
  363. if(options->KeepalivePeriod < 1) {
  364. log(LOG_WARN,"KeepalivePeriod option must be positive.");
  365. result = -1;
  366. }
  367. return result;
  368. }
  369. /*
  370. Local Variables:
  371. mode:c
  372. indent-tabs-mode:nil
  373. c-basic-offset:2
  374. End:
  375. */