config.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /* Copyright 2001,2002 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 1024
  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 = strdup(s);
  55. new->value = 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. * Warn and ignore mangled lines. */
  66. static struct config_line *config_get_lines(FILE *f) {
  67. struct config_line *new;
  68. struct config_line *front = NULL;
  69. char line[CONFIG_LINE_MAXLEN];
  70. int lineno=0; /* current line number */
  71. char *s;
  72. char *start, *end;
  73. assert(f);
  74. fseek(f,0,SEEK_SET); /* make sure we start at the beginning of file */
  75. while(fgets(line, CONFIG_LINE_MAXLEN, f)) {
  76. lineno++;
  77. /* first strip comments */
  78. s = strchr(line,'#');
  79. if(s) {
  80. *s = 0; /* stop the line there */
  81. }
  82. /* walk to the end, remove end whitespace */
  83. s = strchr(line, 0); /* now we're at the null */
  84. do {
  85. *s = 0;
  86. s--;
  87. } while (isspace(*s));
  88. start = line;
  89. while(isspace(*start))
  90. start++;
  91. if(*start == 0)
  92. continue; /* this line has nothing on it */
  93. end = start;
  94. while(*end && !isspace(*end))
  95. end++;
  96. s = end;
  97. while(*s && isspace(*s))
  98. s++;
  99. if(!*end || !*s) { /* only a keyword on this line. no value. */
  100. log(LOG_WARNING,"Config line %d has keyword '%s' but no value. Skipping.",lineno,s);
  101. }
  102. *end = 0; /* null it out */
  103. /* prepare to parse the string into key / value */
  104. new = tor_malloc(sizeof(struct config_line));
  105. new->key = strdup(start);
  106. new->value = strdup(s);
  107. log(LOG_DEBUG,"Config line %d: parsed keyword '%s', value '%s'",
  108. lineno, new->key, new->value);
  109. new->next = front;
  110. front = new;
  111. }
  112. return front;
  113. }
  114. static void config_free_lines(struct config_line *front) {
  115. struct config_line *tmp;
  116. while(front) {
  117. tmp = front;
  118. front = tmp->next;
  119. free(tmp->key);
  120. free(tmp->value);
  121. free(tmp);
  122. }
  123. }
  124. static int config_compare(struct config_line *c, char *key, int type, void *arg) {
  125. int i;
  126. if(strncasecmp(c->key,key,strlen(c->key)))
  127. return 0;
  128. /* it's a match. cast and assign. */
  129. log_fn(LOG_DEBUG,"Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
  130. switch(type) {
  131. case CONFIG_TYPE_INT:
  132. *(int *)arg = atoi(c->value);
  133. break;
  134. case CONFIG_TYPE_BOOL:
  135. i = atoi(c->value);
  136. if (i != 0 && i != 1) {
  137. log(LOG_ERR, "Boolean keyword '%s' expects 0 or 1", c->key);
  138. return 0;
  139. }
  140. *(int *)arg = i;
  141. break;
  142. case CONFIG_TYPE_STRING:
  143. *(char **)arg = strdup(c->value);
  144. break;
  145. case CONFIG_TYPE_DOUBLE:
  146. *(double *)arg = atof(c->value);
  147. break;
  148. }
  149. return 1;
  150. }
  151. static void config_assign(or_options_t *options, struct config_line *list) {
  152. /* iterate through list. for each item convert as appropriate and assign to 'options'. */
  153. while(list) {
  154. if(
  155. /* order matters here! abbreviated arguments use the first match. */
  156. /* string options */
  157. config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
  158. config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) ||
  159. config_compare(list, "SigningPrivateKeyFile", CONFIG_TYPE_STRING, &options->SigningPrivateKeyFile) ||
  160. config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
  161. /* int options */
  162. config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
  163. config_compare(list, "APPort", CONFIG_TYPE_INT, &options->APPort) ||
  164. config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
  165. config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
  166. config_compare(list, "DirFetchPeriod", CONFIG_TYPE_INT, &options->DirFetchPeriod) ||
  167. config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
  168. config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
  169. config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
  170. config_compare(list, "TotalBandwidth", CONFIG_TYPE_INT, &options->TotalBandwidth) ||
  171. config_compare(list, "NumCpus", CONFIG_TYPE_INT, &options->NumCpus) ||
  172. config_compare(list, "OnionRouter", CONFIG_TYPE_BOOL, &options->OnionRouter) ||
  173. config_compare(list, "Daemon", CONFIG_TYPE_BOOL, &options->Daemon) ||
  174. config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
  175. config_compare(list, "LinkPadding", CONFIG_TYPE_BOOL, &options->LinkPadding) ||
  176. config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
  177. /* float options */
  178. config_compare(list, "CoinWeight", CONFIG_TYPE_DOUBLE, &options->CoinWeight)
  179. ) {
  180. /* then we're ok. it matched something. */
  181. } else {
  182. log_fn(LOG_WARNING,"Ignoring unknown keyword '%s'.",list->key);
  183. }
  184. list = list->next;
  185. }
  186. }
  187. /* return 0 if success, <0 if failure. */
  188. int getconfig(int argc, char **argv, or_options_t *options) {
  189. struct config_line *cl;
  190. FILE *cf;
  191. char fname[256];
  192. int i;
  193. int result = 0;
  194. /* give reasonable values for each option. Defaults to zero. */
  195. memset(options,0,sizeof(or_options_t));
  196. options->LogLevel = "debug";
  197. options->loglevel = LOG_DEBUG;
  198. options->CoinWeight = 0.8;
  199. options->MaxConn = 900;
  200. options->DirFetchPeriod = 600;
  201. options->KeepalivePeriod = 300;
  202. options->MaxOnionsPending = 10;
  203. options->NewCircuitPeriod = 60; /* once a minute */
  204. options->TotalBandwidth = 800000; /* at most 800kB/s total sustained incoming */
  205. options->NumCpus = 1;
  206. // options->ReconnectPeriod = 6001;
  207. /* get config lines from /etc/torrc and assign them */
  208. #define rcfile "torrc"
  209. snprintf(fname,256,"/etc/%s",rcfile);
  210. cf = config_open(fname);
  211. if(cf) {
  212. /* we got it open. pull out the config lines. */
  213. cl = config_get_lines(cf);
  214. config_assign(options,cl);
  215. config_free_lines(cl);
  216. config_close(cf);
  217. }
  218. /* if we failed to open it, ignore */
  219. /* learn config file name, get config lines, assign them */
  220. i = 1;
  221. while(i < argc-1 && strcmp(argv[i],"-f")) {
  222. // log(LOG_DEBUG,"examining arg %d (%s), it's not -f.",i,argv[i]);
  223. i++;
  224. }
  225. if(i < argc-1) { /* we found one */
  226. log(LOG_DEBUG,"Opening specified config file '%s'",argv[i+1]);
  227. cf = config_open(argv[i+1]);
  228. if(!cf) { /* it's defined but not there. that's no good. */
  229. log(LOG_ERR, "Unable to open configuration file '%s'.",argv[i+1]);
  230. return -1;
  231. }
  232. cl = config_get_lines(cf);
  233. config_assign(options,cl);
  234. config_free_lines(cl);
  235. config_close(cf);
  236. }
  237. /* go through command-line variables too */
  238. cl = config_get_commandlines(argc,argv);
  239. config_assign(options,cl);
  240. config_free_lines(cl);
  241. /* print config */
  242. /* XXX this section is rotting. Should maybe remove it sometime. */
  243. if (options->loglevel == LOG_DEBUG) {
  244. printf("LogLevel=%s\n",
  245. options->LogLevel);
  246. printf("RouterFile=%s, PrivateKeyFile=%s, SigningPrivateKeyFile=%s\n",
  247. options->RouterFile ? options->RouterFile : "(undefined)",
  248. options->PrivateKeyFile ? options->PrivateKeyFile : "(undefined)",
  249. options->SigningPrivateKeyFile ? options->SigningPrivateKeyFile : "(undefined)");
  250. printf("ORPort=%d, APPort=%d DirPort=%d\n",
  251. options->ORPort,
  252. options->APPort,options->DirPort);
  253. printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
  254. options->CoinWeight,
  255. options->MaxConn,
  256. options->TrafficShaping,
  257. options->LinkPadding);
  258. printf("DirFetchPeriod=%d KeepalivePeriod=%d\n",
  259. options->DirFetchPeriod,
  260. options->KeepalivePeriod);
  261. printf("Daemon=%d\n", options->Daemon);
  262. }
  263. /* Validate options */
  264. if(options->LogLevel) {
  265. if(!strcmp(options->LogLevel,"emerg"))
  266. options->loglevel = LOG_EMERG;
  267. else if(!strcmp(options->LogLevel,"alert"))
  268. options->loglevel = LOG_ALERT;
  269. else if(!strcmp(options->LogLevel,"crit"))
  270. options->loglevel = LOG_CRIT;
  271. else if(!strcmp(options->LogLevel,"err"))
  272. options->loglevel = LOG_ERR;
  273. else if(!strcmp(options->LogLevel,"warning"))
  274. options->loglevel = LOG_WARNING;
  275. else if(!strcmp(options->LogLevel,"notice"))
  276. options->loglevel = LOG_NOTICE;
  277. else if(!strcmp(options->LogLevel,"info"))
  278. options->loglevel = LOG_INFO;
  279. else if(!strcmp(options->LogLevel,"debug"))
  280. options->loglevel = LOG_DEBUG;
  281. else {
  282. log(LOG_ERR,"LogLevel must be one of emerg|alert|crit|err|warning|notice|info|debug.");
  283. result = -1;
  284. }
  285. }
  286. if(options->RouterFile == NULL) {
  287. log(LOG_ERR,"RouterFile option required, but not found.");
  288. result = -1;
  289. }
  290. if(options->ORPort < 0) {
  291. log(LOG_ERR,"ORPort option can't be negative.");
  292. result = -1;
  293. }
  294. if(options->OnionRouter && options->ORPort == 0) {
  295. log(LOG_ERR,"If OnionRouter is set, then ORPort must be positive.");
  296. result = -1;
  297. }
  298. if(options->OnionRouter && options->PrivateKeyFile == NULL) {
  299. log(LOG_ERR,"PrivateKeyFile option required for OnionRouter, but not found.");
  300. result = -1;
  301. }
  302. if(options->DirPort > 0 && options->SigningPrivateKeyFile == NULL) {
  303. log(LOG_ERR,"SigningPrivateKeyFile option required for DirServer, but not found.");
  304. result = -1;
  305. }
  306. if(options->APPort < 0) {
  307. log(LOG_ERR,"APPort option can't be negative.");
  308. result = -1;
  309. }
  310. if(options->DirPort < 0) {
  311. log(LOG_ERR,"DirPort option can't be negative.");
  312. result = -1;
  313. }
  314. if(options->APPort > 1 &&
  315. (options->CoinWeight < 0.0 || options->CoinWeight >= 1.0)) {
  316. log(LOG_ERR,"CoinWeight option must be >=0.0 and <1.0.");
  317. result = -1;
  318. }
  319. if(options->MaxConn < 1) {
  320. log(LOG_ERR,"MaxConn option must be a non-zero positive integer.");
  321. result = -1;
  322. }
  323. if(options->MaxConn >= MAXCONNECTIONS) {
  324. log(LOG_ERR,"MaxConn option must be less than %d.", MAXCONNECTIONS);
  325. result = -1;
  326. }
  327. if(options->DirFetchPeriod < 1) {
  328. log(LOG_ERR,"DirFetchPeriod option must be positive.");
  329. result = -1;
  330. }
  331. if(options->KeepalivePeriod < 1) {
  332. log(LOG_ERR,"KeepalivePeriod option must be positive.");
  333. result = -1;
  334. }
  335. return result;
  336. }
  337. /*
  338. Local Variables:
  339. mode:c
  340. indent-tabs-mode:nil
  341. c-basic-offset:2
  342. End:
  343. */