xref: /freebsd/usr.sbin/ctld/isns.cc (revision 0aa09b7a2a37a437525d1b803ceb7342f37b3034)
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 
isns_req(uint16_t func,uint16_t flags,const char * descr)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
getspace(uint32_t len)58 isns_req::getspace(uint32_t len)
59 {
60 	ir_buf.reserve(ir_buf.size() + len);
61 }
62 
63 void
append(const void * buf,size_t len)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
add(uint32_t tag,uint32_t len,const void * value)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
add_delim()87 isns_req::add_delim()
88 {
89 	add(0, 0, nullptr);
90 }
91 
92 void
add_str(uint32_t tag,const char * value)93 isns_req::add_str(uint32_t tag, const char *value)
94 {
95 
96 	add(tag, strlen(value) + 1, value);
97 }
98 
99 void
add_32(uint32_t tag,uint32_t value)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
add_addr(uint32_t tag,const struct addrinfo * ai)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
add_port(uint32_t tag,const struct addrinfo * ai)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
send(int s)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
receive(int s)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
get_status()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