/contrib/bsnmp/snmpd/trans_udp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 319 lines · 217 code · 39 blank · 63 comment · 46 complexity · a6aa8fc3b6ec1daece69b46271d6e6bf MD5 · raw file

  1. /*
  2. * Copyright (c) 2003
  3. * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4. * All rights reserved.
  5. *
  6. * Author: Harti Brandt <harti@freebsd.org>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $
  30. *
  31. * UDP transport
  32. */
  33. #include <sys/types.h>
  34. #include <sys/queue.h>
  35. #include <stdlib.h>
  36. #include <syslog.h>
  37. #include <string.h>
  38. #include <errno.h>
  39. #include <unistd.h>
  40. #include <netinet/in.h>
  41. #include <arpa/inet.h>
  42. #include "snmpmod.h"
  43. #include "snmpd.h"
  44. #include "trans_udp.h"
  45. #include "tree.h"
  46. #include "oid.h"
  47. static int udp_start(void);
  48. static int udp_stop(int);
  49. static void udp_close_port(struct tport *);
  50. static int udp_init_port(struct tport *);
  51. static ssize_t udp_send(struct tport *, const u_char *, size_t,
  52. const struct sockaddr *, size_t);
  53. /* exported */
  54. const struct transport_def udp_trans = {
  55. "udp",
  56. OIDX_begemotSnmpdTransUdp,
  57. udp_start,
  58. udp_stop,
  59. udp_close_port,
  60. udp_init_port,
  61. udp_send
  62. };
  63. static struct transport *my_trans;
  64. static int
  65. udp_start(void)
  66. {
  67. return (trans_register(&udp_trans, &my_trans));
  68. }
  69. static int
  70. udp_stop(int force __unused)
  71. {
  72. if (my_trans != NULL)
  73. if (trans_unregister(my_trans) != 0)
  74. return (SNMP_ERR_GENERR);
  75. return (SNMP_ERR_NOERROR);
  76. }
  77. /*
  78. * A UDP port is ready
  79. */
  80. static void
  81. udp_input(int fd __unused, void *udata)
  82. {
  83. struct udp_port *p = udata;
  84. p->input.peerlen = sizeof(p->ret);
  85. snmpd_input(&p->input, &p->tport);
  86. }
  87. /*
  88. * Create a UDP socket and bind it to the given port
  89. */
  90. static int
  91. udp_init_port(struct tport *tp)
  92. {
  93. struct udp_port *p = (struct udp_port *)tp;
  94. struct sockaddr_in addr;
  95. u_int32_t ip;
  96. const int on = 1;
  97. if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
  98. syslog(LOG_ERR, "creating UDP socket: %m");
  99. return (SNMP_ERR_RES_UNAVAIL);
  100. }
  101. ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) |
  102. p->addr[3];
  103. memset(&addr, 0, sizeof(addr));
  104. addr.sin_addr.s_addr = htonl(ip);
  105. addr.sin_port = htons(p->port);
  106. addr.sin_family = AF_INET;
  107. addr.sin_len = sizeof(addr);
  108. if (addr.sin_addr.s_addr == INADDR_ANY &&
  109. setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on,
  110. sizeof(on)) == -1) {
  111. syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
  112. close(p->input.fd);
  113. p->input.fd = -1;
  114. return (SNMP_ERR_GENERR);
  115. }
  116. if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) {
  117. if (errno == EADDRNOTAVAIL) {
  118. close(p->input.fd);
  119. p->input.fd = -1;
  120. return (SNMP_ERR_INCONS_NAME);
  121. }
  122. syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr),
  123. p->port);
  124. close(p->input.fd);
  125. p->input.fd = -1;
  126. return (SNMP_ERR_GENERR);
  127. }
  128. if ((p->input.id = fd_select(p->input.fd, udp_input,
  129. p, NULL)) == NULL) {
  130. close(p->input.fd);
  131. p->input.fd = -1;
  132. return (SNMP_ERR_GENERR);
  133. }
  134. return (SNMP_ERR_NOERROR);
  135. }
  136. /*
  137. * Create a new SNMP Port object and start it, if we are not
  138. * in initialization mode. The arguments are in host byte order.
  139. */
  140. static int
  141. udp_open_port(u_int8_t *addr, u_int32_t udp_port, struct udp_port **pp)
  142. {
  143. struct udp_port *port;
  144. int err;
  145. if (udp_port > 0xffff)
  146. return (SNMP_ERR_NO_CREATION);
  147. if ((port = malloc(sizeof(*port))) == NULL)
  148. return (SNMP_ERR_GENERR);
  149. memset(port, 0, sizeof(*port));
  150. /* initialize common part */
  151. port->tport.index.len = 5;
  152. port->tport.index.subs[0] = addr[0];
  153. port->tport.index.subs[1] = addr[1];
  154. port->tport.index.subs[2] = addr[2];
  155. port->tport.index.subs[3] = addr[3];
  156. port->tport.index.subs[4] = udp_port;
  157. port->addr[0] = addr[0];
  158. port->addr[1] = addr[1];
  159. port->addr[2] = addr[2];
  160. port->addr[3] = addr[3];
  161. port->port = udp_port;
  162. port->input.fd = -1;
  163. port->input.id = NULL;
  164. port->input.stream = 0;
  165. port->input.cred = 0;
  166. port->input.peer = (struct sockaddr *)&port->ret;
  167. port->input.peerlen = sizeof(port->ret);
  168. trans_insert_port(my_trans, &port->tport);
  169. if (community != COMM_INITIALIZE &&
  170. (err = udp_init_port(&port->tport)) != SNMP_ERR_NOERROR) {
  171. udp_close_port(&port->tport);
  172. return (err);
  173. }
  174. *pp = port;
  175. return (SNMP_ERR_NOERROR);
  176. }
  177. /*
  178. * Close an SNMP port
  179. */
  180. static void
  181. udp_close_port(struct tport *tp)
  182. {
  183. struct udp_port *port = (struct udp_port *)tp;
  184. snmpd_input_close(&port->input);
  185. trans_remove_port(tp);
  186. free(port);
  187. }
  188. /*
  189. * Send something
  190. */
  191. static ssize_t
  192. udp_send(struct tport *tp, const u_char *buf, size_t len,
  193. const struct sockaddr *addr, size_t addrlen)
  194. {
  195. struct udp_port *p = (struct udp_port *)tp;
  196. return (sendto(p->input.fd, buf, len, 0, addr, addrlen));
  197. }
  198. /*
  199. * Port table
  200. */
  201. int
  202. op_snmp_port(struct snmp_context *ctx, struct snmp_value *value,
  203. u_int sub, u_int iidx, enum snmp_op op)
  204. {
  205. asn_subid_t which = value->var.subs[sub-1];
  206. struct udp_port *p;
  207. u_int8_t addr[4];
  208. u_int32_t port;
  209. switch (op) {
  210. case SNMP_OP_GETNEXT:
  211. if ((p = (struct udp_port *)trans_next_port(my_trans,
  212. &value->var, sub)) == NULL)
  213. return (SNMP_ERR_NOSUCHNAME);
  214. index_append(&value->var, sub, &p->tport.index);
  215. break;
  216. case SNMP_OP_GET:
  217. if ((p = (struct udp_port *)trans_find_port(my_trans,
  218. &value->var, sub)) == NULL)
  219. return (SNMP_ERR_NOSUCHNAME);
  220. break;
  221. case SNMP_OP_SET:
  222. p = (struct udp_port *)trans_find_port(my_trans,
  223. &value->var, sub);
  224. ctx->scratch->int1 = (p != NULL);
  225. if (which != LEAF_begemotSnmpdPortStatus)
  226. abort();
  227. if (!TRUTH_OK(value->v.integer))
  228. return (SNMP_ERR_WRONG_VALUE);
  229. ctx->scratch->int2 = TRUTH_GET(value->v.integer);
  230. if (ctx->scratch->int2) {
  231. /* open an SNMP port */
  232. if (p != NULL)
  233. /* already open - do nothing */
  234. return (SNMP_ERR_NOERROR);
  235. if (index_decode(&value->var, sub, iidx, addr, &port))
  236. return (SNMP_ERR_NO_CREATION);
  237. return (udp_open_port(addr, port, &p));
  238. } else {
  239. /* close SNMP port - do in commit */
  240. }
  241. return (SNMP_ERR_NOERROR);
  242. case SNMP_OP_ROLLBACK:
  243. p = (struct udp_port *)trans_find_port(my_trans,
  244. &value->var, sub);
  245. if (ctx->scratch->int1 == 0) {
  246. /* did not exist */
  247. if (ctx->scratch->int2 == 1) {
  248. /* created */
  249. if (p != NULL)
  250. udp_close_port(&p->tport);
  251. }
  252. }
  253. return (SNMP_ERR_NOERROR);
  254. case SNMP_OP_COMMIT:
  255. p = (struct udp_port *)trans_find_port(my_trans,
  256. &value->var, sub);
  257. if (ctx->scratch->int1 == 1) {
  258. /* did exist */
  259. if (ctx->scratch->int2 == 0) {
  260. /* delete */
  261. if (p != NULL)
  262. udp_close_port(&p->tport);
  263. }
  264. }
  265. return (SNMP_ERR_NOERROR);
  266. default:
  267. abort();
  268. }
  269. /*
  270. * Come here to fetch the value
  271. */
  272. switch (which) {
  273. case LEAF_begemotSnmpdPortStatus:
  274. value->v.integer = 1;
  275. break;
  276. default:
  277. abort();
  278. }
  279. return (SNMP_ERR_NOERROR);
  280. }