config.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. const char *basename(const char *filename) {
  6. char *result;
  7. /* XXX This won't work on windows. */
  8. result = strrchr(filename, '/');
  9. if (result)
  10. return result;
  11. else
  12. return filename;
  13. }
  14. /* open configuration file for reading */
  15. FILE *config_open(const unsigned char *filename) {
  16. assert(filename);
  17. if (strspn(filename,CONFIG_LEGAL_FILENAME_CHARACTERS) != strlen(filename)) {
  18. /* filename has illegal letters */
  19. return NULL;
  20. }
  21. return fopen(filename, "r");
  22. }
  23. /* close configuration file */
  24. int config_close(FILE *f) {
  25. assert(f);
  26. return fclose(f);
  27. }
  28. struct config_line *config_get_commandlines(int argc, char **argv) {
  29. struct config_line *new;
  30. struct config_line *front = NULL;
  31. char *s;
  32. int i = 1;
  33. while(i < argc-1) {
  34. if(!strcmp(argv[i],"-f")) {
  35. // log(LOG_DEBUG,"Commandline: skipping over -f.");
  36. i+=2; /* this is the config file option. ignore it. */
  37. continue;
  38. }
  39. new = malloc(sizeof(struct config_line));
  40. s = argv[i];
  41. while(*s == '-')
  42. s++;
  43. new->key = strdup(s);
  44. new->value = strdup(argv[i+1]);
  45. log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
  46. new->key, new->value);
  47. new->next = front;
  48. front = new;
  49. i += 2;
  50. }
  51. return front;
  52. }
  53. /* parse the config file and strdup into key/value strings. Return list.
  54. * Warn and ignore mangled lines. */
  55. struct config_line *config_get_lines(FILE *f) {
  56. struct config_line *new;
  57. struct config_line *front = NULL;
  58. char line[CONFIG_LINE_MAXLEN];
  59. int lineno=0; /* current line number */
  60. char *s;
  61. char *start, *end;
  62. assert(f);
  63. fseek(f,0,SEEK_SET); /* make sure we start at the beginning of file */
  64. while(fgets(line, CONFIG_LINE_MAXLEN, f)) {
  65. lineno++;
  66. /* first strip comments */
  67. s = strchr(line,'#');
  68. if(s) {
  69. *s = 0; /* stop the line there */
  70. }
  71. /* walk to the end, remove end whitespace */
  72. s = index(line, 0); /* now we're at the null */
  73. do {
  74. *s = 0;
  75. s--;
  76. } while (isspace(*s));
  77. start = line;
  78. while(isspace(*start))
  79. start++;
  80. if(*start == 0)
  81. continue; /* this line has nothing on it */
  82. end = start;
  83. while(*end && !isspace(*end))
  84. end++;
  85. s = end;
  86. while(*s && isspace(*s))
  87. s++;
  88. if(!*end || !*s) { /* only a keyword on this line. no value. */
  89. log(LOG_WARNING,"Config line %d has keyword '%s' but no value. Skipping.",lineno,s);
  90. }
  91. *end = 0; /* null it out */
  92. /* prepare to parse the string into key / value */
  93. new = malloc(sizeof(struct config_line));
  94. new->key = strdup(start);
  95. new->value = strdup(s);
  96. log(LOG_DEBUG,"Config line %d: parsed keyword '%s', value '%s'",
  97. lineno, new->key, new->value);
  98. new->next = front;
  99. front = new;
  100. }
  101. return front;
  102. }
  103. void config_free_lines(struct config_line *front) {
  104. struct config_line *tmp;
  105. while(front) {
  106. tmp = front;
  107. front = tmp->next;
  108. free(tmp->key);
  109. free(tmp->value);
  110. free(tmp);
  111. }
  112. }
  113. int config_compare(struct config_line *c, char *key, int type, void *arg) {
  114. int i;
  115. if(strncasecmp(c->key,key,strlen(c->key)))
  116. return 0;
  117. /* it's a match. cast and assign. */
  118. log(LOG_DEBUG,"config_compare(): Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
  119. switch(type) {
  120. case CONFIG_TYPE_INT:
  121. *(int *)arg = atoi(c->value);
  122. break;
  123. case CONFIG_TYPE_BOOL:
  124. i = atoi(c->value);
  125. if (i != 0 && i != 1) {
  126. log(LOG_ERR, "Boolean keyword '%s' expects 0 or 1", c->key);
  127. return 0;
  128. }
  129. *(int *)arg = i;
  130. break;
  131. case CONFIG_TYPE_STRING:
  132. *(char **)arg = strdup(c->value);
  133. break;
  134. case CONFIG_TYPE_DOUBLE:
  135. *(double *)arg = atof(c->value);
  136. break;
  137. }
  138. return 1;
  139. }
  140. void config_assign(or_options_t *options, struct config_line *list) {
  141. /* iterate through list. for each item convert as appropriate and assign to 'options'. */
  142. while(list) {
  143. if(
  144. /* order matters here! abbreviated arguments use the first match. */
  145. /* string options */
  146. config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
  147. config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) ||
  148. config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
  149. /* int options */
  150. config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
  151. config_compare(list, "APPort", CONFIG_TYPE_INT, &options->APPort) ||
  152. config_compare(list, "OPPort", CONFIG_TYPE_INT, &options->OPPort) ||
  153. config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
  154. config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
  155. config_compare(list, "DirFetchPeriod", CONFIG_TYPE_INT, &options->DirFetchPeriod) ||
  156. config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
  157. config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
  158. config_compare(list, "Daemon", CONFIG_TYPE_BOOL, &options->Daemon) ||
  159. config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
  160. config_compare(list, "LinkPadding", CONFIG_TYPE_BOOL, &options->LinkPadding) ||
  161. /* float options */
  162. config_compare(list, "CoinWeight", CONFIG_TYPE_DOUBLE, &options->CoinWeight)
  163. ) {
  164. /* then we're ok. it matched something. */
  165. } else {
  166. log(LOG_WARNING,"config_assign(): Ignoring unknown keyword '%s'.",list->key);
  167. }
  168. list = list->next;
  169. }
  170. }
  171. /* return 0 if success, <0 if failure. */
  172. int getconfig(int argc, char **argv, or_options_t *options) {
  173. struct config_line *cl;
  174. FILE *cf;
  175. char fname[256];
  176. int i;
  177. const char *cmd;
  178. int result = 0;
  179. /* give reasonable defaults for each option */
  180. memset(options,0,sizeof(or_options_t));
  181. options->Daemon = 0;
  182. options->LogLevel = "debug";
  183. options->loglevel = LOG_DEBUG;
  184. options->CoinWeight = 0.8;
  185. options->LinkPadding = 0;
  186. options->DirFetchPeriod = 600;
  187. options->KeepalivePeriod = 300;
  188. options->MaxOnionsPending = 10;
  189. // options->ReconnectPeriod = 6001;
  190. /* get config lines from /etc/torrc and assign them */
  191. cmd = basename(argv[0]);
  192. snprintf(fname,256,"/etc/%src",cmd);
  193. cf = config_open(fname);
  194. if(cf) {
  195. /* we got it open. pull out the config lines. */
  196. cl = config_get_lines(cf);
  197. config_assign(options,cl);
  198. config_free_lines(cl);
  199. config_close(cf);
  200. }
  201. /* if we failed to open it, ignore */
  202. /* learn config file name, get config lines, assign them */
  203. i = 1;
  204. while(i < argc-1 && strcmp(argv[i],"-f")) {
  205. // log(LOG_DEBUG,"examining arg %d (%s), it's not -f.",i,argv[i]);
  206. i++;
  207. }
  208. if(i < argc-1) { /* we found one */
  209. log(LOG_DEBUG,"Opening specified config file '%s'",argv[i+1]);
  210. cf = config_open(argv[i+1]);
  211. if(!cf) { /* it's defined but not there. that's no good. */
  212. log(LOG_ERR, "Unable to open configuration file '%s'.",argv[i+1]);
  213. return -1;
  214. }
  215. cl = config_get_lines(cf);
  216. config_assign(options,cl);
  217. config_free_lines(cl);
  218. config_close(cf);
  219. }
  220. /* go through command-line variables too */
  221. cl = config_get_commandlines(argc,argv);
  222. config_assign(options,cl);
  223. config_free_lines(cl);
  224. /* print config */
  225. if (options->loglevel == LOG_DEBUG) {
  226. printf("LogLevel=%s\n",
  227. options->LogLevel);
  228. printf("RouterFile=%s, PrivateKeyFile=%s\n",
  229. options->RouterFile ? options->RouterFile : "(undefined)",
  230. options->PrivateKeyFile ? options->PrivateKeyFile : "(undefined)");
  231. printf("ORPort=%d, OPPort=%d, APPort=%d DirPort=%d\n",
  232. options->ORPort,options->OPPort,
  233. options->APPort,options->DirPort);
  234. printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
  235. options->CoinWeight,
  236. options->MaxConn,
  237. options->TrafficShaping,
  238. options->LinkPadding);
  239. printf("DirFetchPeriod=%d KeepalivePeriod=%d\n",
  240. options->DirFetchPeriod,
  241. options->KeepalivePeriod);
  242. printf("Daemon=%d\n", options->Daemon);
  243. }
  244. /* Validate options */
  245. if(options->LogLevel) {
  246. if(!strcmp(options->LogLevel,"emerg"))
  247. options->loglevel = LOG_EMERG;
  248. else if(!strcmp(options->LogLevel,"alert"))
  249. options->loglevel = LOG_ALERT;
  250. else if(!strcmp(options->LogLevel,"crit"))
  251. options->loglevel = LOG_CRIT;
  252. else if(!strcmp(options->LogLevel,"err"))
  253. options->loglevel = LOG_ERR;
  254. else if(!strcmp(options->LogLevel,"warning"))
  255. options->loglevel = LOG_WARNING;
  256. else if(!strcmp(options->LogLevel,"notice"))
  257. options->loglevel = LOG_NOTICE;
  258. else if(!strcmp(options->LogLevel,"info"))
  259. options->loglevel = LOG_INFO;
  260. else if(!strcmp(options->LogLevel,"debug"))
  261. options->loglevel = LOG_DEBUG;
  262. else {
  263. log(LOG_ERR,"LogLevel must be one of emerg|alert|crit|err|warning|notice|info|debug.");
  264. result = -1;
  265. }
  266. }
  267. if(options->RouterFile == NULL) {
  268. log(LOG_ERR,"RouterFile option required, but not found.");
  269. result = -1;
  270. }
  271. if(options->ORPort < 0) {
  272. log(LOG_ERR,"ORPort option required and must be a positive integer value.");
  273. result = -1;
  274. }
  275. if(options->ORPort > 0 && options->PrivateKeyFile == NULL) {
  276. log(LOG_ERR,"PrivateKeyFile option required for OR, but not found.");
  277. result = -1;
  278. }
  279. if(options->OPPort < 0) {
  280. log(LOG_ERR,"OPPort option can't be negative.");
  281. result = -1;
  282. }
  283. if(options->APPort < 0) {
  284. log(LOG_ERR,"APPort option can't be negative.");
  285. result = -1;
  286. }
  287. if(options->DirPort < 0) {
  288. log(LOG_ERR,"DirPort option can't be negative.");
  289. result = -1;
  290. }
  291. if(options->APPort > 1 &&
  292. (options->CoinWeight < 0.0 || options->CoinWeight >= 1.0)) {
  293. log(LOG_ERR,"CoinWeight option must be >=0.0 and <1.0.");
  294. result = -1;
  295. }
  296. if(options->MaxConn < 1) {
  297. log(LOG_ERR,"MaxConn option must be a non-zero positive integer.");
  298. result = -1;
  299. }
  300. if(options->MaxConn >= MAXCONNECTIONS) {
  301. log(LOG_ERR,"MaxConn option must be less than %d.", MAXCONNECTIONS);
  302. result = -1;
  303. }
  304. if(options->DirFetchPeriod < 1) {
  305. log(LOG_ERR,"DirFetchPeriod option must be positive.");
  306. result = -1;
  307. }
  308. if(options->KeepalivePeriod < 1) {
  309. log(LOG_ERR,"KeepalivePeriod option must be positive.");
  310. result = -1;
  311. }
  312. return result;
  313. }