]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/iputils.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/socket.h>
28 /** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */
30 static void RuntimeError(const boost::format
& fmt
)
32 throw runtime_error(fmt
.str());
36 int SSocket(int family
, int type
, int flags
)
38 int ret
= socket(family
, type
, flags
);
40 RuntimeError(boost::format("creating socket of type %d: %s") % family
% strerror(errno
));
44 int SConnect(int sockfd
, const ComboAddress
& remote
)
46 int ret
= connect(sockfd
, (struct sockaddr
*)&remote
, remote
.getSocklen());
48 int savederrno
= errno
;
49 RuntimeError(boost::format("connecting socket to %s: %s") % remote
.toStringWithPort() % strerror(savederrno
));
54 int SBind(int sockfd
, const ComboAddress
& local
)
56 int ret
= bind(sockfd
, (struct sockaddr
*)&local
, local
.getSocklen());
58 int savederrno
= errno
;
59 RuntimeError(boost::format("binding socket to %s: %s") % local
.toStringWithPort() % strerror(savederrno
));
64 int SAccept(int sockfd
, ComboAddress
& remote
)
66 socklen_t remlen
= remote
.getSocklen();
68 int ret
= accept(sockfd
, (struct sockaddr
*)&remote
, &remlen
);
70 RuntimeError(boost::format("accepting new connection on socket: %s") % strerror(errno
));
74 int SListen(int sockfd
, int limit
)
76 int ret
= listen(sockfd
, limit
);
78 RuntimeError(boost::format("setting socket to listen: %s") % strerror(errno
));
82 int SSetsockopt(int sockfd
, int level
, int opname
, int value
)
84 int ret
= setsockopt(sockfd
, level
, opname
, &value
, sizeof(value
));
86 RuntimeError(boost::format("setsockopt for level %d and opname %d to %d failed: %s") % level
% opname
% value
% strerror(errno
));
91 bool HarvestTimestamp(struct msghdr
* msgh
, struct timeval
* tv
)
95 for (cmsg
= CMSG_FIRSTHDR(msgh
); cmsg
!= NULL
; cmsg
= CMSG_NXTHDR(msgh
,cmsg
)) {
96 if ((cmsg
->cmsg_level
== SOL_SOCKET
) && (cmsg
->cmsg_type
== SO_TIMESTAMP
|| cmsg
->cmsg_type
== SCM_TIMESTAMP
) &&
97 CMSG_LEN(sizeof(*tv
)) == cmsg
->cmsg_len
) {
98 memcpy(tv
, CMSG_DATA(cmsg
), sizeof(*tv
));
105 bool HarvestDestinationAddress(struct msghdr
* msgh
, ComboAddress
* destination
)
107 memset(destination
, 0, sizeof(*destination
));
108 struct cmsghdr
*cmsg
;
109 for (cmsg
= CMSG_FIRSTHDR(msgh
); cmsg
!= NULL
; cmsg
= CMSG_NXTHDR(msgh
,cmsg
)) {
110 #if defined(IP_PKTINFO)
111 if ((cmsg
->cmsg_level
== IPPROTO_IP
) && (cmsg
->cmsg_type
== IP_PKTINFO
)) {
112 struct in_pktinfo
*i
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
113 destination
->sin4
.sin_addr
= i
->ipi_addr
;
114 destination
->sin4
.sin_family
= AF_INET
;
117 #elif defined(IP_RECVDSTADDR)
118 if ((cmsg
->cmsg_level
== IPPROTO_IP
) && (cmsg
->cmsg_type
== IP_RECVDSTADDR
)) {
119 struct in_addr
*i
= (struct in_addr
*) CMSG_DATA(cmsg
);
120 destination
->sin4
.sin_addr
= *i
;
121 destination
->sin4
.sin_family
= AF_INET
;
126 if ((cmsg
->cmsg_level
== IPPROTO_IPV6
) && (cmsg
->cmsg_type
== IPV6_PKTINFO
)) {
127 struct in6_pktinfo
*i
= (struct in6_pktinfo
*) CMSG_DATA(cmsg
);
128 destination
->sin6
.sin6_addr
= i
->ipi6_addr
;
129 destination
->sin4
.sin_family
= AF_INET6
;
136 bool IsAnyAddress(const ComboAddress
& addr
)
138 if(addr
.sin4
.sin_family
== AF_INET
)
139 return addr
.sin4
.sin_addr
.s_addr
== 0;
140 else if(addr
.sin4
.sin_family
== AF_INET6
)
141 return !memcmp(&addr
.sin6
.sin6_addr
, &in6addr_any
, sizeof(addr
.sin6
.sin6_addr
));
146 ssize_t
sendfromto(int sock
, const char* data
, size_t len
, int flags
, const ComboAddress
& from
, const ComboAddress
& to
)
152 /* Set up iov and msgh structures. */
153 memset(&msgh
, 0, sizeof(struct msghdr
));
154 iov
.iov_base
= (void*)data
;
158 msgh
.msg_name
= (struct sockaddr
*)&to
;
159 msgh
.msg_namelen
= to
.getSocklen();
161 if(from
.sin4
.sin_family
) {
162 addCMsgSrcAddr(&msgh
, cbuf
, &from
, 0);
165 msgh
.msg_control
=NULL
;
167 return sendmsg(sock
, &msgh
, flags
);
170 // be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works!
171 // be careful: when using this function for *send* purposes, be sure to set cbufsize to 0!
172 // be careful: if you don't call addCMsgSrcAddr after fillMSGHdr, make sure to set msg_control to NULL
173 void fillMSGHdr(struct msghdr
* msgh
, struct iovec
* iov
, char* cbuf
, size_t cbufsize
, char* data
, size_t datalen
, ComboAddress
* addr
)
175 iov
->iov_base
= data
;
176 iov
->iov_len
= datalen
;
178 memset(msgh
, 0, sizeof(struct msghdr
));
180 msgh
->msg_control
= cbuf
;
181 msgh
->msg_controllen
= cbufsize
;
182 msgh
->msg_name
= addr
;
183 msgh
->msg_namelen
= addr
->getSocklen();
185 msgh
->msg_iovlen
= 1;
189 void ComboAddress::truncate(unsigned int bits
)
193 if(sin4
.sin_family
==AF_INET
) {
196 start
= (uint8_t*)&sin4
.sin_addr
.s_addr
;
202 start
= (uint8_t*)&sin6
.sin6_addr
.s6_addr
;
206 auto tozero
= len
*8 - bits
; // if set to 22, this will clear 1 byte, as it should
208 memset(start
+ len
- tozero
/8, 0, tozero
/8); // blot out the whole bytes on the right
210 auto bitsleft
=tozero
% 8; // 2 bits left to clear
212 // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c
213 // so and by '11111100', which is ~((1<<2)-1) = ~3
214 uint8_t* place
= start
+ len
- 1 - tozero
/8;
215 *place
&= (~((1<<bitsleft
)-1));
218 ssize_t
sendMsgWithTimeout(int fd
, const char* buffer
, size_t len
, int timeout
, ComboAddress
& dest
, const ComboAddress
& local
, unsigned int localItf
)
223 bool firstTry
= true;
224 fillMSGHdr(&msgh
, &iov
, cbuf
, sizeof(cbuf
), const_cast<char*>(buffer
), len
, &dest
);
225 addCMsgSrcAddr(&msgh
, cbuf
, &local
, localItf
);
228 ssize_t written
= sendmsg(fd
, &msgh
, 0);
233 if (errno
== EAGAIN
) {
235 int res
= waitForRWData(fd
, false, timeout
, 0);
237 /* there is room available */
241 throw runtime_error("Timeout while waiting to write data");
243 throw runtime_error("Error while waiting for room to write data");
247 throw runtime_error("Timeout while waiting to write data");
251 unixDie("failed in write2WithTimeout");
259 template class NetmaskTree
<bool>;