ifmetric.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/socket.h>
  6. #include <linux/types.h>
  7. #include <linux/if.h>
  8. #include <stdlib.h>
  9. #include <assert.h>
  10. #include "nlrequest.h"
  11. #include "getifn.h"
  12. #define MAX_ROUTES 64
  13. struct nlmsghdr* routes[MAX_ROUTES];
  14. int n_routes = 0;
  15. int enumerate_callback(struct nlmsghdr *n, void *u) {
  16. struct rtmsg *r;
  17. struct rtattr *a = NULL;
  18. int l, *ifn = u;
  19. if (n->nlmsg_type != RTM_NEWROUTE) {
  20. fprintf(stderr, "NETLINK: Got response for wrong request.\n");
  21. return -1;
  22. }
  23. r = NLMSG_DATA(n);
  24. l = NLMSG_PAYLOAD(n, sizeof(struct rtmsg));
  25. a = RTM_RTA(r);
  26. if (r->rtm_table != RT_TABLE_MAIN)
  27. return 0;
  28. while(RTA_OK(a, l)) {
  29. switch(a->rta_type) {
  30. case RTA_OIF:
  31. if (RTA_PAYLOAD(a) != sizeof(int)) {
  32. fprintf(stderr, "NETLINK: Recieved corrupt RTA_OIF payload.\n");
  33. return -1;
  34. }
  35. if (*((int*) RTA_DATA(a)) == *ifn) {
  36. if (n_routes < MAX_ROUTES) {
  37. struct nlmsghdr* copy;
  38. if (!(copy = malloc(n->nlmsg_len))) {
  39. fprintf(stderr, "Could not allocate memory.\n");
  40. return -1;
  41. }
  42. memcpy(copy, n, n->nlmsg_len);
  43. routes[n_routes++] = copy;
  44. } else
  45. fprintf(stderr, "Found too many routes.\n");
  46. break;
  47. }
  48. }
  49. a = RTA_NEXT(a, l);
  50. }
  51. return 0;
  52. }
  53. int enumerate(int s, int ifn) {
  54. struct {
  55. struct nlmsghdr n;
  56. struct rtmsg r;
  57. char a[1024];
  58. } req;
  59. memset(&req, 0, sizeof(req));
  60. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  61. req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_MATCH;
  62. req.n.nlmsg_type = RTM_GETROUTE;
  63. req.r.rtm_family = AF_INET;
  64. req.r.rtm_table = RT_TABLE_MAIN;
  65. return netlink_request(s, (struct nlmsghdr*) &req, enumerate_callback, &ifn);
  66. }
  67. struct nlmsghdr* set_route_metric(struct nlmsghdr* n, int metric) {
  68. struct rtmsg *r;
  69. struct rtattr *a = NULL;
  70. int l, t;
  71. r = NLMSG_DATA(n);
  72. l = NLMSG_PAYLOAD(n, sizeof(struct rtmsg));
  73. a = RTM_RTA(r);
  74. while(RTA_OK(a, l)) {
  75. switch(a->rta_type) {
  76. case RTA_PRIORITY:
  77. if (RTA_PAYLOAD(a) != sizeof(int)) {
  78. fprintf(stderr, "NETLINK: Recieved corrupt RTA_PRIORITY payload.\n");
  79. return NULL;
  80. }
  81. *((int*) RTA_DATA(a)) = metric;
  82. return n;
  83. }
  84. a = RTA_NEXT(a, l);
  85. }
  86. if ((n = realloc(n, (t = n->nlmsg_len+1024))))
  87. addattr32(n, t, RTA_PRIORITY, metric);
  88. else
  89. fprintf(stderr, "realloc() failed.\n");
  90. return n;
  91. }
  92. int delete_route(int s, struct nlmsghdr* n) {
  93. assert(s >= 0 && n);
  94. n->nlmsg_type = RTM_DELROUTE;
  95. n->nlmsg_flags = NLM_F_REQUEST;
  96. return netlink_request(s, n, NULL, NULL);
  97. }
  98. int add_route(int s, struct nlmsghdr* n) {
  99. assert(s >= 0 && n);
  100. n->nlmsg_type = RTM_NEWROUTE;
  101. n->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
  102. return netlink_request(s, n, NULL, NULL);
  103. }
  104. int go(char *iface, int metric) {
  105. int r = -1, j;
  106. int s = -1, ifn;
  107. if ((s = netlink_open()) < 0)
  108. return -1;
  109. if ((ifn = getifn(s, iface)) < 0)
  110. goto finish;
  111. n_routes = 0;
  112. if (enumerate(s, ifn) < 0)
  113. goto finish;
  114. if (n_routes) {
  115. for (j = 0; j < n_routes; j++) {
  116. if (delete_route(s, routes[j]) >= 0)
  117. if ((routes[j] = set_route_metric(routes[j], metric)))
  118. add_route(s, routes[j]);
  119. free(routes[j]);
  120. }
  121. }
  122. r = 0;
  123. finish:
  124. if (s >= 0)
  125. close(s);
  126. return r;
  127. }
  128. int main(int argc, char *argv[]) {
  129. char *iface;
  130. int metric;
  131. if (argc <= 1 || (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))) {
  132. char *b;
  133. if ((b = strrchr(argv[0], '/')))
  134. b++;
  135. else
  136. b = argv[0];
  137. printf("Usage: %s <iface> [metric]\n"
  138. "\n"
  139. "%s is a tool for setting the metrics of all IPv4 routes\n"
  140. "attached to a given network interface at once.\n"
  141. "\n"
  142. " <iface> The interface\n"
  143. " <metric> The new metric (default: 0)\n", b, b);
  144. return 0;
  145. }
  146. iface = argv[1];
  147. metric = argc > 2 ? atoi(argv[2]) : 0;
  148. return go(iface, metric) < 0 ? 1 : 0;
  149. }