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