xshared.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <getopt.h>
  2. #include <libgen.h>
  3. #include <netdb.h>
  4. #include <stdbool.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <xtables.h>
  10. #include "xshared.h"
  11. /*
  12. * Print out any special helps. A user might like to be able to add a --help
  13. * to the commandline, and see expected results. So we call help for all
  14. * specified matches and targets.
  15. */
  16. void print_extension_helps(const struct xtables_target *t,
  17. const struct xtables_rule_match *m)
  18. {
  19. for (; t != NULL; t = t->next) {
  20. if (t->used) {
  21. printf("\n");
  22. if (t->help == NULL)
  23. printf("%s does not take any options\n",
  24. t->name);
  25. else
  26. t->help();
  27. }
  28. }
  29. for (; m != NULL; m = m->next) {
  30. printf("\n");
  31. if (m->match->help == NULL)
  32. printf("%s does not take any options\n",
  33. m->match->name);
  34. else
  35. m->match->help();
  36. }
  37. }
  38. const char *
  39. proto_to_name(uint8_t proto, int nolookup)
  40. {
  41. unsigned int i;
  42. if (proto && !nolookup) {
  43. struct protoent *pent = getprotobynumber(proto);
  44. if (pent)
  45. return pent->p_name;
  46. }
  47. for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
  48. if (xtables_chain_protos[i].num == proto)
  49. return xtables_chain_protos[i].name;
  50. return NULL;
  51. }
  52. static struct xtables_match *
  53. find_proto(const char *pname, enum xtables_tryload tryload,
  54. int nolookup, struct xtables_rule_match **matches)
  55. {
  56. unsigned int proto;
  57. if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) {
  58. const char *protoname = proto_to_name(proto, nolookup);
  59. if (protoname)
  60. return xtables_find_match(protoname, tryload, matches);
  61. } else
  62. return xtables_find_match(pname, tryload, matches);
  63. return NULL;
  64. }
  65. /*
  66. * Some explanations (after four different bugs in 3 different releases): If
  67. * we encounter a parameter, that has not been parsed yet, it's not an option
  68. * of an explicitly loaded match or a target. However, we support implicit
  69. * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at
  70. * the same time 'load tcp protocol match on demand if we specify --dport'.
  71. *
  72. * To make this work, we need to make sure:
  73. * - the parameter has not been parsed by a match (m above)
  74. * - a protocol has been specified
  75. * - the protocol extension has not been loaded yet, or is loaded and unused
  76. * [think of ip6tables-restore!]
  77. * - the protocol extension can be successively loaded
  78. */
  79. static bool should_load_proto(struct iptables_command_state *cs)
  80. {
  81. if (cs->protocol == NULL)
  82. return false;
  83. if (find_proto(cs->protocol, XTF_DONT_LOAD,
  84. cs->options & OPT_NUMERIC, NULL) == NULL)
  85. return true;
  86. return !cs->proto_used;
  87. }
  88. struct xtables_match *load_proto(struct iptables_command_state *cs)
  89. {
  90. if (!should_load_proto(cs))
  91. return NULL;
  92. return find_proto(cs->protocol, XTF_TRY_LOAD,
  93. cs->options & OPT_NUMERIC, &cs->matches);
  94. }
  95. int command_default(struct iptables_command_state *cs,
  96. struct xtables_globals *gl)
  97. {
  98. struct xtables_rule_match *matchp;
  99. struct xtables_match *m;
  100. if (cs->target != NULL &&
  101. (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
  102. cs->c >= cs->target->option_offset &&
  103. cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
  104. xtables_option_tpcall(cs->c, cs->argv, cs->invert,
  105. cs->target, &cs->fw);
  106. return 0;
  107. }
  108. for (matchp = cs->matches; matchp; matchp = matchp->next) {
  109. m = matchp->match;
  110. if (matchp->completed ||
  111. (m->x6_parse == NULL && m->parse == NULL))
  112. continue;
  113. if (cs->c < matchp->match->option_offset ||
  114. cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
  115. continue;
  116. xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw);
  117. return 0;
  118. }
  119. /* Try loading protocol */
  120. m = load_proto(cs);
  121. if (m != NULL) {
  122. size_t size;
  123. cs->proto_used = 1;
  124. size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
  125. m->m = xtables_calloc(1, size);
  126. m->m->u.match_size = size;
  127. strcpy(m->m->u.user.name, m->name);
  128. m->m->u.user.revision = m->revision;
  129. xs_init_match(m);
  130. if (m->x6_options != NULL)
  131. gl->opts = xtables_options_xfrm(gl->orig_opts,
  132. gl->opts,
  133. m->x6_options,
  134. &m->option_offset);
  135. else
  136. gl->opts = xtables_merge_options(gl->orig_opts,
  137. gl->opts,
  138. m->extra_opts,
  139. &m->option_offset);
  140. if (gl->opts == NULL)
  141. xtables_error(OTHER_PROBLEM, "can't alloc memory!");
  142. optind--;
  143. /* Indicate to rerun getopt *immediately* */
  144. return 1;
  145. }
  146. if (cs->c == ':')
  147. xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
  148. "requires an argument", cs->argv[optind-1]);
  149. if (cs->c == '?')
  150. xtables_error(PARAMETER_PROBLEM, "unknown option "
  151. "\"%s\"", cs->argv[optind-1]);
  152. xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
  153. return 0;
  154. }
  155. static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb)
  156. {
  157. for (; cb->name != NULL; ++cb)
  158. if (strcmp(cb->name, cmd) == 0)
  159. return cb->main;
  160. return NULL;
  161. }
  162. int subcmd_main(int argc, char **argv, const struct subcommand *cb)
  163. {
  164. const char *cmd = basename(*argv);
  165. mainfunc_t f = subcmd_get(cmd, cb);
  166. if (f == NULL && argc > 1) {
  167. /*
  168. * Unable to find a main method for our command name?
  169. * Let's try again with the first argument!
  170. */
  171. ++argv;
  172. --argc;
  173. f = subcmd_get(*argv, cb);
  174. }
  175. /* now we should have a valid function pointer */
  176. if (f != NULL)
  177. return f(argc, argv);
  178. fprintf(stderr, "ERROR: No valid subcommand given.\nValid subcommands:\n");
  179. for (; cb->name != NULL; ++cb)
  180. fprintf(stderr, " * %s\n", cb->name);
  181. exit(EXIT_FAILURE);
  182. }
  183. void xs_init_target(struct xtables_target *target)
  184. {
  185. if (target->udata_size != 0) {
  186. free(target->udata);
  187. target->udata = calloc(1, target->udata_size);
  188. if (target->udata == NULL)
  189. xtables_error(RESOURCE_PROBLEM, "malloc");
  190. }
  191. if (target->init != NULL)
  192. target->init(target->t);
  193. }
  194. void xs_init_match(struct xtables_match *match)
  195. {
  196. if (match->udata_size != 0) {
  197. /*
  198. * As soon as a subsequent instance of the same match
  199. * is used, e.g. "-m time -m time", the first instance
  200. * is no longer reachable anyway, so we can free udata.
  201. * Same goes for target.
  202. */
  203. free(match->udata);
  204. match->udata = calloc(1, match->udata_size);
  205. if (match->udata == NULL)
  206. xtables_error(RESOURCE_PROBLEM, "malloc");
  207. }
  208. if (match->init != NULL)
  209. match->init(match->m);
  210. }