xref: /freebsd/usr.sbin/ppp/tcp.c (revision f5a99677)
15d9e6103SBrian Somers /*-
25d9e6103SBrian Somers  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
35d9e6103SBrian Somers  * All rights reserved.
45d9e6103SBrian Somers  *
55d9e6103SBrian Somers  * Redistribution and use in source and binary forms, with or without
65d9e6103SBrian Somers  * modification, are permitted provided that the following conditions
75d9e6103SBrian Somers  * are met:
85d9e6103SBrian Somers  * 1. Redistributions of source code must retain the above copyright
95d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer.
105d9e6103SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
115d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
125d9e6103SBrian Somers  *    documentation and/or other materials provided with the distribution.
135d9e6103SBrian Somers  *
145d9e6103SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155d9e6103SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165d9e6103SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175d9e6103SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185d9e6103SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195d9e6103SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205d9e6103SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215d9e6103SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225d9e6103SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235d9e6103SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245d9e6103SBrian Somers  * SUCH DAMAGE.
255d9e6103SBrian Somers  *
26f5a99677SBrian Somers  *	$Id: tcp.c,v 1.3 1999/05/24 16:39:15 brian Exp $
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>
39f5a99677SBrian Somers #include <sys/uio.h>
405d9e6103SBrian Somers #include <termios.h>
415d9e6103SBrian Somers #include <unistd.h>
425d9e6103SBrian Somers 
435d9e6103SBrian Somers #include "layer.h"
445d9e6103SBrian Somers #include "defs.h"
455d9e6103SBrian Somers #include "mbuf.h"
465d9e6103SBrian Somers #include "log.h"
475d9e6103SBrian Somers #include "sync.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
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.s_addr = inet_addr(host);
705d9e6103SBrian Somers   dest.sin_addr = GetIpAddr(host);
715d9e6103SBrian Somers   if (dest.sin_addr.s_addr == INADDR_NONE) {
725d9e6103SBrian Somers     log_Printf(LogWARN, "%s: %s: unknown host\n", name, host);
736815097bSBrian Somers     return -1;
745d9e6103SBrian Somers   }
755d9e6103SBrian Somers   dest.sin_port = htons(atoi(port));
765d9e6103SBrian Somers   if (dest.sin_port == 0) {
775d9e6103SBrian Somers     sp = getservbyname(port, "tcp");
786815097bSBrian Somers     if (sp)
795d9e6103SBrian Somers       dest.sin_port = sp->s_port;
806815097bSBrian Somers     else {
815d9e6103SBrian Somers       log_Printf(LogWARN, "%s: %s: unknown service\n", name, port);
826815097bSBrian Somers       return -1;
835d9e6103SBrian Somers     }
845d9e6103SBrian Somers   }
856815097bSBrian Somers   log_Printf(LogPHASE, "%s: Connecting to %s:%s/tcp\n", name, host, port);
865d9e6103SBrian Somers 
875d9e6103SBrian Somers   sock = socket(PF_INET, SOCK_STREAM, 0);
886815097bSBrian Somers   if (sock < 0)
896815097bSBrian Somers     return sock;
906815097bSBrian Somers 
915d9e6103SBrian Somers   if (connect(sock, (struct sockaddr *)&dest, sizeof dest) < 0) {
925d9e6103SBrian Somers     log_Printf(LogWARN, "%s: connect: %s\n", name, strerror(errno));
935d9e6103SBrian Somers     close(sock);
946815097bSBrian Somers     return -1;
955d9e6103SBrian Somers   }
965d9e6103SBrian Somers 
976815097bSBrian Somers   return sock;
985d9e6103SBrian Somers }
995d9e6103SBrian Somers 
1006815097bSBrian Somers static struct device tcpdevice = {
1016815097bSBrian Somers   TCP_DEVICE,
1025d9e6103SBrian Somers   "tcp",
1036815097bSBrian Somers   NULL,
1046815097bSBrian Somers   NULL,
1056815097bSBrian Somers   NULL,
1065d9e6103SBrian Somers   NULL,
1075d9e6103SBrian Somers   NULL,
1085d9e6103SBrian Somers   NULL,
1095d9e6103SBrian Somers   NULL,
1105d9e6103SBrian Somers   NULL,
1115d9e6103SBrian Somers   NULL,
1125d9e6103SBrian Somers   NULL
1135d9e6103SBrian Somers };
1146815097bSBrian Somers 
1156815097bSBrian Somers struct device *
1166815097bSBrian Somers tcp_iov2device(int type, struct physical *p, struct iovec *iov,
1176815097bSBrian Somers                int *niov, int maxiov)
1186815097bSBrian Somers {
119acbd1f00SBrian Somers   if (type == TCP_DEVICE) {
120f5a99677SBrian Somers     free(iov[(*niov)++].iov_base);
121acbd1f00SBrian Somers     physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
1226815097bSBrian Somers     return &tcpdevice;
123acbd1f00SBrian Somers   }
1246815097bSBrian Somers 
1256815097bSBrian Somers   return NULL;
1266815097bSBrian Somers }
1276815097bSBrian Somers 
1286815097bSBrian Somers struct device *
1296815097bSBrian Somers tcp_Create(struct physical *p)
1306815097bSBrian Somers {
1316815097bSBrian Somers   char *cp, *host, *port, *svc;
1326815097bSBrian Somers 
1336815097bSBrian Somers   if (p->fd < 0) {
1346815097bSBrian Somers     if ((cp = strchr(p->name.full, ':')) != NULL) {
1356815097bSBrian Somers       *cp = '\0';
1366815097bSBrian Somers       host = p->name.full;
1376815097bSBrian Somers       port = cp + 1;
1386815097bSBrian Somers       svc = strchr(port, '/');
1396815097bSBrian Somers       if (svc && strcasecmp(svc, "/tcp")) {
1406815097bSBrian Somers         *cp = ':';
1416815097bSBrian Somers         return 0;
1426815097bSBrian Somers       }
1436815097bSBrian Somers       if (svc)
1446815097bSBrian Somers         *svc = '\0';
1456815097bSBrian Somers       if (*host && *port) {
1466815097bSBrian Somers         p->fd = tcp_OpenConnection(p->link.name, host, port);
1476815097bSBrian Somers         *cp = ':';
1486815097bSBrian Somers         if (svc)
1496815097bSBrian Somers           *svc = '/';
1506815097bSBrian Somers         if (p->fd >= 0)
1516815097bSBrian Somers           log_Printf(LogDEBUG, "%s: Opened tcp socket %s\n", p->link.name,
1526815097bSBrian Somers                      p->name.full);
1536815097bSBrian Somers       } else {
1546815097bSBrian Somers         if (svc)
1556815097bSBrian Somers           *svc = '/';
1566815097bSBrian Somers         *cp = ':';
1576815097bSBrian Somers       }
1586815097bSBrian Somers     }
1596815097bSBrian Somers   }
1606815097bSBrian Somers 
1616815097bSBrian Somers   if (p->fd >= 0) {
1626815097bSBrian Somers     /* See if we're a tcp socket */
1636815097bSBrian Somers     int type, sz, err;
1646815097bSBrian Somers 
1656815097bSBrian Somers     sz = sizeof type;
1666815097bSBrian Somers     if ((err = getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz)) == 0 &&
1676815097bSBrian Somers         sz == sizeof type && type == SOCK_STREAM) {
1686815097bSBrian Somers       struct sockaddr_in sock;
1696815097bSBrian Somers       struct sockaddr *sockp = (struct sockaddr *)&sock;
1706815097bSBrian Somers 
1716815097bSBrian Somers       if (*p->name.full == '\0') {
1726815097bSBrian Somers         sz = sizeof sock;
1736815097bSBrian Somers         if (getpeername(p->fd, sockp, &sz) != 0 ||
1746815097bSBrian Somers             sz != sizeof(struct sockaddr_in) || sock.sin_family != AF_INET) {
1756815097bSBrian Somers           log_Printf(LogDEBUG, "%s: Link is SOCK_STREAM, but not inet\n",
1766815097bSBrian Somers                      p->link.name);
1776815097bSBrian Somers           return NULL;
1786815097bSBrian Somers         }
1796815097bSBrian Somers 
1806815097bSBrian Somers         log_Printf(LogPHASE, "%s: Link is a tcp socket\n", p->link.name);
1816815097bSBrian Somers 
1826815097bSBrian Somers         snprintf(p->name.full, sizeof p->name.full, "%s:%d/tcp",
1836815097bSBrian Somers                  inet_ntoa(sock.sin_addr), ntohs(sock.sin_port));
1846815097bSBrian Somers         p->name.base = p->name.full;
1856815097bSBrian Somers       }
186acbd1f00SBrian Somers       physical_SetupStack(p, tcpdevice.name, PHYSICAL_FORCE_ASYNC);
1876815097bSBrian Somers       return &tcpdevice;
1886815097bSBrian Somers     }
1896815097bSBrian Somers   }
1906815097bSBrian Somers 
1916815097bSBrian Somers   return NULL;
1926815097bSBrian Somers }
193