2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/ppp/server.c,v 1.28.2.6 2002/09/01 02:12:32 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/server.c,v 1.2 2003/06/17 04:30:01 dillon Exp $
30 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
45 #include "descriptor.h"
52 server_UpdateSet(struct fdescriptor
*d
, fd_set
*r
, fd_set
*w
, fd_set
*e
, int *n
)
54 struct server
*s
= descriptor2server(d
);
59 if (r
&& s
->fd
>= 0) {
63 log_Printf(LogTIMER
, "server: fdset(r) %d\n", s
->fd
);
67 for (p
= log_PromptList(); p
; p
= p
->next
)
68 sets
+= descriptor_UpdateSet(&p
->desc
, r
, w
, e
, n
);
74 server_IsSet(struct fdescriptor
*d
, const fd_set
*fdset
)
76 struct server
*s
= descriptor2server(d
);
79 if (s
->fd
>= 0 && FD_ISSET(s
->fd
, fdset
))
82 for (p
= log_PromptList(); p
; p
= p
->next
)
83 if (descriptor_IsSet(&p
->desc
, fdset
))
90 server_Read(struct fdescriptor
*d
, struct bundle
*bundle
, const fd_set
*fdset
)
92 struct server
*s
= descriptor2server(d
);
93 struct sockaddr_storage ss
;
94 struct sockaddr
*sa
= (struct sockaddr
*)&ss
;
95 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ss
;
97 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&ss
;
99 int ssize
= sizeof ss
, wfd
;
103 if (s
->fd
>= 0 && FD_ISSET(s
->fd
, fdset
)) {
104 wfd
= accept(s
->fd
, sa
, &ssize
);
106 log_Printf(LogERROR
, "server_Read: accept(): %s\n", strerror(errno
));
107 else if (sa
->sa_len
== 0) {
115 switch (sa
->sa_family
) {
117 log_Printf(LogPHASE
, "Connected to local client.\n");
121 ncpaddr_setsa(&addr
, sa
);
122 if (ntohs(sin
->sin_port
) < 1024) {
123 log_Printf(LogALERT
, "Rejected client connection from %s:%u"
124 "(invalid port number) !\n",
125 ncpaddr_ntoa(&addr
), ntohs(sin
->sin_port
));
130 log_Printf(LogPHASE
, "Connected to client from %s:%u\n",
131 ncpaddr_ntoa(&addr
), ntohs(sin
->sin_port
));
136 ncpaddr_setsa(&addr
, sa
);
137 if (ntohs(sin6
->sin6_port
) < 1024) {
138 log_Printf(LogALERT
, "Rejected client connection from %s:%u"
139 "(invalid port number) !\n",
140 ncpaddr_ntoa(&addr
), ntohs(sin6
->sin6_port
));
145 log_Printf(LogPHASE
, "Connected to client from %s:%u\n",
146 ncpaddr_ntoa(&addr
), ntohs(sin6
->sin6_port
));
151 write(wfd
, "Unrecognised access !\n", 22);
158 if ((p
= prompt_Create(s
, bundle
, wfd
)) == NULL
) {
159 write(wfd
, "Connection refused.\n", 20);
162 switch (sa
->sa_family
) {
164 p
->src
.type
= "local";
165 strncpy(p
->src
.from
, s
->cfg
.sockname
, sizeof p
->src
.from
- 1);
166 p
->src
.from
[sizeof p
->src
.from
- 1] = '\0';
170 snprintf(p
->src
.from
, sizeof p
->src
.from
, "%s:%u",
171 ncpaddr_ntoa(&addr
), ntohs(sin
->sin_port
));
176 snprintf(p
->src
.from
, sizeof p
->src
.from
, "%s:%u",
177 ncpaddr_ntoa(&addr
), ntohs(sin6
->sin6_port
));
181 prompt_TtyCommandMode(p
);
186 log_PromptListChanged
= 0;
187 for (p
= log_PromptList(); p
; p
= p
->next
)
188 if (descriptor_IsSet(&p
->desc
, fdset
)) {
189 descriptor_Read(&p
->desc
, bundle
, fdset
);
190 if (log_PromptListChanged
)
196 server_Write(struct fdescriptor
*d __unused
, struct bundle
*bundle __unused
, const fd_set
*fdset __unused
)
198 /* We never want to write here ! */
199 log_Printf(LogALERT
, "server_Write: Internal error: Bad call !\n");
203 struct server server
= {
216 server_Reopen(struct bundle
*bundle
)
218 char name
[sizeof server
.cfg
.sockname
];
222 enum server_stat ret
;
224 if (server
.cfg
.sockname
[0] != '\0') {
225 strcpy(name
, server
.cfg
.sockname
);
226 mask
= server
.cfg
.mask
;
227 server_Close(bundle
);
228 if (server
.cfg
.sockname
[0] != '\0' && stat(server
.cfg
.sockname
, &st
) == 0)
229 if (!(st
.st_mode
& S_IFSOCK
) || unlink(server
.cfg
.sockname
) != 0)
230 return SERVER_FAILED
;
231 ret
= server_LocalOpen(bundle
, name
, mask
);
232 } else if (server
.cfg
.port
!= 0) {
233 port
= server
.cfg
.port
;
234 server_Close(bundle
);
235 ret
= server_TcpOpen(bundle
, port
);
243 server_LocalOpen(struct bundle
*bundle
, const char *name
, mode_t mask
)
245 struct sockaddr_un ifsun
;
249 oldmask
= (mode_t
)-1; /* Silence compiler */
251 if (server
.cfg
.sockname
&& !strcmp(server
.cfg
.sockname
, name
))
252 server_Close(bundle
);
254 memset(&ifsun
, '\0', sizeof ifsun
);
255 ifsun
.sun_len
= strlen(name
);
256 if (ifsun
.sun_len
> sizeof ifsun
.sun_path
- 1) {
257 log_Printf(LogERROR
, "Local: %s: Path too long\n", name
);
258 return SERVER_INVALID
;
260 ifsun
.sun_family
= AF_LOCAL
;
261 strcpy(ifsun
.sun_path
, name
);
263 s
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
265 log_Printf(LogERROR
, "Local: socket: %s\n", strerror(errno
));
268 setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &s
, sizeof s
);
269 if (mask
!= (mode_t
)-1)
270 oldmask
= umask(mask
);
271 if (bind(s
, (struct sockaddr
*)&ifsun
, sizeof ifsun
) < 0) {
272 if (mask
!= (mode_t
)-1)
274 log_Printf(LogWARN
, "Local: bind: %s\n", strerror(errno
));
278 if (mask
!= (mode_t
)-1)
280 if (listen(s
, 5) != 0) {
281 log_Printf(LogERROR
, "Local: Unable to listen to socket -"
282 " BUNDLE overload?\n");
287 server_Close(bundle
);
290 strncpy(server
.cfg
.sockname
, ifsun
.sun_path
, sizeof server
.cfg
.sockname
- 1);
291 server
.cfg
.sockname
[sizeof server
.cfg
.sockname
- 1] = '\0';
292 server
.cfg
.mask
= mask
;
293 log_Printf(LogPHASE
, "Listening at local socket %s.\n", name
);
298 if (server
.fd
== -1) {
301 strncpy(server
.cfg
.sockname
, ifsun
.sun_path
,
302 sizeof server
.cfg
.sockname
- 1);
303 server
.cfg
.sockname
[sizeof server
.cfg
.sockname
- 1] = '\0';
304 server
.cfg
.mask
= mask
;
306 return SERVER_FAILED
;
310 server_TcpOpen(struct bundle
*bundle
, u_short port
)
312 struct sockaddr_storage ss
;
313 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ss
;
315 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&ss
;
319 if (server
.cfg
.port
== port
)
320 server_Close(bundle
);
323 return SERVER_INVALID
;
325 memset(&ss
, '\0', sizeof ss
);
327 if (probe
.ipv6_available
) {
328 sin6
->sin6_family
= AF_INET6
;
329 sin6
->sin6_port
= htons(port
);
330 sin6
->sin6_len
= (u_int8_t
)sizeof ss
;
332 s
= socket(PF_INET6
, SOCK_STREAM
, 0);
336 sin
->sin_family
= AF_INET
;
337 sin
->sin_port
= htons(port
);
338 sin
->sin_len
= (u_int8_t
)sizeof ss
;
339 sin
->sin_addr
.s_addr
= INADDR_ANY
;
341 s
= socket(PF_INET
, SOCK_STREAM
, 0);
345 log_Printf(LogERROR
, "Tcp: socket: %s\n", strerror(errno
));
349 setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &s
, sizeof s
);
350 if (bind(s
, (struct sockaddr
*)&ss
, sz
) < 0) {
351 log_Printf(LogWARN
, "Tcp: bind: %s\n", strerror(errno
));
355 if (listen(s
, 5) != 0) {
356 log_Printf(LogERROR
, "Tcp: Unable to listen to socket: %s\n",
361 server_Close(bundle
);
363 server
.cfg
.port
= port
;
364 *server
.cfg
.sockname
= '\0';
366 log_Printf(LogPHASE
, "Listening at port %d.\n", port
);
370 if (server
.fd
== -1) {
372 server
.cfg
.port
= port
;
373 *server
.cfg
.sockname
= '\0';
376 return SERVER_FAILED
;
380 server_Close(struct bundle
*bundle __unused
)
382 if (server
.fd
>= 0) {
383 if (*server
.cfg
.sockname
!= '\0') {
384 struct sockaddr_un un
;
387 if (getsockname(server
.fd
, (struct sockaddr
*)&un
, &sz
) == 0 &&
388 un
.sun_family
== AF_LOCAL
&& sz
== sizeof un
)
393 /* Drop associated prompts */
394 log_DestroyPrompts(&server
);
403 server_Clear(struct bundle
*bundle
)
407 ret
= server_Close(bundle
);
411 *server
.cfg
.sockname
= '\0';