-
Notifications
You must be signed in to change notification settings - Fork 0
/
tcpd.c
147 lines (112 loc) · 4.54 KB
/
tcpd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "constants.h"
void error(const char *msg)
{
perror(msg);
exit(1);
}
// create sockaddr_in for local port and bind it
struct sockaddr_in make_addr_and_bind(int sockfd, int port)
{
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(port);
local_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) error("binding");
return local_addr;
}
// create sockaddr_in for target end
struct sockaddr_in make_remote_addr(char host[], int port)
{
struct hostent *hp, *gethostbyname();
struct sockaddr_in remote_addr;
/* construct name for connecting to server */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(port);
/* convert hostname to IP address and enter into name */
hp = gethostbyname(host);
if(hp == 0) error("unknown host\n");
bcopy((char *)hp->h_addr, (char *)&remote_addr.sin_addr, hp->h_length);
return remote_addr;
}
int main(int argc, char *argv[])
{
int in_sockfd, out_sockfd, recv_sockfd;
int in_addr_len, out_addr_len, recv_addr_len;
struct sockaddr_in in_addr, out_addr, recv_addr;
char buffer[MSS + 1];
int recv_bytes, sent_bytes, buflen;
/*create socket for IPC with user process and bind it*/
in_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(in_sockfd < 0) error("opening datagram socket");
in_addr = make_addr_and_bind(in_sockfd, TCPD_IN_PORT);
in_addr_len = sizeof(in_addr);
/*create socket for troll communication and bind it*/
out_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(out_sockfd < 0) error("opening datagram socket");
out_addr = make_addr_and_bind(out_sockfd, TCPD_OUT_PORT);
//reuse out_addr to define target end i.e. troll
out_addr = make_remote_addr(LOCALHOST, TROLL_IN_PORT);
out_addr_len = sizeof(out_addr);
/*create socket for receiving communication and bind it*/
recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(recv_sockfd < 0) error("opening datagram socket");
recv_addr = make_addr_and_bind(recv_sockfd, TCPD_RECV_PORT);
recv_addr_len = sizeof(recv_addr);
// TODO: remove error checking for local sockets, they should be reliable?
while(1) {
// wait for message from local user process
recv_bytes = recvfrom(in_sockfd, buffer, MSS + 1, 0, (struct sockaddr *)&in_addr, &in_addr_len);
if( recv_bytes < 0) error("error receiving from user");
// Take appropriate action based on control byte
switch(buffer[0])
{
case 'X' : // Test communication by sending back same data
sent_bytes = sendto(in_sockfd, buffer, recv_bytes, 0, (struct sockaddr *)&in_addr, in_addr_len);
if(sent_bytes < recv_bytes) error("sending X back");
printf("SOCKET call\n");
break;
case 'S': //Send data to troll excluding control byte
sent_bytes = sendto(out_sockfd, buffer + 1, recv_bytes - 1, 0, (struct sockaddr *)&out_addr, out_addr_len);
if(sent_bytes < recv_bytes - 1) error("sending packet to troll");
// Get ACK from server
recv_bytes = recvfrom(recv_sockfd, buffer, MSS, 0, (struct sockaddr *)&recv_addr, &recv_addr_len);
if(recv_bytes < 0) error("receiving ACK");
// Unblock sender
sent_bytes = sendto(in_sockfd, buffer, recv_bytes, 0, (struct sockaddr *)&in_addr, in_addr_len);
if(sent_bytes < recv_bytes) error("sending received message to user");
printf("TCPD sent %d bytes\n", sent_bytes);
break;
case 'R': // User says we will receive data from remote host
recv_bytes = recvfrom(recv_sockfd, buffer, MSS, 0, (struct sockaddr *)&recv_addr, &recv_addr_len);
if(recv_bytes < 0) error("receiving packet from remote host");
//Send ACK to client(send back the received data to troll)
sent_bytes = sendto(out_sockfd, buffer , recv_bytes, 0, (struct sockaddr *)&out_addr, out_addr_len);
if(sent_bytes < recv_bytes - 1) error("sending ACK to troll");
// Send data to local user process
sent_bytes = sendto(in_sockfd, buffer, recv_bytes, 0, (struct sockaddr *)&in_addr, in_addr_len);
if(sent_bytes < recv_bytes) error("sending received message to user");
printf("TCPD receives %d bytes\n", recv_bytes);
break;
case 'B':
case 'L':
case 'A':
case 'C':
case 'Y':
break;
default: //Unknown control byte
printf("Invalid message: %c %.*s\n", buffer[0], recv_bytes -1 , buffer + 1);
break;
}
}
close(in_sockfd);
close(out_sockfd);
close(recv_sockfd);
return 0;
}