]> Pileus Git - ~andy/fetchmail/blob - socket.c
Prevent buffer spamming.
[~andy/fetchmail] / socket.c
1 /*
2  * socket.c -- socket library functions
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include "config.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <netdb.h>
15 #if defined(STDC_HEADERS)
16 #include <stdlib.h>
17 #endif
18 #if defined(HAVE_UNISTD_H)
19 #include <unistd.h>
20 #endif
21 #if defined(HAVE_STDARG_H)
22 #include <stdarg.h>
23 #else
24 #include <varargs.h>
25 #endif
26 #include "socket.h"
27
28 #ifndef  INADDR_NONE
29 #ifdef   INADDR_BROADCAST
30 #define  INADDR_NONE    INADDR_BROADCAST
31 #else
32 #define  INADDR_NONE    -1
33 #endif
34 #endif
35
36 #ifdef SUNOS
37 #include <memory.h>
38 #endif
39
40 int SockOpen(char *host, int clientPort)
41 {
42     int sock;
43     unsigned long inaddr;
44     struct sockaddr_in ad;
45     struct hostent *hp;
46
47     memset(&ad, 0, sizeof(ad));
48     ad.sin_family = AF_INET;
49
50     inaddr = inet_addr(host);
51     if (inaddr != INADDR_NONE)
52         memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
53     else
54     {
55         hp = gethostbyname(host);
56
57         /*
58          * Add a check to make sure the address has a valid IPv4 or IPv6
59          * length.  This prevents buffer spamming by a broken DNS.
60          */
61         if (hp == NULL || (hp->h_length != 4 && hp->h_length != 8))
62             return -1;
63
64         memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
65     }
66     ad.sin_port = htons(clientPort);
67     
68     sock = socket(AF_INET, SOCK_STREAM, 0);
69     if (sock < 0)
70         return -1;
71     if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
72     {
73         close(sock);
74         return -1;
75     }
76
77     return(sock);
78 }
79
80
81 #if defined(HAVE_STDARG_H)
82 int SockPrintf(int sock, char* format, ...)
83 {
84 #else
85 int SockPrintf(sock,format,va_alist)
86 int sock;
87 char *format;
88 va_dcl {
89 #endif
90
91     va_list ap;
92     char buf[8192];
93
94 #if defined(HAVE_STDARG_H)
95     va_start(ap, format) ;
96 #else
97     va_start(ap);
98 #endif
99 #ifdef HAVE_VSNPRINTF
100     vsnprintf(buf, sizeof(buf), format, ap);
101 #else
102     vsprintf(buf, format, ap);
103 #endif
104     va_end(ap);
105     return SockWrite(sock, buf, strlen(buf));
106
107 }
108
109 int SockWrite(int sock, char *buf, int len)
110 {
111     int n, wrlen = 0;
112
113     while (len)
114     {
115         n = write(sock, buf, len);
116         if (n <= 0)
117             return -1;
118         len -= n;
119         wrlen += n;
120         buf += n;
121     }
122     return wrlen;
123 }
124
125 int SockRead(int sock, char *buf, int len)
126 {
127     char *newline, *bp = buf;
128     int n;
129
130     if (--len < 1)
131         return(-1);
132     do {
133         /* 
134          * The reason for these gymnastics is that we want two things:
135          * (1) to read \n-terminated lines,
136          * (2) to return the true length of data read, even if the
137          *     data coming in has embedded NULS.
138          */
139         if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
140             return(-1);
141         if ((newline = memchr(bp, '\n', n)) != NULL)
142             n = newline - bp + 1;
143         if ((n = read(sock, bp, n)) == -1)
144             return(-1);
145         bp += n;
146         len -= n;
147     } while 
148             (!newline && len);
149     *bp = '\0';
150     return bp - buf;
151 }
152
153 int SockPeek(int sock)
154 /* peek at the next socket character without actually reading it */
155 {
156     int n;
157     char ch;
158
159     if ((n = recv(sock, &ch, 1, MSG_PEEK)) == -1)
160         return -1;
161     else
162         return(ch);
163 }
164
165 #ifdef MAIN
166 /*
167  * Use the chargen service to test input beuffering directly.
168  * You may have to uncomment the `chargen' service description in your
169  * inetd.conf (and then SIGHUP inetd) for this to work. 
170  */
171 main()
172 {
173     int         sock = SockOpen("localhost", 19);
174     char        buf[80];
175
176     while (SockRead(sock, buf, sizeof(buf)-1))
177         SockWrite(1, buf, strlen(buf));
178 }
179 #endif /* MAIN */
180
181 /* socket.c ends here */