1 /*
2 ** id_open.c Establish/initiate a connection to an IDENT server
3 **
4 ** Author: Peter Eriksson <pen@lysator.liu.se>
5 ** Fixes: P�r Emanuelsson <pell@lysator.liu.se>
6 */
7
8 #if HAVE_CONFIG_H
9 # include "config.h"
10 #endif
11
12 #include <stdio.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #if HAVE_SYS_TYPES_H
20 # include <sys/types.h>
21 #endif
22 #if HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
24 #endif
25 #if HAVE_SYS_SELECT_H
26 # include <sys/select.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 # include <sys/time.h>
30 # endif
31 #endif
32
33
34 #define IN_LIBIDENT_SRC
35 #include "ident.h"
36
37 #if HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40
41
id_open(const struct in_addr * laddr,const struct in_addr * faddr,struct timeval * timeout)42 ident_t *id_open (const struct in_addr *laddr, const struct in_addr *faddr,
43 struct timeval *timeout)
44 {
45 struct sockaddr_in lsockaddr, fsockaddr;
46
47 memset(&lsockaddr, 0, sizeof(lsockaddr));
48 lsockaddr.sin_family = AF_INET;
49 #if HAVE_SA_LEN
50 lsockaddr.sin_len = sizeof(lsockaddr);
51 #endif
52 lsockaddr.sin_addr.s_addr = laddr->s_addr;
53
54 memcpy(&fsockaddr, &lsockaddr, sizeof(fsockaddr));
55 fsockaddr.sin_addr.s_addr = faddr->s_addr;
56
57 return id_open_addr((struct sockaddr *)&lsockaddr,
58 (struct sockaddr *)&fsockaddr, timeout);
59 }
60
61
id_open_addr(const struct sockaddr * laddr,const struct sockaddr * faddr,struct timeval * timeout)62 ident_t *id_open_addr (const struct sockaddr *laddr,
63 const struct sockaddr *faddr, struct timeval *timeout)
64 {
65 ident_t *id;
66 int res, tmperrno, pf;
67 struct sockaddr_storage ss_laddr, ss_faddr;
68 fd_set rs, ws, es;
69 const int on = 1;
70 struct linger linger;
71
72 if ((id = (ident_t *) malloc(sizeof(*id))) == NULL)
73 return NULL;
74
75 switch (faddr->sa_family)
76 {
77 case AF_INET:
78 pf = PF_INET;
79 break;
80
81 #ifdef AF_INET6
82 case AF_INET6:
83 pf = PF_INET6;
84 break;
85 #endif
86
87 default:
88 free(id);
89 return NULL;
90 }
91
92 if ((id->fd = socket(pf, SOCK_STREAM, 0)) < 0)
93 {
94 free(id);
95 return NULL;
96 }
97
98 if (timeout)
99 {
100 if (((res = fcntl(id->fd, F_GETFL, 0)) < 0)
101 || (fcntl(id->fd, F_SETFL, res | FNDELAY) < 0))
102 goto ERROR;
103 }
104
105 /* We silently ignore errors if we can't change LINGER */
106 /* New style setsockopt() */
107 linger.l_onoff = 0;
108 linger.l_linger = 0;
109
110 setsockopt(id->fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
111 setsockopt(id->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
112
113 id->buf[0] = '\0';
114
115 memcpy(&ss_laddr, laddr, sizeof(ss_laddr));
116 switch (ss_laddr.ss_family)
117 {
118 case AF_INET:
119 ((struct sockaddr_in *)&ss_laddr)->sin_port = 0;
120 break;
121
122 #ifdef AF_INET6
123 case AF_INET6:
124 ((struct sockaddr_in6 *)&ss_laddr)->sin6_port = 0;
125 break;
126 #endif
127 }
128
129
130 #if HAVE_SA_LEN
131 if (bind(id->fd, (struct sockaddr *) &ss_laddr, ss_laddr.ss_len) < 0)
132 #else
133 if (bind(id->fd, (struct sockaddr *) &ss_laddr, sizeof(ss_laddr)) < 0)
134 #endif
135 {
136 #ifdef DEBUG
137 perror("libident: bind");
138 #endif
139 goto ERROR;
140 }
141
142 memcpy(&ss_faddr, faddr, sizeof(ss_faddr));
143 switch (ss_faddr.ss_family)
144 {
145 case AF_INET:
146 ((struct sockaddr_in *)&ss_faddr)->sin_port = htons(IPPORT_IDENT);
147 break;
148
149 #ifdef AF_INET6
150 case AF_INET6:
151 ((struct sockaddr_in6 *)&ss_faddr)->sin6_port = htons(IPPORT_IDENT);
152 break;
153 #endif
154 }
155
156 errno = 0;
157 #if HAVE_SA_LEN
158 res = connect(id->fd, (struct sockaddr *)&ss_faddr, ss_faddr.ss_len);
159 #else
160 res = connect(id->fd, (struct sockaddr *)&ss_faddr, sizeof(ss_faddr));
161 #endif
162
163 if (res < 0 && errno != EINPROGRESS)
164 {
165 #ifdef DEBUG
166 perror("libident: connect");
167 #endif
168 goto ERROR;
169 }
170
171 if (timeout)
172 {
173 FD_ZERO(&rs);
174 FD_ZERO(&ws);
175 FD_ZERO(&es);
176
177 FD_SET(id->fd, &rs);
178 FD_SET(id->fd, &ws);
179 FD_SET(id->fd, &es);
180
181 if ((res = select(FD_SETSIZE, &rs, &ws, &es, timeout)) < 0)
182 {
183 #ifdef DEBUG
184 perror("libident: select");
185 #endif
186 goto ERROR;
187 }
188
189 if (res == 0)
190 {
191 errno = ETIMEDOUT;
192 goto ERROR;
193 }
194
195 if (FD_ISSET(id->fd, &es))
196 goto ERROR;
197
198 if (!FD_ISSET(id->fd, &rs) && !FD_ISSET(id->fd, &ws))
199 goto ERROR;
200 }
201
202 return id;
203
204 ERROR:
205 tmperrno = errno; /* Save, so close() won't erase it */
206 close(id->fd);
207 free(id);
208 errno = tmperrno;
209 return NULL;
210 }
211