1/* $OpenBSD: util.c,v 1.1.1.1 2022/09/01 14:20:33 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 "snmpd.h" 33 34ssize_t 35sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to, 36 socklen_t tolen, struct sockaddr *from, socklen_t fromlen) 37{ 38 struct iovec iov; 39 struct msghdr msg; 40 struct cmsghdr *cmsg; 41 struct in6_pktinfo *pkt6; 42 struct sockaddr_in *in; 43 struct sockaddr_in6 *in6; 44 union { 45 struct cmsghdr hdr; 46 char inbuf[CMSG_SPACE(sizeof(struct in_addr))]; 47 char in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 48 } cmsgbuf; 49 50 bzero(&msg, sizeof(msg)); 51 bzero(&cmsgbuf, sizeof(cmsgbuf)); 52 53 iov.iov_base = buf; 54 iov.iov_len = len; 55 msg.msg_iov = &iov; 56 msg.msg_iovlen = 1; 57 msg.msg_name = to; 58 msg.msg_namelen = tolen; 59 msg.msg_control = &cmsgbuf; 60 msg.msg_controllen = sizeof(cmsgbuf); 61 62 cmsg = CMSG_FIRSTHDR(&msg); 63 switch (to->sa_family) { 64 case AF_INET: 65 msg.msg_controllen = sizeof(cmsgbuf.inbuf); 66 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 67 cmsg->cmsg_level = IPPROTO_IP; 68 cmsg->cmsg_type = IP_SENDSRCADDR; 69 in = (struct sockaddr_in *)from; 70 memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr)); 71 break; 72 case AF_INET6: 73 msg.msg_controllen = sizeof(cmsgbuf.in6buf); 74 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 75 cmsg->cmsg_level = IPPROTO_IPV6; 76 cmsg->cmsg_type = IPV6_PKTINFO; 77 in6 = (struct sockaddr_in6 *)from; 78 pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 79 pkt6->ipi6_addr = in6->sin6_addr; 80 break; 81 } 82 83 return sendmsg(s, &msg, flags); 84} 85 86ssize_t 87recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, 88 socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen) 89{ 90 struct iovec iov; 91 struct msghdr msg; 92 struct cmsghdr *cmsg; 93 struct in6_pktinfo *pkt6; 94 struct sockaddr_in *in; 95 struct sockaddr_in6 *in6; 96 ssize_t ret; 97 union { 98 struct cmsghdr hdr; 99 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; 100 } cmsgbuf; 101 102 bzero(&msg, sizeof(msg)); 103 bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); 104 105 iov.iov_base = buf; 106 iov.iov_len = len; 107 msg.msg_iov = &iov; 108 msg.msg_iovlen = 1; 109 msg.msg_name = from; 110 msg.msg_namelen = *fromlen; 111 msg.msg_control = &cmsgbuf.buf; 112 msg.msg_controllen = sizeof(cmsgbuf.buf); 113 114 if ((ret = recvmsg(s, &msg, flags)) == -1) 115 return (-1); 116 117 *fromlen = from->sa_len; 118 *tolen = 0; 119 120 if (getsockname(s, to, tolen) != 0) 121 *tolen = 0; 122 123 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 124 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 125 switch (from->sa_family) { 126 case AF_INET: 127 if (cmsg->cmsg_level == IPPROTO_IP && 128 cmsg->cmsg_type == IP_RECVDSTADDR) { 129 in = (struct sockaddr_in *)to; 130 in->sin_family = AF_INET; 131 in->sin_len = *tolen = sizeof(*in); 132 memcpy(&in->sin_addr, CMSG_DATA(cmsg), 133 sizeof(struct in_addr)); 134 } 135 break; 136 case AF_INET6: 137 if (cmsg->cmsg_level == IPPROTO_IPV6 && 138 cmsg->cmsg_type == IPV6_PKTINFO) { 139 in6 = (struct sockaddr_in6 *)to; 140 in6->sin6_family = AF_INET6; 141 in6->sin6_len = *tolen = sizeof(*in6); 142 pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 143 memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, 144 sizeof(struct in6_addr)); 145 if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) 146 in6->sin6_scope_id = 147 pkt6->ipi6_ifindex; 148 } 149 break; 150 } 151 } 152 153 return (ret); 154} 155 156const char * 157log_in6addr(const struct in6_addr *addr) 158{ 159 static char buf[NI_MAXHOST]; 160 struct sockaddr_in6 sa_in6; 161 u_int16_t tmp16; 162 163 bzero(&sa_in6, sizeof(sa_in6)); 164 sa_in6.sin6_len = sizeof(sa_in6); 165 sa_in6.sin6_family = AF_INET6; 166 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 167 168 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 169 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 170 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 171 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 172 sa_in6.sin6_scope_id = ntohs(tmp16); 173 sa_in6.sin6_addr.s6_addr[2] = 0; 174 sa_in6.sin6_addr.s6_addr[3] = 0; 175 } 176 177 return (print_host((struct sockaddr_storage *)&sa_in6, buf, 178 NI_MAXHOST)); 179} 180 181const char * 182print_host(struct sockaddr_storage *ss, char *buf, size_t len) 183{ 184 if (getnameinfo((struct sockaddr *)ss, ss->ss_len, 185 buf, len, NULL, 0, NI_NUMERICHOST) != 0) { 186 buf[0] = '\0'; 187 return (NULL); 188 } 189 return (buf); 190} 191 192char * 193tohexstr(uint8_t *bstr, int len) 194{ 195#define MAXHEXSTRLEN 256 196 static char hstr[2 * MAXHEXSTRLEN + 1]; 197 static const char hex[] = "0123456789abcdef"; 198 int i; 199 200 if (len > MAXHEXSTRLEN) 201 len = MAXHEXSTRLEN; /* truncate */ 202 for (i = 0; i < len; i++) { 203 hstr[i + i] = hex[bstr[i] >> 4]; 204 hstr[i + i + 1] = hex[bstr[i] & 0x0f]; 205 } 206 hstr[i + i] = '\0'; 207 return hstr; 208} 209 210uint8_t * 211fromhexstr(uint8_t *bstr, const char *hstr, size_t len) 212{ 213 size_t i; 214 char hex[3]; 215 216 if (len % 2 != 0) 217 return NULL; 218 219 hex[2] = '\0'; 220 for (i = 0; i < len; i += 2) { 221 if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1])) 222 return NULL; 223 hex[0] = hstr[i]; 224 hex[1] = hstr[i + 1]; 225 bstr[i / 2] = strtol(hex, NULL, 16); 226 } 227 228 return bstr; 229} 230