/* version 2026-02-12 */ /* compilation: gcc -Wall -o remote remote.c */ #include #include #include #include #include #include #include #include #include #include #include int fullread(int fd, void *_buf, int count) { char *buf = _buf; int ret = 0; int l; while (count) { l = read(fd, buf, count); if (l <= 0) return -1; count -= l; buf += l; ret += l; } return ret; } int fullwrite(int fd, void *_buf, int count) { char *buf = _buf; int ret = 0; int l; while (count) { l = write(fd, buf, count); if (l <= 0) return -1; count -= l; buf += l; ret += l; } return ret; } typedef struct { int port; int sock; int dead; } link_t; #define MAX 256 link_t links[MAX]; int links_count; int main(int n, char **v) { if (n != 4) { printf("gimme \n"); exit(1); } signal(SIGCHLD, SIG_DFL); char *central_ip = v[1]; int central_port = atoi(v[2]); char *key = v[3]; /* connect to central */ /* s is socket to connect to central */ int s = socket(AF_INET, SOCK_STREAM, 0); if (s == -1) abort(); int vv = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &vv, sizeof(v)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } struct sockaddr_in a; a.sin_family = AF_INET; a.sin_port = htons(central_port); a.sin_addr.s_addr = inet_addr(central_ip); if (connect(s, (struct sockaddr *)&a, sizeof(a)) == -1) { perror("connect"); exit(1); } /* send key */ if (fullwrite(s, key, strlen(key)) != strlen(key)) abort(); while (1) { struct pollfd fds[1 + MAX]; fds[0].fd = s; fds[0].events = POLLIN; fds[0].revents = 0; for (int i = 0; i < links_count; i++) { fds[1 + i].fd = links[i].sock; fds[1 + i].events = POLLIN; fds[1 + i].revents = 0; } int fds_size = 1 + links_count; int r = poll(fds, fds_size, -1); if (r <= 0) continue; /* data from central? */ if (fds[0].revents & POLLIN) { char b[512]; int port, length; if (fullread(s, &port, sizeof(int)) != sizeof(int)) exit(1); if (fullread(s, &length, sizeof(int)) != sizeof(int)) exit(1); if (length > 512) { printf("too big length %d\n", length); exit(1); } /* new kid to create? */ if (length == 0) { /* maybe do something if no more free connection? should not happen, * the client program is also limited to MAX... */ if (links_count == MAX) { printf("too many connections\n"); continue; } int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) continue; int vv = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &vv, sizeof(vv)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } struct sockaddr_in a; a.sin_family = AF_INET; a.sin_port = htons(22); a.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sock, (struct sockaddr *)&a, sizeof(a)) == -1) { perror("connect"); exit(1); } links[links_count].port = port; links[links_count].sock = sock; links[links_count].dead = 0; links_count++; continue; } /* forward to client - ignore if none found */ if (length > 0) { if (fullread(s, b, length) != length) exit(1); } for (int i = 0; i < links_count; i++) { if (links[i].port != port) continue; if (links[i].dead) continue; if (length == -1) { /* length -1 means problem, prepare kid to die */ links[i].dead = 1; continue; } if (fullwrite(links[i].sock, b, length) != length) { /* problem with kid, prepare it to die */ links[i].dead = 1; } } } /* data from kids? */ for (int i = 1; i < fds_size; i++) { int link = i - 1; if (!(fds[i].revents & POLLIN)) continue; if (links[link].dead) continue; char b[512]; int r = read(links[link].sock, b, 512); if (r <= 0) { /* problem, prepare kid to die */ links[link].dead = 1; continue; } /* send to central */ if (fullwrite(s, &links[link].port, sizeof(int)) != sizeof(int)) exit(1); if (fullwrite(s, &r, sizeof(int)) != sizeof(int)) exit(1); if (fullwrite(s, b, r) != r) exit(1); } /* remove dead kids */ for (int i = 0; i < links_count; i++) { if (!links[i].dead) continue; /* dead - inform central (maybe more than once, no big deal) */ if (fullwrite(s, &links[i].port, sizeof(int)) != sizeof(int)) exit(1); int x = -1; if (fullwrite(s, &x, sizeof(int)) != sizeof(int)) exit(1); /* close and kill */ close(links[i].sock); memmove(&links[i], &links[i+1], sizeof(link_t) * (links_count - 1 - i)); links_count--; i--; } } return 0; } ; }