You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

krnl_route.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. /* This file is part of Netsukuku
  2. * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
  3. *
  4. * This source code is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as published
  6. * by the Free Software Foundation; either version 2 of the License,
  7. * or (at your option) any later version.
  8. *
  9. * This source code is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. * Please refer to the GNU Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Public License along with
  15. * this source code; if not, write to:
  16. * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. *
  18. * -
  19. *
  20. * Various parts are ripped from iproute2/iproute.c
  21. * written by Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>.
  22. */
  23. #include "includes.h"
  24. #include "if.h"
  25. #include "libnetlink.h"
  26. #include "inet.h"
  27. #include "krnl_route.h"
  28. #include "libnetlink.h"
  29. #include "ll_map.h"
  30. #include "common.h"
  31. #ifdef LINUX_2_6_14
  32. #include <linux/ip_mp_alg.h>
  33. #define NTK_MULTIPATH_ALGO IP_MP_ALG_WRANDOM
  34. #endif
  35. static struct {
  36. int tb;
  37. int flushed;
  38. char *flushb;
  39. int flushp;
  40. int flushe;
  41. struct rtnl_handle *rth;
  42. int protocol, protocolmask;
  43. int scope, scopemask;
  44. int type, typemask;
  45. int tos, tosmask;
  46. int iif, iifmask;
  47. int oif, oifmask;
  48. int realm, realmmask;
  49. inet_prefix rprefsrc;
  50. inet_prefix rvia;
  51. inet_prefix rdst;
  52. inet_prefix mdst;
  53. inet_prefix rsrc;
  54. inet_prefix msrc;
  55. } filter;
  56. void
  57. route_reset_filter()
  58. {
  59. setzero(&filter, sizeof(filter));
  60. filter.mdst.bits = -1;
  61. filter.msrc.bits = -1;
  62. }
  63. int route_exec(int route_cmd, int route_type, int route_scope,
  64. unsigned flags, inet_prefix * src, inet_prefix * to,
  65. struct nexthop *nhops, char *dev, u_char table);
  66. int
  67. route_add(ROUTE_CMD_VARS)
  68. {
  69. return route_exec(RTM_NEWROUTE, type, scope, NLM_F_CREATE | NLM_F_EXCL,
  70. src, to, nhops, dev, table);
  71. }
  72. int
  73. route_del(ROUTE_CMD_VARS)
  74. {
  75. return route_exec(RTM_DELROUTE, type, scope, 0, src, to, nhops, dev,
  76. table);
  77. }
  78. /*If it doesn't exist, CREATE IT! de ih oh oh*/
  79. int
  80. route_replace(ROUTE_CMD_VARS)
  81. {
  82. return route_exec(RTM_NEWROUTE, type, scope,
  83. NLM_F_REPLACE | NLM_F_CREATE, src, to, nhops, dev,
  84. table);
  85. }
  86. int
  87. route_change(ROUTE_CMD_VARS)
  88. {
  89. return route_exec(RTM_NEWROUTE, type, scope, NLM_F_REPLACE, src, to,
  90. nhops, dev, table);
  91. }
  92. int
  93. route_append(ROUTE_CMD_VARS)
  94. {
  95. return route_exec(RTM_NEWROUTE, type, scope,
  96. NLM_F_CREATE | NLM_F_APPEND, src, to, nhops, dev,
  97. table);
  98. }
  99. int
  100. add_nexthops(struct nlmsghdr *n, struct rtmsg *r, struct nexthop *nhop)
  101. {
  102. char buf[1024];
  103. struct rtattr *rta = (void *) buf;
  104. struct rtnexthop *rtnh;
  105. int i = 0, idx;
  106. rta->rta_type = RTA_MULTIPATH;
  107. rta->rta_len = RTA_LENGTH(0);
  108. rtnh = RTA_DATA(rta);
  109. if (!nhop[i + 1].dev) {
  110. /* Just one gateway */
  111. r->rtm_family = nhop[i].gw.family;
  112. addattr_l(n, sizeof(struct rt_request), RTA_GATEWAY,
  113. &nhop[i].gw.data, nhop[i].gw.len);
  114. if (nhop[0].dev) {
  115. if ((idx = ll_name_to_index(nhop[0].dev)) == 0) {
  116. error(ERROR_MSG "Device \"%s\" doesn't really exist\n",
  117. ERROR_POS, nhop[0].dev);
  118. return -1;
  119. }
  120. addattr32(n, sizeof(struct rt_request), RTA_OIF, idx);
  121. }
  122. return 0;
  123. }
  124. #if 0
  125. /* We have more than one nexthop, equalize them */
  126. req.rt.rtm_flags |= RTM_F_EQUALIZE;
  127. #endif
  128. while (nhop[i].dev != 0) {
  129. setzero(rtnh, sizeof(*rtnh));
  130. rtnh->rtnh_len = sizeof(*rtnh);
  131. rta->rta_len += rtnh->rtnh_len;
  132. if (nhop[i].gw.len) {
  133. if (nhop[i].gw.family == AF_INET)
  134. rta_addattr32(rta, 4096, RTA_GATEWAY, nhop[i].gw.data[0]);
  135. else if (nhop[i].gw.family == AF_INET6)
  136. rta_addattr_l(rta, 4096, RTA_GATEWAY, nhop[i].gw.data,
  137. nhop[i].gw.len);
  138. rtnh->rtnh_len += sizeof(struct rtattr) + nhop[i].gw.len;
  139. }
  140. if (nhop[i].dev)
  141. if ((rtnh->rtnh_ifindex = ll_name_to_index(nhop[i].dev)) == 0)
  142. fatal("%s:%d, Cannot find device \"%s\"\n", ERROR_POS,
  143. nhop[i].dev);
  144. if (nhop[i].hops == 0) {
  145. debug(DBG_NORMAL, "hops=%d is invalid. Using hops=255\n",
  146. nhop[i].hops);
  147. rtnh->rtnh_hops = 255;
  148. } else
  149. rtnh->rtnh_hops = nhop[i].hops - 1;
  150. rtnh = RTNH_NEXT(rtnh);
  151. i++;
  152. }
  153. if (rta->rta_len > RTA_LENGTH(0))
  154. addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
  155. return 0;
  156. }
  157. /*
  158. * route_exec: replaces, adds or deletes a route from the routing table.
  159. * `to' and nhops->gw must be addresses given in network order
  160. */
  161. int
  162. route_exec(int route_cmd, int route_type, int route_scope, unsigned flags,
  163. inet_prefix * src, inet_prefix * to, struct nexthop *nhops,
  164. char *dev, u_char table)
  165. {
  166. struct rt_request req;
  167. struct rtnl_handle rth;
  168. setzero(&req, sizeof(req));
  169. if (!table)
  170. table = RT_TABLE_MAIN;
  171. req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  172. req.nh.nlmsg_flags = NLM_F_REQUEST | flags;
  173. req.nh.nlmsg_type = route_cmd;
  174. req.rt.rtm_family = AF_UNSPEC;
  175. req.rt.rtm_table = table;
  176. req.rt.rtm_protocol = RTPROT_NETSUKUKU;
  177. req.rt.rtm_scope = RT_SCOPE_NOWHERE;
  178. req.rt.rtm_type = RTN_UNSPEC;
  179. /* kernel protocol layer */
  180. if (table == RT_TABLE_LOCAL)
  181. req.rt.rtm_protocol = RTPROT_KERNEL;
  182. if (route_cmd != RTM_DELROUTE) {
  183. req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
  184. req.rt.rtm_type = RTN_UNICAST;
  185. }
  186. if (route_type)
  187. req.rt.rtm_type = route_type;
  188. if (route_scope)
  189. req.rt.rtm_scope = route_scope;
  190. else if (req.rt.rtm_type == RTN_LOCAL)
  191. req.rt.rtm_scope = RT_SCOPE_HOST;
  192. if (rtnl_open(&rth, 0) < 0)
  193. return -1;
  194. if (dev || nhops)
  195. ll_init_map(&rth);
  196. #ifdef LINUX_2_6_14
  197. uint32_t mp_alg = NTK_MULTIPATH_ALGO;
  198. addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg));
  199. #endif
  200. if (dev) {
  201. int idx;
  202. if ((idx = ll_name_to_index(dev)) == 0) {
  203. error("%s:%d, Device \"%s\" doesn't really exist\n", ERROR_POS,
  204. dev);
  205. return -1;
  206. }
  207. addattr32(&req.nh, sizeof(req), RTA_OIF, idx);
  208. }
  209. if (to) {
  210. req.rt.rtm_family = to->family;
  211. req.rt.rtm_dst_len = to->bits;
  212. if (!to->data[0] && !to->data[1] && !to->data[2] && !to->data[3]) {
  213. /* Modify the default gw */
  214. if (route_cmd == RTM_DELROUTE)
  215. req.rt.rtm_protocol = 0;
  216. }
  217. if (to->len)
  218. addattr_l(&req.nh, sizeof(req), RTA_DST, &to->data, to->len);
  219. }
  220. if (src) {
  221. if (req.rt.rtm_family == AF_UNSPEC)
  222. req.rt.rtm_family = src->family;
  223. addattr_l(&req.nh, sizeof(req), RTA_PREFSRC, &src->data, src->len);
  224. }
  225. if (nhops)
  226. add_nexthops(&req.nh, &req.rt, nhops);
  227. if (req.rt.rtm_family == AF_UNSPEC)
  228. req.rt.rtm_family = AF_INET;
  229. /*Finaly stage: <<Hey krnl, r u there?>> */
  230. if (rtnl_talk(&rth, &req.nh, 0, 0, NULL, NULL, NULL) < 0)
  231. return -1;
  232. rtnl_close(&rth);
  233. return 0;
  234. }
  235. /*
  236. * route_get_gw: if the route stored in `who' and `n' is matched by the
  237. * `filter', it stores the gateway address of that route in `arg', which
  238. * is a pointer to an inet_prefix struct. The address is stored in host order.
  239. * The dev name of the route is appended at `arg'+sizeof(inet_prefix).
  240. * Only the non-deleted routes are considered.
  241. */
  242. int
  243. route_get_gw(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
  244. {
  245. struct rtmsg *r = NLMSG_DATA(n);
  246. int len = n->nlmsg_len;
  247. struct rtattr *tb[RTA_MAX + 1];
  248. inet_prefix dst;
  249. inet_prefix via;
  250. int host_len = -1;
  251. if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE)
  252. return 0;
  253. if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
  254. return 0;
  255. len -= NLMSG_LENGTH(sizeof(*r));
  256. if (len < 0)
  257. return -1;
  258. if (r->rtm_family == AF_INET6)
  259. host_len = 128;
  260. else if (r->rtm_family == AF_INET)
  261. host_len = 32;
  262. else if (r->rtm_family == AF_DECnet)
  263. host_len = 16;
  264. else if (r->rtm_family == AF_IPX)
  265. host_len = 80;
  266. if (r->rtm_family == AF_INET6) {
  267. if (filter.tb) {
  268. if (filter.tb < 0) {
  269. if (!(r->rtm_flags & RTM_F_CLONED))
  270. return 0;
  271. } else {
  272. if (r->rtm_flags & RTM_F_CLONED)
  273. return 0;
  274. if (filter.tb == RT_TABLE_LOCAL) {
  275. if (r->rtm_type != RTN_LOCAL)
  276. return 0;
  277. } else if (filter.tb == RT_TABLE_MAIN) {
  278. if (r->rtm_type == RTN_LOCAL)
  279. return 0;
  280. } else {
  281. return 0;
  282. }
  283. }
  284. }
  285. } else {
  286. if (filter.tb > 0 && filter.tb != r->rtm_table)
  287. return 0;
  288. }
  289. if ((filter.protocol ^ r->rtm_protocol) & filter.protocolmask)
  290. return 0;
  291. if ((filter.scope ^ r->rtm_scope) & filter.scopemask)
  292. return 0;
  293. if ((filter.type ^ r->rtm_type) & filter.typemask)
  294. return 0;
  295. if ((filter.tos ^ r->rtm_tos) & filter.tosmask)
  296. return 0;
  297. if (filter.rdst.family &&
  298. (r->rtm_family != filter.rdst.family
  299. || filter.rdst.bits > r->rtm_dst_len))
  300. return 0;
  301. if (filter.mdst.family &&
  302. (r->rtm_family != filter.mdst.family ||
  303. (filter.mdst.bits < r->rtm_dst_len)))
  304. return 0;
  305. if (filter.rsrc.family &&
  306. (r->rtm_family != filter.rsrc.family
  307. || filter.rsrc.bits > r->rtm_src_len))
  308. return 0;
  309. if (filter.msrc.family &&
  310. (r->rtm_family != filter.msrc.family ||
  311. (filter.msrc.bits < r->rtm_src_len)))
  312. return 0;
  313. if (filter.rvia.family && r->rtm_family != filter.rvia.family)
  314. return 0;
  315. if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
  316. return 0;
  317. parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
  318. setzero(&dst, sizeof(dst));
  319. dst.family = r->rtm_family;
  320. if (tb[RTA_DST]) {
  321. memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len + 7) / 8);
  322. }
  323. if (filter.rdst.family
  324. && inet_addr_match(&dst, &filter.rdst, filter.rdst.bits))
  325. return 0;
  326. if (filter.mdst.family &&
  327. inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
  328. return 0;
  329. if (n->nlmsg_type == RTM_DELROUTE)
  330. return 0;
  331. /*
  332. * ... and finally if all the tests passed, copy the gateway address
  333. */
  334. if (tb[RTA_GATEWAY]) {
  335. memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len / 8);
  336. via.family = r->rtm_family;
  337. inet_setip(arg, (u_int *) & via.data, via.family);
  338. } else if (tb[RTA_MULTIPATH]) {
  339. struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
  340. len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
  341. for (;;) {
  342. if (len < sizeof(*nh))
  343. break;
  344. if (nh->rtnh_len > len)
  345. break;
  346. if (r->rtm_flags & RTM_F_CLONED
  347. && r->rtm_type == RTN_MULTICAST)
  348. goto skip_nexthop;
  349. if (nh->rtnh_len > sizeof(*nh)) {
  350. parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
  351. nh->rtnh_len - sizeof(*nh));
  352. if (tb[RTA_GATEWAY]) {
  353. memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]),
  354. host_len / 8);
  355. via.family = r->rtm_family;
  356. inet_setip(arg, (u_int *) & via.data, via.family);
  357. /* Copy the interface name */
  358. strncpy((char *) arg + sizeof(inet_prefix),
  359. ll_index_to_name(nh->rtnh_ifindex), IFNAMSIZ);
  360. break;
  361. }
  362. }
  363. skip_nexthop:
  364. len -= NLMSG_ALIGN(nh->rtnh_len);
  365. nh = RTNH_NEXT(nh);
  366. }
  367. }
  368. /* Copy the interface name */
  369. if (tb[RTA_OIF] && filter.oifmask != -1)
  370. strncpy((char *) arg + sizeof(inet_prefix),
  371. ll_index_to_name(*(int *) RTA_DATA(tb[RTA_OIF])),
  372. IFNAMSIZ);
  373. return 0;
  374. }
  375. /*
  376. * route_get_exact_prefix: it dumps the routing table and search for a route
  377. * which has the prefix equal to `prefix', if it is found its destination
  378. * address is stored in `dst' and its interface name in `dev_name' (which must
  379. * be IFNAMSIZ big).
  380. */
  381. int
  382. route_get_exact_prefix_dst(inet_prefix prefix, inet_prefix * dst,
  383. char *dev_name)
  384. {
  385. int do_ipv6 = AF_UNSPEC;
  386. struct rtnl_handle rth;
  387. char dst_data[sizeof(inet_prefix) + IFNAMSIZ];
  388. route_reset_filter();
  389. filter.tb = RT_TABLE_MAIN;
  390. filter.mdst = prefix;
  391. filter.rdst = filter.mdst;
  392. if (do_ipv6 == AF_UNSPEC && filter.tb)
  393. do_ipv6 = AF_INET;
  394. if (rtnl_open(&rth, 0) < 0)
  395. return -1;
  396. ll_init_map(&rth);
  397. if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
  398. error(ERROR_MSG "Cannot send dump request" ERROR_POS);
  399. return -1;
  400. }
  401. setzero(dst_data, sizeof(dst_data));
  402. if (rtnl_dump_filter(&rth, route_get_gw, dst_data, NULL, NULL) < 0) {
  403. debug(DBG_NORMAL, ERROR_MSG "Dump terminated" ERROR_POS);
  404. return -1;
  405. }
  406. inet_copy(dst, (inet_prefix *) dst_data);
  407. memcpy(dev_name, dst_data + sizeof(inet_prefix), IFNAMSIZ);
  408. rtnl_close(&rth);
  409. return 0;
  410. }
  411. int
  412. route_flush_cache(int family)
  413. {
  414. int len, err;
  415. int flush_fd;
  416. char ROUTE_FLUSH_SYSCTL[] = "/proc/sys/net/ipvX/route/flush";
  417. char *buf = "-1";
  418. len = strlen(buf);
  419. if (family == AF_INET)
  420. ROUTE_FLUSH_SYSCTL[17] = '4';
  421. else if (family == AF_INET6)
  422. ROUTE_FLUSH_SYSCTL[17] = '6';
  423. else
  424. return -1;
  425. flush_fd = open(ROUTE_FLUSH_SYSCTL, O_WRONLY);
  426. if (flush_fd < 0) {
  427. debug(DBG_NORMAL, "Cannot open \"%s\"\n", ROUTE_FLUSH_SYSCTL);
  428. return -1;
  429. }
  430. if ((err = write(flush_fd, (void *) buf, len)) == 0) {
  431. debug(DBG_NORMAL, "Warning: Route Cache not flushed\n");
  432. return -1;
  433. } else if (err == -1) {
  434. debug(DBG_NORMAL, "Cannot flush routing cache: %s\n",
  435. strerror(errno));
  436. return -1;
  437. }
  438. close(flush_fd);
  439. return 0;
  440. }
  441. int
  442. route_ip_forward(int family, int enable)
  443. {
  444. int len, err;
  445. int flush_fd;
  446. char *ROUTE_FORWARD_SYSCTL = "/proc/sys/net/ipv4/ip_forward";
  447. char *ROUTE_FORWARD_SYSCTL_6 =
  448. "/proc/sys/net/ipv6/conf/all/forwarding";
  449. char *sysctl_path, buf[2];
  450. buf[0] = '1';
  451. buf[1] = 0;
  452. len = strlen(buf);
  453. if (family == AF_INET)
  454. sysctl_path = ROUTE_FORWARD_SYSCTL;
  455. else if (family == AF_INET6)
  456. sysctl_path = ROUTE_FORWARD_SYSCTL_6;
  457. else
  458. return -1;
  459. if (!enable)
  460. buf[0] = '0';
  461. flush_fd = open(sysctl_path, O_WRONLY);
  462. if (flush_fd < 0) {
  463. debug(DBG_NORMAL, "Cannot open \"%s\"\n", sysctl_path);
  464. return -1;
  465. }
  466. if ((err = write(flush_fd, (void *) buf, len)) == 0) {
  467. debug(DBG_NORMAL, "Warning: ip_forward setting changed\n");
  468. return -1;
  469. } else if (err == -1) {
  470. debug(DBG_NORMAL, "Cannot change the ip_forward setting: %s\n",
  471. strerror(errno));
  472. return -1;
  473. }
  474. close(flush_fd);
  475. return 0;
  476. }
  477. /*
  478. * route_rp_filter
  479. *
  480. * Modifies the /proc/sys/net/ipv4/conf/INTERFACE/rp_filter config file.
  481. */
  482. int
  483. route_rp_filter(int family, char *dev, int enable)
  484. {
  485. int len, err, ret = 0;
  486. int flush_fd;
  487. /* The path is /proc/sys/net/ipv4/conf/INTERFACE/rp_filter */
  488. const char *RP_FILTER_SYSCTL_1 = "/proc/sys/net/ipv4/conf/";
  489. const char *RP_FILTER_SYSCTL_1_IPV6 = "/proc/sys/net/ipv6/conf/";
  490. const char *RP_FILTER_SYSCTL_2 = "/rp_filter";
  491. char *final_path = 0, buf[2];
  492. buf[0] = '1';
  493. buf[1] = 0;
  494. #define RP_FILTER_PATH_SZ (strlen(RP_FILTER_SYSCTL_1)+ \
  495. strlen(RP_FILTER_SYSCTL_2)+IF_NAMESIZE+1)
  496. final_path = xzalloc(RP_FILTER_PATH_SZ);
  497. len = strlen(buf);
  498. if (family == AF_INET) {
  499. strcpy(final_path, RP_FILTER_SYSCTL_1);
  500. } else if (family == AF_INET6) {
  501. strcpy(final_path, RP_FILTER_SYSCTL_1_IPV6);
  502. } else
  503. ERROR_FINISH(ret, -1, finish);
  504. strcat(final_path, dev);
  505. strcat(final_path, RP_FILTER_SYSCTL_2);
  506. if (!enable)
  507. buf[0] = '0';
  508. flush_fd = open(final_path, O_WRONLY);
  509. if (flush_fd < 0) {
  510. debug(DBG_NORMAL, "Cannot open \"%s\"\n", final_path);
  511. ERROR_FINISH(ret, -1, finish);
  512. }
  513. if ((err = write(flush_fd, (void *) buf, len)) == 0) {
  514. debug(DBG_NORMAL, "Warning: rp_filter setting changed\n");
  515. ERROR_FINISH(ret, -1, finish);
  516. } else if (err == -1) {
  517. debug(DBG_NORMAL, "Cannot change the rp_filter setting: %s\n",
  518. strerror(errno));
  519. ERROR_FINISH(ret, -1, finish);
  520. }
  521. close(flush_fd);
  522. finish:
  523. if (final_path)
  524. xfree(final_path);
  525. return ret;
  526. }
  527. /*
  528. * route_rp_filter_all_dev: do route_rp_filter() for all the interfaces
  529. * present in the `ifs' array.
  530. */
  531. int
  532. route_rp_filter_all_dev(int family, interface * ifs, int ifs_n, int enable)
  533. {
  534. int i, ret = 0;
  535. for (i = 0; i < ifs_n; i++)
  536. ret += route_rp_filter(family, ifs[i].dev_name, enable);
  537. return ret;
  538. }
  539. /*Life is strange*/