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