inz

snmpcproxy.c (raw)

  1. /*
  2.  * Copyright (c) 2015 Santtu Lakkala
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20.  * DEALINGS IN THE SOFTWARE.
  21.  */
  22. #include <netinet/in.h>
  23. #include <sys/select.h>
  24. #include <arpa/inet.h>
  25. #include <stdlib.h>
  26. #include <signal.h>
  27. #include <unistd.h>
  28. #include <string.h>
  29. #include <poll.h>
  30.  
  31. #include <stdio.h>
  32.  
  33. #define MAX_AGENTS 64
  34.  
  35. struct agent {
  36. const char *community;
  37. size_t c_len;
  38. struct sockaddr_in agent;
  39. struct sockaddr_in client;
  40. };
  41.  
  42. int strmatchn(const char *a, size_t a_len, const char *b, size_t b_len)
  43. {
  44. return a_len == b_len && !strncmp(a, b, a_len);
  45. }
  46.  
  47. size_t find_agent(struct agent *agents, size_t n_agents, const char *community, size_t c_len)
  48. {
  49. size_t i;
  50.  
  51. for (i = 0; i < n_agents; i++) {
  52. if (strmatchn(agents[i].community, agents[i].c_len, community, c_len))
  53. break;
  54. }
  55. return i;
  56. }
  57.  
  58. int set_agent(struct agent *agents, size_t *n_agents, const char *details)
  59. {
  60. const char *colon = strchr(details, ':');
  61. size_t i;
  62. char buffer[256];
  63.  
  64. if (!colon)
  65. return 0;
  66. i = find_agent(agents, *n_agents, details, colon - details);
  67. if (i == *n_agents) {
  68. if (i == MAX_AGENTS)
  69. return 0;
  70. (*n_agents)++;
  71. agents[i].community = details;
  72. agents[i].c_len = colon - details;
  73. }
  74.  
  75. memset(&agents[i].client, 0, sizeof(agents[i].client));
  76. memset(&agents[i].agent, 0, sizeof(agents[i].agent));
  77.  
  78. details = colon + 1;
  79. colon = strchr(details, ':');
  80.  
  81. if (colon) {
  82. memcpy(buffer, details, colon - details);
  83. buffer[colon - details] = '\0';
  84.  
  85. inet_aton(buffer, &agents[i].agent.sin_addr);
  86. agents[i].agent.sin_port = htons(atoi(colon + 1));
  87. } else {
  88. inet_aton(details, &agents[i].agent.sin_addr);
  89. agents[i].agent.sin_port = htons(161);
  90. }
  91.  
  92. return 1;
  93.  
  94. }
  95.  
  96. int running = 1;
  97.  
  98. void sighand(int signo)
  99. {
  100. (void)signo;
  101. running = 0;
  102. }
  103.  
  104. int main(int argc, char **argv)
  105. {
  106. struct agent agents[MAX_AGENTS];
  107. size_t n_agents;
  108. char buffer[8192];
  109. struct sockaddr_in serv = { 0 };
  110. struct pollfd pfds[MAX_AGENTS + 1];
  111.  
  112. int i;
  113.  
  114. serv.sin_family = AF_INET;
  115. serv.sin_addr.s_addr = htonl(INADDR_ANY);
  116. serv.sin_port = htons(161);
  117.  
  118. signal(SIGINT, sighand);
  119.  
  120. for (i = 1; i < argc; i++) {
  121. if (*argv[i] == '-') {
  122. const char *o = &argv[i][1];
  123. while (*o) {
  124. if (i + 1 >= argc)
  125. return 1;
  126.  
  127. switch (*o++) {
  128. case 'l':
  129. if (!inet_aton(argv[++i], &serv.sin_addr))
  130. return 1;
  131. break;
  132. case 'p':
  133. serv.sin_port = htons(atoi(argv[++i]));
  134. break;
  135. case 'a':
  136. set_agent(agents, &n_agents, argv[++i]);
  137. break;
  138. default:
  139. return 1;
  140. break;
  141. }
  142. }
  143. } else {
  144. return 1;
  145. }
  146. }
  147.  
  148. if ((pfds[0].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  149. perror("Failed to create socket for listening: ");
  150. return 1;
  151. }
  152. pfds[0].events = POLLIN;
  153.  
  154. for (i = 0; i < n_agents; i++) {
  155. if ((pfds[i + 1].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  156. perror("Failed to create socket for listening: ");
  157. return 1;
  158. }
  159. pfds[i + 1].events = POLLIN;
  160. }
  161.  
  162. if (bind(pfds[0].fd, (const struct sockaddr *)&serv, sizeof(serv)) < 0) {
  163. perror("Failed to bind: ");
  164. return 1;
  165. }
  166.  
  167. while (running) {
  168. int n;
  169.  
  170. n = poll(pfds, n_agents + 1, -1);
  171.  
  172. if (pfds[0].revents & POLLIN) {
  173. struct sockaddr_in c;
  174. socklen_t len = sizeof(c);
  175. ssize_t r = recvfrom(pfds[0].fd, buffer, sizeof(buffer), 0,
  176. (struct sockaddr *)&c, &len);
  177. if (r == 0)
  178. break;
  179. if (r > 6) {
  180. int len = (unsigned char)buffer[6];
  181. if (r > 6 + len) {
  182. i = find_agent(agents, n_agents, buffer + 7, len);
  183.  
  184. if (i < n_agents) {
  185. memcpy(&agents[i].client, &c, len);
  186. sendto(pfds[i + 1].fd, buffer, r, 0,
  187. (const struct sockaddr *)&agents[i].agent, sizeof(struct sockaddr_in));
  188. }
  189. }
  190. printf("%.*s\n", len, buffer + 7);
  191. }
  192. n--;
  193. }
  194.  
  195. for (i = 0; n && i < n_agents; i++) {
  196. if (pfds[i + 1].revents & POLLIN) {
  197. ssize_t r = recv(pfds[i + 1].fd, buffer, sizeof(buffer), 0);
  198. if (r == 0)
  199. break;
  200. if (r > 0)
  201. sendto(pfds[0].fd, buffer, r, 0, (const struct sockaddr *)&agents[i].client, sizeof(struct sockaddr_in));
  202. n--;
  203. }
  204. }
  205. }
  206.  
  207. return 0;
  208. }
  209.