1 /* $OpenBSD: util.c,v 1.12 2021/08/09 18:14:53 martijn Exp $ */ 2 /* 3 * Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/queue.h> 20 #include <sys/socket.h> 21 22 #include <net/if.h> 23 24 #include <ber.h> 25 #include <ctype.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <netdb.h> 30 #include <event.h> 31 32 #include "snmp.h" 33 #include "snmpd.h" 34 35 ssize_t 36 sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to, 37 socklen_t tolen, struct sockaddr *from, socklen_t fromlen) 38 { 39 struct iovec iov; 40 struct msghdr msg; 41 struct cmsghdr *cmsg; 42 struct in6_pktinfo *pkt6; 43 struct sockaddr_in *in; 44 struct sockaddr_in6 *in6; 45 union { 46 struct cmsghdr hdr; 47 char inbuf[CMSG_SPACE(sizeof(struct in_addr))]; 48 char in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 49 } cmsgbuf; 50 51 bzero(&msg, sizeof(msg)); 52 bzero(&cmsgbuf, sizeof(cmsgbuf)); 53 54 iov.iov_base = buf; 55 iov.iov_len = len; 56 msg.msg_iov = &iov; 57 msg.msg_iovlen = 1; 58 msg.msg_name = to; 59 msg.msg_namelen = tolen; 60 msg.msg_control = &cmsgbuf; 61 msg.msg_controllen = sizeof(cmsgbuf); 62 63 cmsg = CMSG_FIRSTHDR(&msg); 64 switch (to->sa_family) { 65 case AF_INET: 66 msg.msg_controllen = sizeof(cmsgbuf.inbuf); 67 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 68 cmsg->cmsg_level = IPPROTO_IP; 69 cmsg->cmsg_type = IP_SENDSRCADDR; 70 in = (struct sockaddr_in *)from; 71 memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr)); 72 break; 73 case AF_INET6: 74 msg.msg_controllen = sizeof(cmsgbuf.in6buf); 75 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 76 cmsg->cmsg_level = IPPROTO_IPV6; 77 cmsg->cmsg_type = IPV6_PKTINFO; 78 in6 = (struct sockaddr_in6 *)from; 79 pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 80 pkt6->ipi6_addr = in6->sin6_addr; 81 break; 82 } 83 84 return sendmsg(s, &msg, flags); 85 } 86 87 ssize_t 88 recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, 89 socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen) 90 { 91 struct iovec iov; 92 struct msghdr msg; 93 struct cmsghdr *cmsg; 94 struct in6_pktinfo *pkt6; 95 struct sockaddr_in *in; 96 struct sockaddr_in6 *in6; 97 ssize_t ret; 98 union { 99 struct cmsghdr hdr; 100 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; 101 } cmsgbuf; 102 103 bzero(&msg, sizeof(msg)); 104 bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); 105 106 iov.iov_base = buf; 107 iov.iov_len = len; 108 msg.msg_iov = &iov; 109 msg.msg_iovlen = 1; 110 msg.msg_name = from; 111 msg.msg_namelen = *fromlen; 112 msg.msg_control = &cmsgbuf.buf; 113 msg.msg_controllen = sizeof(cmsgbuf.buf); 114 115 if ((ret = recvmsg(s, &msg, flags)) == -1) 116 return (-1); 117 118 *fromlen = from->sa_len; 119 *tolen = 0; 120 121 if (getsockname(s, to, tolen) != 0) 122 *tolen = 0; 123 124 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 125 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 126 switch (from->sa_family) { 127 case AF_INET: 128 if (cmsg->cmsg_level == IPPROTO_IP && 129 cmsg->cmsg_type == IP_RECVDSTADDR) { 130 in = (struct sockaddr_in *)to; 131 in->sin_family = AF_INET; 132 in->sin_len = *tolen = sizeof(*in); 133 memcpy(&in->sin_addr, CMSG_DATA(cmsg), 134 sizeof(struct in_addr)); 135 } 136 break; 137 case AF_INET6: 138 if (cmsg->cmsg_level == IPPROTO_IPV6 && 139 cmsg->cmsg_type == IPV6_PKTINFO) { 140 in6 = (struct sockaddr_in6 *)to; 141 in6->sin6_family = AF_INET6; 142 in6->sin6_len = *tolen = sizeof(*in6); 143 pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 144 memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, 145 sizeof(struct in6_addr)); 146 if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) 147 in6->sin6_scope_id = 148 pkt6->ipi6_ifindex; 149 } 150 break; 151 } 152 } 153 154 return (ret); 155 } 156 157 const char * 158 log_in6addr(const struct in6_addr *addr) 159 { 160 static char buf[NI_MAXHOST]; 161 struct sockaddr_in6 sa_in6; 162 u_int16_t tmp16; 163 164 bzero(&sa_in6, sizeof(sa_in6)); 165 sa_in6.sin6_len = sizeof(sa_in6); 166 sa_in6.sin6_family = AF_INET6; 167 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 168 169 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 170 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 171 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 172 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 173 sa_in6.sin6_scope_id = ntohs(tmp16); 174 sa_in6.sin6_addr.s6_addr[2] = 0; 175 sa_in6.sin6_addr.s6_addr[3] = 0; 176 } 177 178 return (print_host((struct sockaddr_storage *)&sa_in6, buf, 179 NI_MAXHOST)); 180 } 181 182 const char * 183 print_host(struct sockaddr_storage *ss, char *buf, size_t len) 184 { 185 if (getnameinfo((struct sockaddr *)ss, ss->ss_len, 186 buf, len, NULL, 0, NI_NUMERICHOST) != 0) { 187 buf[0] = '\0'; 188 return (NULL); 189 } 190 return (buf); 191 } 192 193 char * 194 tohexstr(uint8_t *bstr, int len) 195 { 196 #define MAXHEXSTRLEN 256 197 static char hstr[2 * MAXHEXSTRLEN + 1]; 198 static const char hex[] = "0123456789abcdef"; 199 int i; 200 201 if (len > MAXHEXSTRLEN) 202 len = MAXHEXSTRLEN; /* truncate */ 203 for (i = 0; i < len; i++) { 204 hstr[i + i] = hex[bstr[i] >> 4]; 205 hstr[i + i + 1] = hex[bstr[i] & 0x0f]; 206 } 207 hstr[i + i] = '\0'; 208 return hstr; 209 } 210 211 uint8_t * 212 fromhexstr(uint8_t *bstr, const char *hstr, size_t len) 213 { 214 size_t i; 215 char hex[3]; 216 217 if (len % 2 != 0) 218 return NULL; 219 220 hex[2] = '\0'; 221 for (i = 0; i < len; i += 2) { 222 if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1])) 223 return NULL; 224 hex[0] = hstr[i]; 225 hex[1] = hstr[i + 1]; 226 bstr[i / 2] = strtol(hex, NULL, 16); 227 } 228 229 return bstr; 230 } 231