1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/param.h> 31 #include <sys/time.h> 32 #include <sys/socket.h> 33 #include <sys/wait.h> 34 #include <sys/endian.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 #include <netdb.h> 38 #include <stdbool.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "ctld.hh" 44 #include "isns.hh" 45 46 isns_req::isns_req(uint16_t func, uint16_t flags, const char *descr) 47 : ir_descr(descr) 48 { 49 struct isns_hdr hdr; 50 51 be16enc(&hdr.ih_version, ISNS_VERSION); 52 be16enc(&hdr.ih_function, func); 53 be16enc(&hdr.ih_flags, flags); 54 append(&hdr, sizeof(hdr)); 55 } 56 57 void 58 isns_req::getspace(uint32_t len) 59 { 60 ir_buf.reserve(ir_buf.size() + len); 61 } 62 63 void 64 isns_req::append(const void *buf, size_t len) 65 { 66 const char *cp = reinterpret_cast<const char *>(buf); 67 ir_buf.insert(ir_buf.end(), cp, cp + len); 68 } 69 70 void 71 isns_req::add(uint32_t tag, uint32_t len, const void *value) 72 { 73 struct isns_tlv tlv; 74 uint32_t vlen; 75 76 vlen = roundup2(len, 4); 77 getspace(sizeof(tlv) + vlen); 78 be32enc(&tlv.it_tag, tag); 79 be32enc(&tlv.it_length, vlen); 80 append(&tlv, sizeof(tlv)); 81 append(value, len); 82 if (vlen != len) 83 ir_buf.insert(ir_buf.end(), vlen - len, 0); 84 } 85 86 void 87 isns_req::add_delim() 88 { 89 add(0, 0, nullptr); 90 } 91 92 void 93 isns_req::add_str(uint32_t tag, const char *value) 94 { 95 96 add(tag, strlen(value) + 1, value); 97 } 98 99 void 100 isns_req::add_32(uint32_t tag, uint32_t value) 101 { 102 uint32_t beval; 103 104 be32enc(&beval, value); 105 add(tag, sizeof(value), &beval); 106 } 107 108 void 109 isns_req::add_addr(uint32_t tag, const struct addrinfo *ai) 110 { 111 const struct sockaddr_in *in4; 112 const struct sockaddr_in6 *in6; 113 uint8_t buf[16]; 114 115 switch (ai->ai_addr->sa_family) { 116 case AF_INET: 117 in4 = (const struct sockaddr_in *)ai->ai_addr; 118 memset(buf, 0, 10); 119 buf[10] = 0xff; 120 buf[11] = 0xff; 121 memcpy(&buf[12], &in4->sin_addr, sizeof(in4->sin_addr)); 122 add(tag, sizeof(buf), buf); 123 break; 124 case AF_INET6: 125 in6 = (const struct sockaddr_in6 *)ai->ai_addr; 126 add(tag, sizeof(in6->sin6_addr), &in6->sin6_addr); 127 break; 128 default: 129 log_errx(1, "Unsupported address family %d", 130 ai->ai_addr->sa_family); 131 } 132 } 133 134 void 135 isns_req::add_port(uint32_t tag, const struct addrinfo *ai) 136 { 137 const struct sockaddr_in *in4; 138 const struct sockaddr_in6 *in6; 139 uint32_t buf; 140 141 switch (ai->ai_addr->sa_family) { 142 case AF_INET: 143 in4 = (const struct sockaddr_in *)ai->ai_addr; 144 be32enc(&buf, ntohs(in4->sin_port)); 145 add(tag, sizeof(buf), &buf); 146 break; 147 case AF_INET6: 148 in6 = (const struct sockaddr_in6 *)ai->ai_addr; 149 be32enc(&buf, ntohs(in6->sin6_port)); 150 add(tag, sizeof(buf), &buf); 151 break; 152 default: 153 log_errx(1, "Unsupported address family %d", 154 ai->ai_addr->sa_family); 155 } 156 } 157 158 bool 159 isns_req::send(int s) 160 { 161 struct isns_hdr *hdr; 162 int res; 163 164 hdr = (struct isns_hdr *)ir_buf.data(); 165 be16enc(hdr->ih_length, ir_buf.size() - sizeof(*hdr)); 166 be16enc(hdr->ih_flags, be16dec(hdr->ih_flags) | 167 ISNS_FLAG_LAST | ISNS_FLAG_FIRST); 168 be16enc(hdr->ih_transaction, 0); 169 be16enc(hdr->ih_sequence, 0); 170 171 res = write(s, ir_buf.data(), ir_buf.size()); 172 return (res > 0 && (size_t)res == ir_buf.size()); 173 } 174 175 bool 176 isns_req::receive(int s) 177 { 178 struct isns_hdr *hdr; 179 ssize_t res, len; 180 181 ir_buf.resize(sizeof(*hdr)); 182 res = read(s, ir_buf.data(), sizeof(*hdr)); 183 if (res < (ssize_t)sizeof(*hdr)) { 184 ir_buf.clear(); 185 return (false); 186 } 187 hdr = (struct isns_hdr *)ir_buf.data(); 188 if (be16dec(hdr->ih_version) != ISNS_VERSION) 189 return (false); 190 if ((be16dec(hdr->ih_flags) & (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) != 191 (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) 192 return (false); 193 len = be16dec(hdr->ih_length); 194 ir_buf.resize(sizeof(*hdr) + len); 195 res = read(s, ir_buf.data() + sizeof(*hdr), len); 196 if (res < len) 197 return (false); 198 return (res == len); 199 } 200 201 uint32_t 202 isns_req::get_status() 203 { 204 205 if (ir_buf.size() < sizeof(struct isns_hdr) + 4) 206 return (-1); 207 return (be32dec(&ir_buf[sizeof(struct isns_hdr)])); 208 } 209