1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #if !defined(lint) 9 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10 static const char rcsid[] = "@(#)$Id$"; 11 #endif 12 #include <sys/types.h> 13 #include <sys/time.h> 14 #include <sys/socket.h> 15 16 #include <netinet/in.h> 17 #include <net/if.h> 18 19 #include <arpa/inet.h> 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <fcntl.h> 24 #include <string.h> 25 #include <unistd.h> 26 #include <syslog.h> 27 #include <errno.h> 28 #include <signal.h> 29 30 #include "netinet/ip_compat.h" 31 #include "netinet/ip_fil.h" 32 #include "netinet/ip_state.h" 33 #include "netinet/ip_nat.h" 34 #include "netinet/ip_sync.h" 35 36 int main(int, char *[]); 37 void usage(const char *progname); 38 39 int terminate = 0; 40 41 void usage(const char *progname) { 42 fprintf(stderr, 43 "Usage: %s <destination IP> <destination port> [remote IP]\n", 44 progname); 45 } 46 47 #if 0 48 static void handleterm(int sig) 49 { 50 terminate = sig; 51 } 52 #endif 53 54 #define BUFFERLEN 1400 55 56 int main(argc, argv) 57 int argc; 58 char *argv[]; 59 { 60 int nfd = -1 , lfd = -1; 61 int n1, n2, n3, magic, len, inbuf; 62 struct sockaddr_in sin; 63 struct sockaddr_in in; 64 char buff[BUFFERLEN]; 65 synclogent_t *sl; 66 syncupdent_t *su; 67 synchdr_t *sh; 68 char *progname; 69 70 progname = strrchr(argv[0], '/'); 71 if (progname) { 72 progname++; 73 } else { 74 progname = argv[0]; 75 } 76 77 if (argc < 2) { 78 usage(progname); 79 exit(1); 80 } 81 82 #if 0 83 signal(SIGHUP, handleterm); 84 signal(SIGINT, handleterm); 85 signal(SIGTERM, handleterm); 86 #endif 87 88 openlog(progname, LOG_PID, LOG_SECURITY); 89 90 lfd = open(IPSYNC_NAME, O_WRONLY); 91 if (lfd == -1) { 92 syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); 93 exit(1); 94 } 95 96 bzero((char *)&sin, sizeof(sin)); 97 sin.sin_family = AF_INET; 98 if (argc > 1) 99 sin.sin_addr.s_addr = inet_addr(argv[1]); 100 if (argc > 2) 101 sin.sin_port = htons(atoi(argv[2])); 102 else 103 sin.sin_port = htons(43434); 104 if (argc > 3) 105 in.sin_addr.s_addr = inet_addr(argv[3]); 106 else 107 in.sin_addr.s_addr = 0; 108 in.sin_port = 0; 109 110 while(1) { 111 112 if (lfd != -1) 113 close(lfd); 114 if (nfd != -1) 115 close(nfd); 116 117 lfd = open(IPSYNC_NAME, O_WRONLY); 118 if (lfd == -1) { 119 syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); 120 goto tryagain; 121 } 122 123 nfd = socket(AF_INET, SOCK_DGRAM, 0); 124 if (nfd == -1) { 125 syslog(LOG_ERR, "Socket :%m"); 126 goto tryagain; 127 } 128 129 n1 = 1; 130 setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1)); 131 132 if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { 133 syslog(LOG_ERR, "Bind: %m"); 134 goto tryagain; 135 } 136 137 syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr)); 138 139 inbuf = 0; 140 while (1) { 141 142 143 /* 144 * XXX currently we do not check the source address 145 * of a datagram, this can be a security risk 146 */ 147 n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf); 148 149 printf("header : %d bytes read (header = %d bytes)\n", 150 n1, (int) sizeof(*sh)); 151 152 if (n1 < 0) { 153 syslog(LOG_ERR, "Read error (header): %m"); 154 goto tryagain; 155 } 156 157 if (n1 == 0) { 158 /* XXX can this happen??? */ 159 syslog(LOG_ERR, 160 "Read error (header) : No data"); 161 sleep(1); 162 continue; 163 } 164 165 inbuf += n1; 166 167 moreinbuf: 168 if (inbuf < sizeof(*sh)) { 169 continue; /* need more data */ 170 } 171 172 sh = (synchdr_t *)buff; 173 len = ntohl(sh->sm_len); 174 magic = ntohl(sh->sm_magic); 175 176 if (magic != SYNHDRMAGIC) { 177 syslog(LOG_ERR, "Invalid header magic %x", 178 magic); 179 goto tryagain; 180 } 181 182 #define IPSYNC_DEBUG 183 #ifdef IPSYNC_DEBUG 184 printf("v:%d p:%d len:%d magic:%x", sh->sm_v, 185 sh->sm_p, len, magic); 186 187 if (sh->sm_cmd == SMC_CREATE) 188 printf(" cmd:CREATE"); 189 else if (sh->sm_cmd == SMC_UPDATE) 190 printf(" cmd:UPDATE"); 191 else 192 printf(" cmd:Unknown(%d)", sh->sm_cmd); 193 194 if (sh->sm_table == SMC_NAT) 195 printf(" table:NAT"); 196 else if (sh->sm_table == SMC_STATE) 197 printf(" table:STATE"); 198 else 199 printf(" table:Unknown(%d)", sh->sm_table); 200 201 printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); 202 #endif 203 204 if (inbuf < sizeof(*sh) + len) { 205 continue; /* need more data */ 206 goto tryagain; 207 } 208 209 #ifdef IPSYNC_DEBUG 210 if (sh->sm_cmd == SMC_CREATE) { 211 sl = (synclogent_t *)buff; 212 213 } else if (sh->sm_cmd == SMC_UPDATE) { 214 su = (syncupdent_t *)buff; 215 if (sh->sm_p == IPPROTO_TCP) { 216 printf(" TCP Update: age %lu state %d/%d\n", 217 su->sup_tcp.stu_age, 218 su->sup_tcp.stu_state[0], 219 su->sup_tcp.stu_state[1]); 220 } 221 } else { 222 printf("Unknown command\n"); 223 } 224 #endif 225 226 n2 = sizeof(*sh) + len; 227 n3 = write(lfd, buff, n2); 228 if (n3 <= 0) { 229 syslog(LOG_ERR, "%s: Write error: %m", 230 IPSYNC_NAME); 231 goto tryagain; 232 } 233 234 235 if (n3 != n2) { 236 syslog(LOG_ERR, "%s: Incomplete write (%d/%d)", 237 IPSYNC_NAME, n3, n2); 238 goto tryagain; 239 } 240 241 /* signal received? */ 242 if (terminate) 243 break; 244 245 /* move buffer to the front,we might need to make 246 * this more efficient, by using a rolling pointer 247 * over the buffer and only copying it, when 248 * we are reaching the end 249 */ 250 inbuf -= n2; 251 if (inbuf) { 252 bcopy(buff+n2, buff, inbuf); 253 printf("More data in buffer\n"); 254 goto moreinbuf; 255 } 256 } 257 258 if (terminate) 259 break; 260 tryagain: 261 sleep(1); 262 } 263 264 265 /* terminate */ 266 if (lfd != -1) 267 close(lfd); 268 if (nfd != -1) 269 close(nfd); 270 271 syslog(LOG_ERR, "signal %d received, exiting...", terminate); 272 273 exit(1); 274 } 275