xref: /freebsd/usr.sbin/ppp/tcp.c (revision b3e76948)
15d9e6103SBrian Somers /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
45d9e6103SBrian Somers  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
55d9e6103SBrian Somers  * All rights reserved.
65d9e6103SBrian Somers  *
75d9e6103SBrian Somers  * Redistribution and use in source and binary forms, with or without
85d9e6103SBrian Somers  * modification, are permitted provided that the following conditions
95d9e6103SBrian Somers  * are met:
105d9e6103SBrian Somers  * 1. Redistributions of source code must retain the above copyright
115d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer.
125d9e6103SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
135d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
145d9e6103SBrian Somers  *    documentation and/or other materials provided with the distribution.
155d9e6103SBrian Somers  *
165d9e6103SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175d9e6103SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185d9e6103SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195d9e6103SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205d9e6103SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215d9e6103SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225d9e6103SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235d9e6103SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245d9e6103SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255d9e6103SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265d9e6103SBrian Somers  * SUCH DAMAGE.
275d9e6103SBrian Somers  */
285d9e6103SBrian Somers 
295d9e6103SBrian Somers #include <sys/types.h>
305d9e6103SBrian Somers #include <sys/socket.h>
315d9e6103SBrian Somers #include <netinet/in.h>
325d9e6103SBrian Somers #include <arpa/inet.h>
335d9e6103SBrian Somers #include <netdb.h>
345d9e6103SBrian Somers 
355d9e6103SBrian Somers #include <errno.h>
365d9e6103SBrian Somers #include <stdio.h>
375d9e6103SBrian Somers #include <stdlib.h>
385d9e6103SBrian Somers #include <string.h>
39165fbe26SBrian Somers #include <sys/stat.h>
40f5a99677SBrian Somers #include <sys/uio.h>
415d9e6103SBrian Somers #include <termios.h>
425d9e6103SBrian Somers #include <unistd.h>
435d9e6103SBrian Somers 
445d9e6103SBrian Somers #include "layer.h"
455d9e6103SBrian Somers #include "defs.h"
465d9e6103SBrian Somers #include "mbuf.h"
475d9e6103SBrian Somers #include "log.h"
485d9e6103SBrian Somers #include "timer.h"
495d9e6103SBrian Somers #include "lqr.h"
505d9e6103SBrian Somers #include "hdlc.h"
515d9e6103SBrian Somers #include "throughput.h"
525d9e6103SBrian Somers #include "fsm.h"
535d9e6103SBrian Somers #include "lcp.h"
545d9e6103SBrian Somers #include "ccp.h"
555d9e6103SBrian Somers #include "link.h"
565d9e6103SBrian Somers #include "async.h"
575d9e6103SBrian Somers #include "descriptor.h"
585d9e6103SBrian Somers #include "physical.h"
595d9e6103SBrian Somers #include "tcp.h"
605d9e6103SBrian Somers 
615d9e6103SBrian Somers static int
tcp_OpenConnection(const char * name,char * host,char * port)626815097bSBrian Somers tcp_OpenConnection(const char *name, char *host, char *port)
635d9e6103SBrian Somers {
645d9e6103SBrian Somers   struct sockaddr_in dest;
655d9e6103SBrian Somers   int sock;
665d9e6103SBrian Somers   struct servent *sp;
675d9e6103SBrian Somers 
685d9e6103SBrian Somers   dest.sin_family = AF_INET;
695d9e6103SBrian Somers   dest.sin_addr = GetIpAddr(host);
705d9e6103SBrian Somers   if (dest.sin_addr.s_addr == INADDR_NONE) {
715d9e6103SBrian Somers     log_Printf(LogWARN, "%s: %s: unknown host\n", name, host);
72bcff3386SBrian Somers     return -2;
735d9e6103SBrian Somers   }
745d9e6103SBrian Somers   dest.sin_port = htons(atoi(port));
755d9e6103SBrian Somers   if (dest.sin_port == 0) {
765d9e6103SBrian Somers     sp = getservbyname(port, "tcp");
776815097bSBrian Somers     if (sp)
785d9e6103SBrian Somers       dest.sin_port = sp->s_port;
796815097bSBrian Somers     else {
805d9e6103SBrian Somers       log_Printf(LogWARN, "%s: %s: unknown service\n", name, port);
81bcff3386SBrian Somers       return -2;
825d9e6103SBrian Somers     }
835d9e6103SBrian Somers   }
846815097bSBrian Somers   log_Printf(LogPHASE, "%s: Connecting to %s:%s/tcp\n", name, host, port);
855d9e6103SBrian Somers 
8663c6cac9SBrian Somers   sock = socket(PF_INET, SOCK_STREAM, 0);
876815097bSBrian Somers   if (sock < 0)
88bcff3386SBrian Somers     return -2;
896815097bSBrian Somers 
905d9e6103SBrian Somers   if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) {
915d9e6103SBrian Somers     log_Printf(LogWARN, "%s: connect: %s\n", name, strerror(errno));
925d9e6103SBrian Somers     close(sock);
93bcff3386SBrian Somers     return -2;
945d9e6103SBrian Somers   }
955d9e6103SBrian Somers 
966815097bSBrian Somers   return sock;
975d9e6103SBrian Somers }
985d9e6103SBrian Somers 
996815097bSBrian Somers static struct device tcpdevice = {
1006815097bSBrian Somers   TCP_DEVICE,
1015d9e6103SBrian Somers   "tcp",
102c8b9fb53SBrian Somers   0,
103fdc29d54SBrian Somers   { CD_NOTREQUIRED, 0 },
1046815097bSBrian Somers   NULL,
1056815097bSBrian Somers   NULL,
1066815097bSBrian Somers   NULL,
1075d9e6103SBrian Somers   NULL,
1085d9e6103SBrian Somers   NULL,
1095d9e6103SBrian Somers   NULL,
1105d9e6103SBrian Somers   NULL,
1115d9e6103SBrian Somers   NULL,
1125d9e6103SBrian Somers   NULL,
113eb6e5e05SBrian Somers   NULL,
11487c3786eSBrian Somers   NULL,
115fb11a9c2SBrian Somers   NULL,
116de59e178SBrian Somers   NULL,
1175d9e6103SBrian Somers   NULL
1185d9e6103SBrian Somers };
1196815097bSBrian Somers 
1206815097bSBrian Somers struct device *
tcp_iov2device(int type,struct physical * p,struct iovec * iov,int * niov,int maxiov __unused,int * auxfd __unused,int * nauxfd __unused)1216815097bSBrian Somers tcp_iov2device(int type, struct physical *p, struct iovec *iov,
122057f1760SBrian Somers                int *niov, int maxiov __unused, int *auxfd __unused,
123057f1760SBrian Somers 	       int *nauxfd __unused)
1246815097bSBrian Somers {
125acbd1f00SBrian Somers   if (type == TCP_DEVICE) {
126f5a99677SBrian Somers     free(iov[(*niov)++].iov_base);
127acbd1f00SBrian Somers     physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
1286815097bSBrian Somers     return &tcpdevice;
129acbd1f00SBrian Somers   }
1306815097bSBrian Somers 
1316815097bSBrian Somers   return NULL;
1326815097bSBrian Somers }
1336815097bSBrian Somers 
1346815097bSBrian Somers struct device *
tcp_Create(struct physical * p)1356815097bSBrian Somers tcp_Create(struct physical *p)
1366815097bSBrian Somers {
1376815097bSBrian Somers   char *cp, *host, *port, *svc;
1386815097bSBrian Somers 
1396815097bSBrian Somers   if (p->fd < 0) {
14087c3786eSBrian Somers     if ((cp = strchr(p->name.full, ':')) != NULL && !strchr(cp + 1, ':')) {
1416815097bSBrian Somers       *cp = '\0';
1426815097bSBrian Somers       host = p->name.full;
1436815097bSBrian Somers       port = cp + 1;
1446815097bSBrian Somers       svc = strchr(port, '/');
1456815097bSBrian Somers       if (svc && strcasecmp(svc, "/tcp")) {
1466815097bSBrian Somers         *cp = ':';
1476815097bSBrian Somers         return 0;
1486815097bSBrian Somers       }
14987c3786eSBrian Somers       if (svc) {
15087c3786eSBrian Somers         p->fd--;     /* We own the device but maybe can't use it - change fd */
1516815097bSBrian Somers         *svc = '\0';
15287c3786eSBrian Somers       }
1536815097bSBrian Somers       if (*host && *port) {
1546815097bSBrian Somers         p->fd = tcp_OpenConnection(p->link.name, host, port);
1556815097bSBrian Somers         *cp = ':';
1566815097bSBrian Somers         if (svc)
1576815097bSBrian Somers           *svc = '/';
1586815097bSBrian Somers         if (p->fd >= 0)
1596815097bSBrian Somers           log_Printf(LogDEBUG, "%s: Opened tcp socket %s\n", p->link.name,
1606815097bSBrian Somers                      p->name.full);
1616815097bSBrian Somers       } else {
1626815097bSBrian Somers         if (svc)
1636815097bSBrian Somers           *svc = '/';
1646815097bSBrian Somers         *cp = ':';
1656815097bSBrian Somers       }
1666815097bSBrian Somers     }
1676815097bSBrian Somers   }
1686815097bSBrian Somers 
1696815097bSBrian Somers   if (p->fd >= 0) {
1706815097bSBrian Somers     /* See if we're a tcp socket */
171165fbe26SBrian Somers     struct stat st;
172165fbe26SBrian Somers 
173165fbe26SBrian Somers     if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) {
174165fbe26SBrian Somers       int type, sz;
1756815097bSBrian Somers 
1766815097bSBrian Somers       sz = sizeof type;
177165fbe26SBrian Somers       if (getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz) == -1) {
178165fbe26SBrian Somers         log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name);
179165fbe26SBrian Somers         close(p->fd);
180165fbe26SBrian Somers         p->fd = -1;
181165fbe26SBrian Somers         return NULL;
182165fbe26SBrian Somers       }
183165fbe26SBrian Somers 
184165fbe26SBrian Somers       if (sz == sizeof type && type == SOCK_STREAM) {
1856815097bSBrian Somers         struct sockaddr_in sock;
1866815097bSBrian Somers         struct sockaddr *sockp = (struct sockaddr *)&sock;
1876815097bSBrian Somers 
1886815097bSBrian Somers         if (*p->name.full == '\0') {
1896815097bSBrian Somers           sz = sizeof sock;
1906815097bSBrian Somers           if (getpeername(p->fd, sockp, &sz) != 0 ||
1916815097bSBrian Somers               sz != sizeof(struct sockaddr_in) || sock.sin_family != AF_INET) {
1926815097bSBrian Somers             log_Printf(LogDEBUG, "%s: Link is SOCK_STREAM, but not inet\n",
1936815097bSBrian Somers                        p->link.name);
1946815097bSBrian Somers             return NULL;
1956815097bSBrian Somers           }
1966815097bSBrian Somers 
1976815097bSBrian Somers           log_Printf(LogPHASE, "%s: Link is a tcp socket\n", p->link.name);
1986815097bSBrian Somers 
1996815097bSBrian Somers           snprintf(p->name.full, sizeof p->name.full, "%s:%d/tcp",
2006815097bSBrian Somers                    inet_ntoa(sock.sin_addr), ntohs(sock.sin_port));
2016815097bSBrian Somers           p->name.base = p->name.full;
2026815097bSBrian Somers         }
203acbd1f00SBrian Somers         physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
204fdc29d54SBrian Somers         if (p->cfg.cd.necessity != CD_DEFAULT)
205fdc29d54SBrian Somers           log_Printf(LogWARN, "Carrier settings ignored\n");
2066815097bSBrian Somers         return &tcpdevice;
2076815097bSBrian Somers       }
2086815097bSBrian Somers     }
209165fbe26SBrian Somers   }
2106815097bSBrian Somers 
2116815097bSBrian Somers   return NULL;
2126815097bSBrian Somers }
213