Actually allow tests of the release mechanism...
[tftp-hpa.git] / tftpd / recvfrom.c
blob22440ce208a910fa7d2539f09bffd985e56a4132
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
5 * This program is free software available under the same license
6 * as the "OpenBSD" operating system, distributed at
7 * http://www.openbsd.org/.
9 * ----------------------------------------------------------------------- */
12 * recvfrom.c
14 * Emulate recvfrom() using recvmsg(), but try to capture the local address
15 * since some TFTP clients consider it an error to get the reply from another
16 * IP address than the request was sent to.
20 #include "config.h" /* Must be included first! */
21 #include "recvfrom.h"
22 #include "tftpsubs.h"
23 #ifdef HAVE_MACHINE_PARAM_H
24 #include <machine/param.h> /* Needed on some versions of FreeBSD */
25 #endif
27 #if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
29 #include <sys/uio.h>
31 #ifdef IP_PKTINFO
32 # ifndef HAVE_STRUCT_IN_PKTINFO
33 # ifdef __linux__
34 /* Assume this version of glibc simply lacks the definition */
35 struct in_pktinfo {
36 int ipi_ifindex;
37 struct in_addr ipi_spec_dst;
38 struct in_addr ipi_addr;
40 # else
41 # undef IP_PKTINFO /* No definition, no way to get it */
42 # endif
43 # endif
44 #endif
46 #ifndef CMSG_LEN
47 # define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size))
48 #endif
49 #ifndef CMSG_SPACE
50 # define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
51 #endif
53 int
54 myrecvfrom(int s, void *buf, int len, unsigned int flags,
55 struct sockaddr *from, int *fromlen,
56 struct sockaddr_in *myaddr)
58 struct msghdr msg;
59 struct iovec iov;
60 int n;
61 struct cmsghdr *cmptr;
62 union {
63 struct cmsghdr cm;
64 #ifdef IP_PKTINFO
65 char control[CMSG_SPACE(sizeof(struct in_addr)) +
66 CMSG_SPACE(sizeof(struct in_pktinfo))];
67 #else
68 char control[CMSG_SPACE(sizeof(struct in_addr))];
69 #endif
70 } control_un;
71 int on = 1;
72 #ifdef IP_PKTINFO
73 struct in_pktinfo pktinfo;
74 #endif
76 /* Try to enable getting the return address */
77 #ifdef IP_RECVDSTADDR
78 setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
79 #endif
80 #ifdef IP_PKTINFO
81 setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
82 #endif
84 bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
85 msg.msg_control = control_un.control;
86 msg.msg_controllen = sizeof(control_un.control);
87 msg.msg_flags = 0;
89 msg.msg_name = from;
90 msg.msg_namelen = *fromlen;
91 iov.iov_base = buf;
92 iov.iov_len = len;
93 msg.msg_iov = &iov;
94 msg.msg_iovlen = 1;
96 if ( (n = recvmsg(s, &msg, flags)) < 0 )
97 return n; /* Error */
99 *fromlen = msg.msg_namelen;
101 if ( myaddr ) {
102 bzero(myaddr, sizeof(struct sockaddr_in));
103 myaddr->sin_family = AF_INET;
105 if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
106 (msg.msg_flags & MSG_CTRUNC) )
107 return n; /* No information available */
109 for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ;
110 cmptr = CMSG_NXTHDR(&msg, cmptr) ) {
112 #ifdef IP_RECVDSTADDR
113 if ( cmptr->cmsg_level == IPPROTO_IP &&
114 cmptr->cmsg_type == IP_RECVDSTADDR ) {
115 memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr),
116 sizeof(struct in_addr));
118 #endif
120 #ifdef IP_PKTINFO
121 if ( cmptr->cmsg_level == IPPROTO_IP &&
122 cmptr->cmsg_type == IP_PKTINFO ) {
123 memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
124 memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
126 #endif
131 return n;
134 #else /* pointless... */
137 myrecvfrom(int s, void *buf, int len, unsigned int flags,
138 struct sockaddr *from, int *fromlen,
139 struct sockaddr_in *myaddr)
141 /* There is no way we can get the local address, fudge it */
143 bzero(myaddr, sizeof(struct sockaddr_in));
144 myaddr->sin_family = AF_INET;
146 myaddr->sin_port = htons(IPPORT_TFTP);
147 bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
149 return recvfrom(s,buf,len,flags,from,fromlen);
152 #endif