#ifdef USE_L2TP #include "l2tpd.h" #include "l2tp_tunnel.h" l2tp_replication_t::l2tp_replication_t(void) { repl_listen_fd = -1; repl_fd = -1; replication_error = 0; replicate_peer = 0; } void l2tp_replication_t::SelectEvent(int fd, SelectEventType event) { if (fd == repl_fd) { if (event & SEL_READ) { unsigned char buf[2048]; int bytes = read(fd, buf, sizeof(buf)); if (bytes > 0) write(repl_fd, buf, bytes); if (bytes == -1 && errno != EAGAIN) { perror("read(repl_fd)"); goto close_it; } if (bytes == 0) { close_it: fprintf(stderr, "replication socket(%d) closing\n", repl_fd); SelectSetEvents(repl_fd, SEL_NONE); close(repl_fd); repl_fd = -1; } } return; } struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; socklen_t len = sizeof(sin); int new_fd = accept(fd, (struct sockaddr *)&sin, &len); if (-1 == new_fd) { perror("l2tp_replication_t::SelectEvent accept"); return; } if (sin.sin_addr.s_addr != replicate_peer) { fprintf(stderr, "accept(repl_listen_fd): peer %s not accepted\n", iptostr(ntohl(sin.sin_addr.s_addr))); close(new_fd); return; } if (-1 != repl_fd) { fprintf(stderr, "accept(repl_listen_fd): already have replication socket\n"); close(new_fd); return; } fprintf(stderr, "replication socket(%d) open from peer %s\n", new_fd, iptostr(ntohl(sin.sin_addr.s_addr))); repl_fd = new_fd; SelectSetEvents(repl_fd, SEL_READ); } int l2tpd_t::setup_replication(ctrlfd_t *cfd, u32 replicate) { replicate_peer = replicate; repl_listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (repl_listen_fd < 0) { cfd->perror("l2tpd_t::setup_replication: socket(STREAM, TCP)"); cfd->done(-2); return -2; } int one = 1; if (setsockopt(repl_listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { cfd->perror("l2tpd_t:setsockopt(repl_listen_fd, SO_REUSEADDR)"); cfd->done(-2); return -2; } struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(33000); if (bind(repl_listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { cfd->perror("l2tpd_t::setup_replication bind(repl_listen_fd)"); cfd->done(-2); return -2; } if (listen(repl_listen_fd, 1)) { cfd->perror("l2tpd_t::setup_replication listen"); cfd->done(-2); return -2; } make_nonblock(repl_listen_fd); l2tp_replication_t *repl = this; repl->SelectSetEvents(repl_listen_fd, SEL_READ); return 0; } void l2tp_replication_t::replicate_packet(char *buf, int len, union sockaddr_union *sau, int sin_len) { char tmp[4096]; struct replication_packet *pkt = (struct replication_packet *)tmp; /* FIXME */ pkt->len = len; pkt->port = sau->sin.sin_port; pkt->addr = sau->sin.sin_addr.s_addr; memcpy(pkt->buf, buf, len); if (write(repl_fd, pkt, sizeof(pkt) + len) < 0) { perror("replicate_packet:write"); // FIXME replication_error = 1; } } #endif /* USE_L2TP */