1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr */ 8145510Sdarrenr#if !defined(lint) 9145510Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10255332Scystatic const char rcsid[] = "@(#)$Id$"; 11145510Sdarrenr#endif 12145510Sdarrenr#include <sys/types.h> 13145510Sdarrenr#include <sys/time.h> 14145510Sdarrenr#include <sys/socket.h> 15145510Sdarrenr 16145510Sdarrenr#include <netinet/in.h> 17145510Sdarrenr#include <net/if.h> 18145510Sdarrenr 19145510Sdarrenr#include <arpa/inet.h> 20145510Sdarrenr 21145510Sdarrenr#include <stdio.h> 22145510Sdarrenr#include <stdlib.h> 23145510Sdarrenr#include <fcntl.h> 24161357Sguido#include <string.h> 25145510Sdarrenr#include <unistd.h> 26145510Sdarrenr#include <syslog.h> 27145510Sdarrenr#include <errno.h> 28145510Sdarrenr#include <signal.h> 29145510Sdarrenr 30145510Sdarrenr#include "netinet/ip_compat.h" 31145510Sdarrenr#include "netinet/ip_fil.h" 32145510Sdarrenr#include "netinet/ip_state.h" 33145510Sdarrenr#include "netinet/ip_nat.h" 34145510Sdarrenr#include "netinet/ip_sync.h" 35145510Sdarrenr 36145510Sdarrenrint main __P((int, char *[])); 37161357Sguidovoid usage __P((const char *progname)); 38145510Sdarrenr 39145510Sdarrenrint terminate = 0; 40145510Sdarrenr 41145510Sdarrenrvoid usage(const char *progname) { 42145510Sdarrenr fprintf(stderr, 43145510Sdarrenr "Usage: %s <destination IP> <destination port> [remote IP]\n", 44145510Sdarrenr progname); 45145510Sdarrenr} 46145510Sdarrenr 47161357Sguido#if 0 48145510Sdarrenrstatic void handleterm(int sig) 49145510Sdarrenr{ 50145510Sdarrenr terminate = sig; 51145510Sdarrenr} 52161357Sguido#endif 53145510Sdarrenr 54145510Sdarrenr#define BUFFERLEN 1400 55145510Sdarrenr 56145510Sdarrenrint main(argc, argv) 57255332Scy int argc; 58255332Scy char *argv[]; 59145510Sdarrenr{ 60255332Scy int nfd = -1 , lfd = -1; 61145510Sdarrenr int n1, n2, n3, magic, len, inbuf; 62145510Sdarrenr struct sockaddr_in sin; 63145510Sdarrenr struct sockaddr_in in; 64145510Sdarrenr char buff[BUFFERLEN]; 65145510Sdarrenr synclogent_t *sl; 66145510Sdarrenr syncupdent_t *su; 67145510Sdarrenr synchdr_t *sh; 68145510Sdarrenr char *progname; 69255332Scy 70145510Sdarrenr progname = strrchr(argv[0], '/'); 71145510Sdarrenr if (progname) { 72145510Sdarrenr progname++; 73145510Sdarrenr } else { 74145510Sdarrenr progname = argv[0]; 75145510Sdarrenr } 76255332Scy 77145510Sdarrenr if (argc < 2) { 78145510Sdarrenr usage(progname); 79145510Sdarrenr exit(1); 80145510Sdarrenr } 81145510Sdarrenr 82145510Sdarrenr#if 0 83145510Sdarrenr signal(SIGHUP, handleterm); 84145510Sdarrenr signal(SIGINT, handleterm); 85145510Sdarrenr signal(SIGTERM, handleterm); 86145510Sdarrenr#endif 87145510Sdarrenr 88145510Sdarrenr openlog(progname, LOG_PID, LOG_SECURITY); 89255332Scy 90145510Sdarrenr lfd = open(IPSYNC_NAME, O_WRONLY); 91145510Sdarrenr if (lfd == -1) { 92145510Sdarrenr syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); 93145510Sdarrenr exit(1); 94145510Sdarrenr } 95145510Sdarrenr 96145510Sdarrenr bzero((char *)&sin, sizeof(sin)); 97145510Sdarrenr sin.sin_family = AF_INET; 98145510Sdarrenr if (argc > 1) 99145510Sdarrenr sin.sin_addr.s_addr = inet_addr(argv[1]); 100145510Sdarrenr if (argc > 2) 101145510Sdarrenr sin.sin_port = htons(atoi(argv[2])); 102145510Sdarrenr else 103145510Sdarrenr sin.sin_port = htons(43434); 104255332Scy if (argc > 3) 105145510Sdarrenr in.sin_addr.s_addr = inet_addr(argv[3]); 106145510Sdarrenr else 107145510Sdarrenr in.sin_addr.s_addr = 0; 108145510Sdarrenr in.sin_port = 0; 109145510Sdarrenr 110145510Sdarrenr while(1) { 111255332Scy 112145510Sdarrenr if (lfd != -1) 113145510Sdarrenr close(lfd); 114145510Sdarrenr if (nfd != -1) 115145510Sdarrenr close(nfd); 116145510Sdarrenr 117145510Sdarrenr lfd = open(IPSYNC_NAME, O_WRONLY); 118145510Sdarrenr if (lfd == -1) { 119145510Sdarrenr syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); 120145510Sdarrenr goto tryagain; 121145510Sdarrenr } 122255332Scy 123145510Sdarrenr nfd = socket(AF_INET, SOCK_DGRAM, 0); 124145510Sdarrenr if (nfd == -1) { 125145510Sdarrenr syslog(LOG_ERR, "Socket :%m"); 126145510Sdarrenr goto tryagain; 127145510Sdarrenr } 128145510Sdarrenr 129145510Sdarrenr n1 = 1; 130145510Sdarrenr setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1)); 131145510Sdarrenr 132145510Sdarrenr if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { 133145510Sdarrenr syslog(LOG_ERR, "Bind: %m"); 134145510Sdarrenr goto tryagain; 135145510Sdarrenr } 136145510Sdarrenr 137161357Sguido syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr)); 138255332Scy 139255332Scy inbuf = 0; 140145510Sdarrenr while (1) { 141145510Sdarrenr 142145510Sdarrenr 143255332Scy /* 144145510Sdarrenr * XXX currently we do not check the source address 145145510Sdarrenr * of a datagram, this can be a security risk 146145510Sdarrenr */ 147145510Sdarrenr n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf); 148255332Scy 149145510Sdarrenr printf("header : %d bytes read (header = %d bytes)\n", 150255332Scy n1, (int) sizeof(*sh)); 151255332Scy 152145510Sdarrenr if (n1 < 0) { 153145510Sdarrenr syslog(LOG_ERR, "Read error (header): %m"); 154145510Sdarrenr goto tryagain; 155145510Sdarrenr } 156145510Sdarrenr 157145510Sdarrenr if (n1 == 0) { 158145510Sdarrenr /* XXX can this happen??? */ 159145510Sdarrenr syslog(LOG_ERR, 160145510Sdarrenr "Read error (header) : No data"); 161145510Sdarrenr sleep(1); 162145510Sdarrenr continue; 163145510Sdarrenr } 164145510Sdarrenr 165255332Scy inbuf += n1; 166255332Scy 167145510Sdarrenrmoreinbuf: 168145510Sdarrenr if (inbuf < sizeof(*sh)) { 169145510Sdarrenr continue; /* need more data */ 170145510Sdarrenr } 171145510Sdarrenr 172145510Sdarrenr sh = (synchdr_t *)buff; 173145510Sdarrenr len = ntohl(sh->sm_len); 174255332Scy magic = ntohl(sh->sm_magic); 175145510Sdarrenr 176145510Sdarrenr if (magic != SYNHDRMAGIC) { 177145510Sdarrenr syslog(LOG_ERR, "Invalid header magic %x", 178145510Sdarrenr magic); 179145510Sdarrenr goto tryagain; 180145510Sdarrenr } 181145510Sdarrenr 182145510Sdarrenr#define IPSYNC_DEBUG 183145510Sdarrenr#ifdef IPSYNC_DEBUG 184145510Sdarrenr printf("v:%d p:%d len:%d magic:%x", sh->sm_v, 185145510Sdarrenr sh->sm_p, len, magic); 186145510Sdarrenr 187145510Sdarrenr if (sh->sm_cmd == SMC_CREATE) 188145510Sdarrenr printf(" cmd:CREATE"); 189145510Sdarrenr else if (sh->sm_cmd == SMC_UPDATE) 190145510Sdarrenr printf(" cmd:UPDATE"); 191145510Sdarrenr else 192145510Sdarrenr printf(" cmd:Unknown(%d)", sh->sm_cmd); 193145510Sdarrenr 194145510Sdarrenr if (sh->sm_table == SMC_NAT) 195145510Sdarrenr printf(" table:NAT"); 196145510Sdarrenr else if (sh->sm_table == SMC_STATE) 197145510Sdarrenr printf(" table:STATE"); 198145510Sdarrenr else 199145510Sdarrenr printf(" table:Unknown(%d)", sh->sm_table); 200145510Sdarrenr 201145510Sdarrenr printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); 202255332Scy#endif 203255332Scy 204145510Sdarrenr if (inbuf < sizeof(*sh) + len) { 205145510Sdarrenr continue; /* need more data */ 206145510Sdarrenr goto tryagain; 207145510Sdarrenr } 208145510Sdarrenr 209145510Sdarrenr#ifdef IPSYNC_DEBUG 210145510Sdarrenr if (sh->sm_cmd == SMC_CREATE) { 211145510Sdarrenr sl = (synclogent_t *)buff; 212145510Sdarrenr 213145510Sdarrenr } else if (sh->sm_cmd == SMC_UPDATE) { 214145510Sdarrenr su = (syncupdent_t *)buff; 215145510Sdarrenr if (sh->sm_p == IPPROTO_TCP) { 216255332Scy printf(" TCP Update: age %lu state %d/%d\n", 217145510Sdarrenr su->sup_tcp.stu_age, 218255332Scy su->sup_tcp.stu_state[0], 219145510Sdarrenr su->sup_tcp.stu_state[1]); 220145510Sdarrenr } 221145510Sdarrenr } else { 222145510Sdarrenr printf("Unknown command\n"); 223145510Sdarrenr } 224145510Sdarrenr#endif 225145510Sdarrenr 226145510Sdarrenr n2 = sizeof(*sh) + len; 227145510Sdarrenr n3 = write(lfd, buff, n2); 228145510Sdarrenr if (n3 <= 0) { 229161357Sguido syslog(LOG_ERR, "%s: Write error: %m", 230161357Sguido IPSYNC_NAME); 231145510Sdarrenr goto tryagain; 232145510Sdarrenr } 233145510Sdarrenr 234255332Scy 235145510Sdarrenr if (n3 != n2) { 236161357Sguido syslog(LOG_ERR, "%s: Incomplete write (%d/%d)", 237161357Sguido IPSYNC_NAME, n3, n2); 238145510Sdarrenr goto tryagain; 239145510Sdarrenr } 240145510Sdarrenr 241145510Sdarrenr /* signal received? */ 242145510Sdarrenr if (terminate) 243145510Sdarrenr break; 244145510Sdarrenr 245145510Sdarrenr /* move buffer to the front,we might need to make 246145510Sdarrenr * this more efficient, by using a rolling pointer 247145510Sdarrenr * over the buffer and only copying it, when 248255332Scy * we are reaching the end 249145510Sdarrenr */ 250145510Sdarrenr inbuf -= n2; 251145510Sdarrenr if (inbuf) { 252145510Sdarrenr bcopy(buff+n2, buff, inbuf); 253145510Sdarrenr printf("More data in buffer\n"); 254145510Sdarrenr goto moreinbuf; 255145510Sdarrenr } 256145510Sdarrenr } 257145510Sdarrenr 258145510Sdarrenr if (terminate) 259145510Sdarrenr break; 260145510Sdarrenrtryagain: 261145510Sdarrenr sleep(1); 262145510Sdarrenr } 263145510Sdarrenr 264145510Sdarrenr 265145510Sdarrenr /* terminate */ 266145510Sdarrenr if (lfd != -1) 267145510Sdarrenr close(lfd); 268145510Sdarrenr if (nfd != -1) 269145510Sdarrenr close(nfd); 270145510Sdarrenr 271145510Sdarrenr syslog(LOG_ERR, "signal %d received, exiting...", terminate); 272145510Sdarrenr 273145510Sdarrenr exit(1); 274145510Sdarrenr} 275