config.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. if(strncasecmp(c->key,key,strlen(c->key)))
  115. return 0;
  116. /* it's a match. cast and assign. */
  117. log(LOG_DEBUG,"config_compare(): Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
  118. switch(type) {
  119. case CONFIG_TYPE_INT:
  120. *(int *)arg = atoi(c->value);
  121. break;
  122. case CONFIG_TYPE_STRING:
  123. *(char **)arg = strdup(c->value);
  124. break;
  125. case CONFIG_TYPE_DOUBLE:
  126. *(double *)arg = atof(c->value);
  127. break;
  128. }
  129. return 1;
  130. }
  131. void config_assign(or_options_t *options, struct config_line *list) {
  132. /* iterate through list. for each item convert as appropriate and assign to 'options'. */
  133. while(list) {
  134. if(
  135. /* order matters here! abbreviated arguments use the first match. */
  136. /* string options */
  137. config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
  138. config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) ||
  139. config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
  140. /* int options */
  141. config_compare(list, "Role", CONFIG_TYPE_INT, &options->Role) ||
  142. config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
  143. config_compare(list, "APPort", CONFIG_TYPE_INT, &options->APPort) ||
  144. config_compare(list, "OPPort", CONFIG_TYPE_INT, &options->OPPort) ||
  145. config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
  146. config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
  147. config_compare(list, "TrafficShaping", CONFIG_TYPE_INT, &options->TrafficShaping) ||
  148. config_compare(list, "LinkPadding", CONFIG_TYPE_INT, &options->LinkPadding) ||
  149. config_compare(list, "DirRebuildPeriod",CONFIG_TYPE_INT, &options->DirRebuildPeriod) ||
  150. config_compare(list, "DirFetchPeriod", CONFIG_TYPE_INT, &options->DirFetchPeriod) ||
  151. config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
  152. /* float options */
  153. config_compare(list, "CoinWeight", CONFIG_TYPE_DOUBLE, &options->CoinWeight)
  154. ) {
  155. /* then we're ok. it matched something. */
  156. } else {
  157. log(LOG_WARNING,"config_assign(): Ignoring unknown keyword '%s'.",list->key);
  158. }
  159. list = list->next;
  160. }
  161. }
  162. /* return 0 if success, <0 if failure. */
  163. int getconfig(int argc, char **argv, or_options_t *options) {
  164. struct config_line *cl;
  165. FILE *cf;
  166. char fname[256];
  167. int i;
  168. const char *cmd;
  169. int result = 0;
  170. /* give reasonable defaults for each option */
  171. memset(options,0,sizeof(or_options_t));
  172. options->LogLevel = "debug";
  173. options->loglevel = LOG_DEBUG;
  174. options->CoinWeight = 0.8;
  175. options->LinkPadding = 0;
  176. options->DirRebuildPeriod = 600;
  177. options->DirFetchPeriod = 6000;
  178. options->KeepalivePeriod = 300;
  179. // options->ReconnectPeriod = 6001;
  180. options->Role = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
  181. /* get config lines from /etc/torrc and assign them */
  182. cmd = basename(argv[0]);
  183. snprintf(fname,256,"/etc/%src",cmd);
  184. cf = config_open(fname);
  185. if(cf) {
  186. /* we got it open. pull out the config lines. */
  187. cl = config_get_lines(cf);
  188. config_assign(options,cl);
  189. config_free_lines(cl);
  190. config_close(cf);
  191. }
  192. /* if we failed to open it, ignore */
  193. /* learn config file name, get config lines, assign them */
  194. i = 1;
  195. while(i < argc-1 && strcmp(argv[i],"-f")) {
  196. // log(LOG_DEBUG,"examining arg %d (%s), it's not -f.",i,argv[i]);
  197. i++;
  198. }
  199. if(i < argc-1) { /* we found one */
  200. log(LOG_DEBUG,"Opening specified config file '%s'",argv[i+1]);
  201. cf = config_open(argv[i+1]);
  202. if(!cf) { /* it's defined but not there. that's no good. */
  203. log(LOG_ERR, "Unable to open configuration file '%s'.",argv[i+1]);
  204. return -1;
  205. }
  206. cl = config_get_lines(cf);
  207. config_assign(options,cl);
  208. config_free_lines(cl);
  209. config_close(cf);
  210. }
  211. /* go through command-line variables too */
  212. cl = config_get_commandlines(argc,argv);
  213. config_assign(options,cl);
  214. config_free_lines(cl);
  215. /* print config */
  216. if (options->loglevel == LOG_DEBUG) {
  217. printf("LogLevel=%s, Role=%d\n",
  218. options->LogLevel,
  219. options->Role);
  220. printf("RouterFile=%s, PrivateKeyFile=%s\n",
  221. options->RouterFile ? options->RouterFile : "(undefined)",
  222. options->PrivateKeyFile ? options->PrivateKeyFile : "(undefined)");
  223. printf("ORPort=%d, OPPort=%d, APPort=%d DirPort=%d\n",
  224. options->ORPort,options->OPPort,
  225. options->APPort,options->DirPort);
  226. printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d, LinkPadding=%d\n",
  227. options->CoinWeight,
  228. options->MaxConn,
  229. options->TrafficShaping,
  230. options->LinkPadding);
  231. printf("DirRebuildPeriod=%d, DirFetchPeriod=%d KeepalivePeriod=%d\n",
  232. options->DirRebuildPeriod,
  233. options->DirFetchPeriod,
  234. options->KeepalivePeriod);
  235. }
  236. /* Validate options */
  237. if(options->LogLevel) {
  238. if(!strcmp(options->LogLevel,"emerg"))
  239. options->loglevel = LOG_EMERG;
  240. else if(!strcmp(options->LogLevel,"alert"))
  241. options->loglevel = LOG_ALERT;
  242. else if(!strcmp(options->LogLevel,"crit"))
  243. options->loglevel = LOG_CRIT;
  244. else if(!strcmp(options->LogLevel,"err"))
  245. options->loglevel = LOG_ERR;
  246. else if(!strcmp(options->LogLevel,"warning"))
  247. options->loglevel = LOG_WARNING;
  248. else if(!strcmp(options->LogLevel,"notice"))
  249. options->loglevel = LOG_NOTICE;
  250. else if(!strcmp(options->LogLevel,"info"))
  251. options->loglevel = LOG_INFO;
  252. else if(!strcmp(options->LogLevel,"debug"))
  253. options->loglevel = LOG_DEBUG;
  254. else {
  255. log(LOG_ERR,"LogLevel must be one of emerg|alert|crit|err|warning|notice|info|debug.");
  256. result = -1;
  257. }
  258. }
  259. if(options->Role < 0 || options->Role > 63) {
  260. log(LOG_ERR,"Role option must be an integer between 0 and 63 (inclusive).");
  261. result = -1;
  262. }
  263. if(options->RouterFile == NULL) {
  264. log(LOG_ERR,"RouterFile option required, but not found.");
  265. result = -1;
  266. }
  267. if(ROLE_IS_OR(options->Role) && options->PrivateKeyFile == NULL) {
  268. log(LOG_ERR,"PrivateKeyFile option required for OR, but not found.");
  269. result = -1;
  270. }
  271. if((options->Role & ROLE_OR_LISTEN) && options->ORPort < 1) {
  272. log(LOG_ERR,"ORPort option required and must be a positive integer value.");
  273. result = -1;
  274. }
  275. if((options->Role & ROLE_OP_LISTEN) && options->OPPort < 1) {
  276. log(LOG_ERR,"OPPort option required and must be a positive integer value.");
  277. result = -1;
  278. }
  279. if((options->Role & ROLE_AP_LISTEN) && options->APPort < 1) {
  280. log(LOG_ERR,"APPort option required and must be a positive integer value.");
  281. result = -1;
  282. }
  283. if((options->Role & ROLE_DIR_LISTEN) && options->DirPort < 1) {
  284. log(LOG_ERR,"DirPort option required and must be a positive integer value.");
  285. result = -1;
  286. }
  287. if((options->Role & ROLE_AP_LISTEN) &&
  288. (options->CoinWeight < 0.0 || options->CoinWeight >= 1.0)) {
  289. log(LOG_ERR,"CoinWeight option must be a value from 0.0 upto 1.0, but not including 1.0.");
  290. result = -1;
  291. }
  292. if(options->MaxConn <= 0) {
  293. log(LOG_ERR,"MaxConn option must be a non-zero positive integer.");
  294. result = -1;
  295. }
  296. if(options->MaxConn >= MAXCONNECTIONS) {
  297. log(LOG_ERR,"MaxConn option must be less than %d.", MAXCONNECTIONS);
  298. result = -1;
  299. }
  300. if(options->TrafficShaping != 0 && options->TrafficShaping != 1) {
  301. log(LOG_ERR,"TrafficShaping option must be either 0 or 1.");
  302. result = -1;
  303. }
  304. if(options->LinkPadding != 0 && options->LinkPadding != 1) {
  305. log(LOG_ERR,"LinkPadding option must be either 0 or 1.");
  306. result = -1;
  307. }
  308. if(options->DirRebuildPeriod < 1) {
  309. log(LOG_ERR,"DirRebuildPeriod option must be positive.");
  310. result = -1;
  311. }
  312. if(options->DirFetchPeriod < 1) {
  313. log(LOG_ERR,"DirFetchPeriod option must be positive.");
  314. result = -1;
  315. }
  316. if(options->KeepalivePeriod < 1) {
  317. log(LOG_ERR,"KeepalivePeriod option must be positive.");
  318. result = -1;
  319. }
  320. return result;
  321. }