net_iptables.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /**
  2. * @file net_iptables.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * @section DESCRIPTION
  30. *
  31. * iptables and ebtables module.
  32. *
  33. * Note that all iptables/ebtables commands (in general) must be issued synchronously, or
  34. * the kernel may randomly report errors if there is another iptables/ebtables command in
  35. * progress. To solve this, the NCD process contains a single "iptables lock". All
  36. * iptables/ebtables commands exposed here go through that lock.
  37. * In case you wish to call iptables/ebtables directly, the lock is exposed via
  38. * net.iptables.lock().
  39. *
  40. * Synopsis:
  41. * net.iptables.append(string table, string chain, string arg1 ...)
  42. * Description:
  43. * init: iptables -t table -A chain arg1 ...
  44. * deinit: iptables -t table -D chain arg1 ...
  45. *
  46. * Synopsis:
  47. * net.iptables.insert(string table, string chain, string arg1 ...)
  48. * Description:
  49. * init: iptables -t table -I chain arg1 ...
  50. * deinit: iptables -t table -D chain arg1 ...
  51. *
  52. * Synopsis:
  53. * net.iptables.policy(string table, string chain, string target, string revert_target)
  54. * Description:
  55. * init: iptables -t table -P chain target
  56. * deinit: iptables -t table -P chain revert_target
  57. *
  58. * Synopsis:
  59. * net.iptables.newchain(string table, string chain)
  60. * net.iptables.newchain(string chain) // DEPRECATED, defaults to table="filter"
  61. * Description:
  62. * init: iptables -t table -N chain
  63. * deinit: iptables -t table -X chain
  64. *
  65. * Synopsis:
  66. * net.ebtables.append(string table, string chain, string arg1 ...)
  67. * Description:
  68. * init: ebtables -t table -A chain arg1 ...
  69. * deinit: ebtables -t table -D chain arg1 ...
  70. *
  71. * Synopsis:
  72. * net.ebtables.insert(string table, string chain, string arg1 ...)
  73. * Description:
  74. * init: ebtables -t table -I chain arg1 ...
  75. * deinit: ebtables -t table -D chain arg1 ...
  76. *
  77. * Synopsis:
  78. * net.ebtables.policy(string table, string chain, string target, string revert_target)
  79. * Description:
  80. * init: ebtables -t table -P chain target
  81. * deinit: ebtables -t table -P chain revert_target
  82. *
  83. * Synopsis:
  84. * net.ebtables.newchain(string table, string chain)
  85. * Description:
  86. * init: ebtables -t table -N chain
  87. * deinit: ebtables -t table -X chain
  88. *
  89. * Synopsis:
  90. * net.iptables.lock()
  91. * Description:
  92. * Use at the beginning of a block of custom iptables/ebtables commands to make sure
  93. * they do not interfere with other iptables/ebtables commands.
  94. * WARNING: improper usage of the lock can lead to deadlock. In particular:
  95. * - Do not call any of the iptables/ebtables wrappers above from a lock section;
  96. * those will attempt to aquire the lock themselves.
  97. * - Do not enter another lock section from a lock section.
  98. * - Do not perform any potentially long wait from a lock section.
  99. *
  100. * Synopsis:
  101. * net.iptables.lock::unlock()
  102. * Description:
  103. * Use at the end of a block of custom iptables/ebtables commands to make sure
  104. * they do not interfere with other iptables/ebtables commands.
  105. */
  106. #include <stdlib.h>
  107. #include <string.h>
  108. #include <unistd.h>
  109. #include <misc/debug.h>
  110. #include <misc/find_program.h>
  111. #include <misc/balloc.h>
  112. #include <ncd/extra/BEventLock.h>
  113. #include <ncd/modules/command_template.h>
  114. #include <generated/blog_channel_ncd_net_iptables.h>
  115. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  116. #define ModuleGlobal(i) ((i)->m->group->group_state)
  117. static void template_free_func (void *vo, int is_error);
  118. struct global {
  119. BEventLock iptables_lock;
  120. };
  121. struct instance {
  122. NCDModuleInst *i;
  123. command_template_instance cti;
  124. };
  125. struct unlock_instance;
  126. #define LOCK_STATE_LOCKING 1
  127. #define LOCK_STATE_LOCKED 2
  128. #define LOCK_STATE_UNLOCKED 3
  129. #define LOCK_STATE_RELOCKING 4
  130. struct lock_instance {
  131. NCDModuleInst *i;
  132. BEventLockJob lock_job;
  133. struct unlock_instance *unlock;
  134. int state;
  135. };
  136. struct unlock_instance {
  137. NCDModuleInst *i;
  138. struct lock_instance *lock;
  139. };
  140. static void unlock_free (struct unlock_instance *o);
  141. static int build_append_or_insert_cmdline (NCDModuleInst *i, NCDValRef args, const char *prog, int remove, char **exec, CmdLine *cl, const char *type)
  142. {
  143. // read arguments
  144. NCDValRef table_arg;
  145. NCDValRef chain_arg;
  146. if (!NCDVal_ListReadHead(args, 2, &table_arg, &chain_arg)) {
  147. ModuleLog(i, BLOG_ERROR, "wrong arity");
  148. goto fail0;
  149. }
  150. if (!NCDVal_IsStringNoNulls(table_arg) || !NCDVal_IsStringNoNulls(chain_arg)) {
  151. ModuleLog(i, BLOG_ERROR, "wrong type");
  152. goto fail0;
  153. }
  154. const char *table = NCDVal_StringData(table_arg);
  155. size_t table_len = NCDVal_StringLength(table_arg);
  156. const char *chain = NCDVal_StringData(chain_arg);
  157. size_t chain_len = NCDVal_StringLength(chain_arg);
  158. // find program
  159. if (!(*exec = badvpn_find_program(prog))) {
  160. ModuleLog(i, BLOG_ERROR, "failed to find program: %s", prog);
  161. goto fail0;
  162. }
  163. // start cmdline
  164. if (!CmdLine_Init(cl)) {
  165. ModuleLog(i, BLOG_ERROR, "CmdLine_Init failed");
  166. goto fail1;
  167. }
  168. // add header
  169. if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_AppendNoNull(cl, table, table_len) || !CmdLine_Append(cl, (remove ? "-D" : type)) || !CmdLine_AppendNoNull(cl, chain, chain_len)) {
  170. ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
  171. goto fail2;
  172. }
  173. // add additional arguments
  174. size_t count = NCDVal_ListCount(args);
  175. for (size_t j = 2; j < count; j++) {
  176. NCDValRef arg = NCDVal_ListGet(args, j);
  177. if (!NCDVal_IsStringNoNulls(arg)) {
  178. ModuleLog(i, BLOG_ERROR, "wrong type");
  179. goto fail2;
  180. }
  181. if (!CmdLine_AppendNoNull(cl, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
  182. ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
  183. goto fail2;
  184. }
  185. }
  186. // finish
  187. if (!CmdLine_Finish(cl)) {
  188. ModuleLog(i, BLOG_ERROR, "CmdLine_Finish failed");
  189. goto fail2;
  190. }
  191. return 1;
  192. fail2:
  193. CmdLine_Free(cl);
  194. fail1:
  195. free(*exec);
  196. fail0:
  197. return 0;
  198. }
  199. static int build_append_cmdline (NCDModuleInst *i, NCDValRef args, const char *prog, int remove, char **exec, CmdLine *cl)
  200. {
  201. return build_append_or_insert_cmdline(i, args, prog, remove, exec, cl, "-A");
  202. }
  203. static int build_insert_cmdline (NCDModuleInst *i, NCDValRef args, const char *prog, int remove, char **exec, CmdLine *cl)
  204. {
  205. return build_append_or_insert_cmdline(i, args, prog, remove, exec, cl, "-I");
  206. }
  207. static int build_policy_cmdline (NCDModuleInst *i, NCDValRef args, const char *prog, int remove, char **exec, CmdLine *cl)
  208. {
  209. // read arguments
  210. NCDValRef table_arg;
  211. NCDValRef chain_arg;
  212. NCDValRef target_arg;
  213. NCDValRef revert_target_arg;
  214. if (!NCDVal_ListRead(args, 4, &table_arg, &chain_arg, &target_arg, &revert_target_arg)) {
  215. ModuleLog(i, BLOG_ERROR, "wrong arity");
  216. goto fail0;
  217. }
  218. if (!NCDVal_IsStringNoNulls(table_arg) || !NCDVal_IsStringNoNulls(chain_arg) ||
  219. !NCDVal_IsStringNoNulls(target_arg) || !NCDVal_IsStringNoNulls(revert_target_arg)
  220. ) {
  221. ModuleLog(i, BLOG_ERROR, "wrong type");
  222. goto fail0;
  223. }
  224. const char *table = NCDVal_StringData(table_arg);
  225. size_t table_len = NCDVal_StringLength(table_arg);
  226. const char *chain = NCDVal_StringData(chain_arg);
  227. size_t chain_len = NCDVal_StringLength(chain_arg);
  228. const char *target = NCDVal_StringData(target_arg);
  229. size_t target_len = NCDVal_StringLength(target_arg);
  230. const char *revert_target = NCDVal_StringData(revert_target_arg);
  231. size_t revert_target_len = NCDVal_StringLength(revert_target_arg);
  232. // find program
  233. if (!(*exec = badvpn_find_program(prog))) {
  234. ModuleLog(i, BLOG_ERROR, "failed to find program: %s", prog);
  235. goto fail0;
  236. }
  237. // start cmdline
  238. if (!CmdLine_Init(cl)) {
  239. ModuleLog(i, BLOG_ERROR, "CmdLine_Init failed");
  240. goto fail1;
  241. }
  242. // add arguments
  243. if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_AppendNoNull(cl, table, table_len) ||
  244. !CmdLine_Append(cl, "-P") || !CmdLine_AppendNoNull(cl, chain, chain_len) ||
  245. !CmdLine_AppendNoNull(cl, (remove ? revert_target : target), (remove ? revert_target_len : target_len))
  246. ) {
  247. ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
  248. goto fail2;
  249. }
  250. // finish
  251. if (!CmdLine_Finish(cl)) {
  252. ModuleLog(i, BLOG_ERROR, "CmdLine_Finish failed");
  253. goto fail2;
  254. }
  255. return 1;
  256. fail2:
  257. CmdLine_Free(cl);
  258. fail1:
  259. free(*exec);
  260. fail0:
  261. return 0;
  262. }
  263. static int build_newchain_cmdline (NCDModuleInst *i, NCDValRef args, const char *prog, int remove, char **exec, CmdLine *cl)
  264. {
  265. // read arguments
  266. NCDValRef table_arg = NCDVal_NewInvalid();
  267. NCDValRef chain_arg;
  268. if (!NCDVal_ListRead(args, 1, &chain_arg) && !NCDVal_ListRead(args, 2, &table_arg, &chain_arg)) {
  269. ModuleLog(i, BLOG_ERROR, "wrong arity");
  270. goto fail0;
  271. }
  272. if ((!NCDVal_IsInvalid(table_arg) && !NCDVal_IsStringNoNulls(table_arg)) || !NCDVal_IsStringNoNulls(chain_arg)) {
  273. ModuleLog(i, BLOG_ERROR, "wrong type");
  274. goto fail0;
  275. }
  276. const char *table = (NCDVal_IsInvalid(table_arg) ? "filter" : NCDVal_StringData(table_arg));
  277. size_t table_len = (NCDVal_IsInvalid(table_arg) ? 6 : NCDVal_StringLength(table_arg));
  278. const char *chain = NCDVal_StringData(chain_arg);
  279. size_t chain_len = NCDVal_StringLength(chain_arg);
  280. // find program
  281. if (!(*exec = badvpn_find_program(prog))) {
  282. ModuleLog(i, BLOG_ERROR, "failed to find program: %s", prog);
  283. goto fail0;
  284. }
  285. // start cmdline
  286. if (!CmdLine_Init(cl)) {
  287. ModuleLog(i, BLOG_ERROR, "CmdLine_Init failed");
  288. goto fail1;
  289. }
  290. // add arguments
  291. if (!CmdLine_AppendMulti(cl, 2, *exec, "-t") ||
  292. !CmdLine_AppendNoNull(cl, table, table_len) ||
  293. !CmdLine_Append(cl, (remove ? "-X" : "-N")) ||
  294. !CmdLine_AppendNoNull(cl, chain, chain_len)
  295. ) {
  296. ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
  297. goto fail2;
  298. }
  299. // finish
  300. if (!CmdLine_Finish(cl)) {
  301. ModuleLog(i, BLOG_ERROR, "CmdLine_Finish failed");
  302. goto fail2;
  303. }
  304. return 1;
  305. fail2:
  306. CmdLine_Free(cl);
  307. fail1:
  308. free(*exec);
  309. fail0:
  310. return 0;
  311. }
  312. static int build_iptables_append_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  313. {
  314. return build_append_cmdline(i, args, "iptables", remove, exec, cl);
  315. }
  316. static int build_iptables_insert_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  317. {
  318. return build_insert_cmdline(i, args, "iptables", remove, exec, cl);
  319. }
  320. static int build_iptables_policy_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  321. {
  322. return build_policy_cmdline(i, args, "iptables", remove, exec, cl);
  323. }
  324. static int build_iptables_newchain_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  325. {
  326. return build_newchain_cmdline(i, args, "iptables", remove, exec, cl);
  327. }
  328. static int build_ebtables_append_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  329. {
  330. return build_append_cmdline(i, args, "ebtables", remove, exec, cl);
  331. }
  332. static int build_ebtables_insert_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  333. {
  334. return build_insert_cmdline(i, args, "ebtables", remove, exec, cl);
  335. }
  336. static int build_ebtables_policy_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  337. {
  338. return build_policy_cmdline(i, args, "ebtables", remove, exec, cl);
  339. }
  340. static int build_ebtables_newchain_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **exec, CmdLine *cl)
  341. {
  342. return build_newchain_cmdline(i, args, "ebtables", remove, exec, cl);
  343. }
  344. static void lock_job_handler (struct lock_instance *o)
  345. {
  346. ASSERT(o->state == LOCK_STATE_LOCKING || o->state == LOCK_STATE_RELOCKING)
  347. if (o->state == LOCK_STATE_LOCKING) {
  348. ASSERT(!o->unlock)
  349. // up
  350. NCDModuleInst_Backend_Up(o->i);
  351. // set state locked
  352. o->state = LOCK_STATE_LOCKED;
  353. }
  354. else if (o->state == LOCK_STATE_RELOCKING) {
  355. ASSERT(o->unlock)
  356. ASSERT(o->unlock->lock == o)
  357. // die unlock
  358. unlock_free(o->unlock);
  359. o->unlock = NULL;
  360. // set state locked
  361. o->state = LOCK_STATE_LOCKED;
  362. }
  363. }
  364. static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
  365. {
  366. // allocate global state structure
  367. struct global *g = BAlloc(sizeof(*g));
  368. if (!g) {
  369. BLog(BLOG_ERROR, "BAlloc failed");
  370. return 0;
  371. }
  372. // set group state pointer
  373. group->group_state = g;
  374. // init iptables lock
  375. BEventLock_Init(&g->iptables_lock, BReactor_PendingGroup(params->reactor));
  376. return 1;
  377. }
  378. static void func_globalfree (struct NCDInterpModuleGroup *group)
  379. {
  380. struct global *g = group->group_state;
  381. // free iptables lock
  382. BEventLock_Free(&g->iptables_lock);
  383. // free global state structure
  384. BFree(g);
  385. }
  386. static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, command_template_build_cmdline build_cmdline)
  387. {
  388. struct global *g = ModuleGlobal(i);
  389. struct instance *o = vo;
  390. o->i = i;
  391. command_template_new(&o->cti, i, params, build_cmdline, template_free_func, o, BLOG_CURRENT_CHANNEL, &g->iptables_lock);
  392. }
  393. void template_free_func (void *vo, int is_error)
  394. {
  395. struct instance *o = vo;
  396. if (is_error) {
  397. NCDModuleInst_Backend_DeadError(o->i);
  398. } else {
  399. NCDModuleInst_Backend_Dead(o->i);
  400. }
  401. }
  402. static void append_iptables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  403. {
  404. func_new(vo, i, params, build_iptables_append_cmdline);
  405. }
  406. static void insert_iptables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  407. {
  408. func_new(vo, i, params, build_iptables_insert_cmdline);
  409. }
  410. static void policy_iptables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  411. {
  412. func_new(vo, i, params, build_iptables_policy_cmdline);
  413. }
  414. static void newchain_iptables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  415. {
  416. func_new(vo, i, params, build_iptables_newchain_cmdline);
  417. }
  418. static void append_ebtables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  419. {
  420. func_new(vo, i, params, build_ebtables_append_cmdline);
  421. }
  422. static void insert_ebtables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  423. {
  424. func_new(vo, i, params, build_ebtables_insert_cmdline);
  425. }
  426. static void policy_ebtables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  427. {
  428. func_new(vo, i, params, build_ebtables_policy_cmdline);
  429. }
  430. static void newchain_ebtables_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  431. {
  432. func_new(vo, i, params, build_ebtables_newchain_cmdline);
  433. }
  434. static void func_die (void *vo)
  435. {
  436. struct instance *o = vo;
  437. command_template_die(&o->cti);
  438. }
  439. static void lock_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  440. {
  441. struct global *g = ModuleGlobal(i);
  442. struct lock_instance *o = vo;
  443. o->i = i;
  444. // init lock job
  445. BEventLockJob_Init(&o->lock_job, &g->iptables_lock, (BEventLock_handler)lock_job_handler, o);
  446. BEventLockJob_Wait(&o->lock_job);
  447. // set no unlock
  448. o->unlock = NULL;
  449. // set state locking
  450. o->state = LOCK_STATE_LOCKING;
  451. }
  452. static void lock_func_die (void *vo)
  453. {
  454. struct lock_instance *o = vo;
  455. if (o->state == LOCK_STATE_UNLOCKED) {
  456. ASSERT(o->unlock)
  457. ASSERT(o->unlock->lock == o)
  458. o->unlock->lock = NULL;
  459. }
  460. else if (o->state == LOCK_STATE_RELOCKING) {
  461. ASSERT(o->unlock)
  462. ASSERT(o->unlock->lock == o)
  463. unlock_free(o->unlock);
  464. }
  465. else {
  466. ASSERT(!o->unlock)
  467. }
  468. // free lock job
  469. BEventLockJob_Free(&o->lock_job);
  470. // dead
  471. NCDModuleInst_Backend_Dead(o->i);
  472. }
  473. static void unlock_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
  474. {
  475. struct unlock_instance *o = vo;
  476. o->i = i;
  477. // get lock lock
  478. struct lock_instance *lock = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
  479. // make sure lock doesn't already have an unlock
  480. if (lock->unlock) {
  481. BLog(BLOG_ERROR, "lock already has an unlock");
  482. goto fail0;
  483. }
  484. // make sure lock is locked
  485. if (lock->state != LOCK_STATE_LOCKED) {
  486. BLog(BLOG_ERROR, "lock is not locked");
  487. goto fail0;
  488. }
  489. // set lock
  490. o->lock = lock;
  491. // set unlock in lock
  492. lock->unlock = o;
  493. // up
  494. NCDModuleInst_Backend_Up(o->i);
  495. // release lock
  496. BEventLockJob_Release(&lock->lock_job);
  497. // set lock state unlocked
  498. lock->state = LOCK_STATE_UNLOCKED;
  499. return;
  500. fail0:
  501. NCDModuleInst_Backend_DeadError(i);
  502. }
  503. static void unlock_func_die (void *vo)
  504. {
  505. struct unlock_instance *o = vo;
  506. // if lock is gone, die right away
  507. if (!o->lock) {
  508. unlock_free(o);
  509. return;
  510. }
  511. ASSERT(o->lock->unlock == o)
  512. ASSERT(o->lock->state == LOCK_STATE_UNLOCKED)
  513. // wait lock
  514. BEventLockJob_Wait(&o->lock->lock_job);
  515. // set lock state relocking
  516. o->lock->state = LOCK_STATE_RELOCKING;
  517. }
  518. static void unlock_free (struct unlock_instance *o)
  519. {
  520. NCDModuleInst_Backend_Dead(o->i);
  521. }
  522. static struct NCDModule modules[] = {
  523. {
  524. .type = "net.iptables.append",
  525. .func_new2 = append_iptables_func_new,
  526. .func_die = func_die,
  527. .alloc_size = sizeof(struct instance)
  528. }, {
  529. .type = "net.iptables.insert",
  530. .func_new2 = insert_iptables_func_new,
  531. .func_die = func_die,
  532. .alloc_size = sizeof(struct instance)
  533. }, {
  534. .type = "net.iptables.policy",
  535. .func_new2 = policy_iptables_func_new,
  536. .func_die = func_die,
  537. .alloc_size = sizeof(struct instance)
  538. }, {
  539. .type = "net.iptables.newchain",
  540. .func_new2 = newchain_iptables_func_new,
  541. .func_die = func_die,
  542. .alloc_size = sizeof(struct instance)
  543. }, {
  544. .type = "net.ebtables.append",
  545. .func_new2 = append_ebtables_func_new,
  546. .func_die = func_die,
  547. .alloc_size = sizeof(struct instance)
  548. }, {
  549. .type = "net.ebtables.insert",
  550. .func_new2 = insert_ebtables_func_new,
  551. .func_die = func_die,
  552. .alloc_size = sizeof(struct instance)
  553. }, {
  554. .type = "net.ebtables.policy",
  555. .func_new2 = policy_ebtables_func_new,
  556. .func_die = func_die,
  557. .alloc_size = sizeof(struct instance)
  558. }, {
  559. .type = "net.ebtables.newchain",
  560. .func_new2 = newchain_ebtables_func_new,
  561. .func_die = func_die,
  562. .alloc_size = sizeof(struct instance)
  563. }, {
  564. .type = "net.iptables.lock",
  565. .func_new2 = lock_func_new,
  566. .func_die = lock_func_die,
  567. .alloc_size = sizeof(struct lock_instance)
  568. }, {
  569. .type = "net.iptables.lock::unlock",
  570. .func_new2 = unlock_func_new,
  571. .func_die = unlock_func_die,
  572. .alloc_size = sizeof(struct unlock_instance)
  573. }, {
  574. .type = NULL
  575. }
  576. };
  577. const struct NCDModuleGroup ncdmodule_net_iptables = {
  578. .modules = modules,
  579. .func_globalinit = func_globalinit,
  580. .func_globalfree = func_globalfree
  581. };