DF-3534 / tty_leak2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /* DF-3531 isolation: which part of the cycle leaks the node? * modes: nodd (ldisc on/off only) | nodata (connect, no data) * full (connect+data) | socksock (socket<->socket connect+data) */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #define AF_NG 32 #define NG_DATA 1 #define NG_CONTROL 2 #define NG_VERSION 8 #define NGM_GENERIC_COOKIE 1137070366 #define NGM_MKPEER 2 #define NGM_CONNECT 3 #define NGM_NAME 4 #define NGM_NODEINFO (6 | 0x10000000 | 0x20000000) #define NG_TYPESIZ 32 #define NG_HOOKSIZ 32 #define NG_NODESIZ 32 #define NG_PATHSIZ 512 #define NETGRAPHDISC_ 6 struct ngm_hdr_ { u_char version, spare; u_short spare2; u_int arglen, cmd, flags, token, typecookie; char cmdstr[32]; }; struct ng_mesg_ { struct ngm_hdr_ h; char data[1024]; }; struct ngm_connect_ { char path[NG_PATHSIZ]; char ourhook[NG_HOOKSIZ]; char peerhook[NG_HOOKSIZ]; }; struct nodeinfo_ { char name[NG_NODESIZ]; char type[NG_TYPESIZ]; u_int32_t id, hooks; }; struct sockaddr_ng_ { u_char sg_len; sa_family_t sg_family; char sg_data[64]; }; #define NGIOCGINFO_ _IOR('N', 40, struct nodeinfo_) static u_int32_t tok = 0x7000; static int ngm(int cs, const char *path, u_int cmd, const void *arg, size_t al, struct ng_mesg_ *reply) { struct ng_mesg_ m; struct sockaddr_ng_ sa; ssize_t n; memset(&m, 0, sizeof(m)); m.h.version = NG_VERSION; m.h.arglen = al; m.h.cmd = cmd; m.h.token = ++tok; m.h.typecookie = NGM_GENERIC_COOKIE; if (al) memcpy(m.data, arg, al); memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; snprintf(sa.sg_data, sizeof(sa.sg_data), "%s", path); sa.sg_len = 2 + strlen(sa.sg_data) + 1; n = sendto(cs, &m, sizeof(m.h) + al, 0, (struct sockaddr *)&sa, sa.sg_len); if (n < 0) return (-1); if (reply) { u_int32_t mt = m.h.token; int t; for (t = 0; t < 32; t++) { n = recv(cs, reply, sizeof(*reply), 0); if (n < 0) return (-1); if (reply->h.token != mt) continue; if (reply->h.flags & 1) { if (reply->h.arglen == 4) return (-((int)*(u_int32_t *)reply->data ? (int)*(u_int32_t *)reply->data : EIO)); return (0); } } return (-1); } return (0); } static int myid(int cs, u_int32_t *id) { static struct ng_mesg_ r; if (ngm(cs, ".", NGM_NODEINFO, NULL, 0, &r) < 0) return (-1); *id = ((struct nodeinfo_ *)r.data)->id; return (0); } static int cycle_tty(int doconnect, int senddata) { int master, slave, cs, ds, disc = NETGRAPHDISC_, zero = 0; struct nodeinfo_ ni; struct ngm_connect_ con; struct sockaddr_ng_ sa; static char buf[1500]; if ((master = posix_openpt(O_RDWR | O_NOCTTY)) < 0) return -1; fcntl(master, F_SETFL, O_NONBLOCK); if (grantpt(master) || unlockpt(master)) return -1; if ((slave = open(ptsname(master), O_RDWR | O_NOCTTY)) < 0) return -1; if (ioctl(slave, TIOCSETD, &disc) < 0) { perror("TIOCSETD"); return -1; } memset(&ni, 0, sizeof(ni)); if (ioctl(slave, NGIOCGINFO_, &ni) < 0) { perror("NGIOCGINFO"); return -1; } if (doconnect) { cs = socket(AF_NG, SOCK_DGRAM, NG_CONTROL); ds = socket(AF_NG, SOCK_DGRAM, NG_DATA); if (cs < 0 || ds < 0) return -1; memset(&con, 0, sizeof(con)); snprintf(con.path, sizeof(con.path), "%s:", ni.name); strcpy(con.ourhook, "d"); strcpy(con.peerhook, "hook"); if (ngm(cs, ".", NGM_CONNECT, &con, sizeof(con), NULL) < 0) { fprintf(stderr, "connect %s: %s\n", con.path, strerror(errno)); return -1; } u_int32_t id; if (myid(cs, &id) < 0) return -1; memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; snprintf(sa.sg_data, sizeof(sa.sg_data), "[%x]:", id); sa.sg_len = 2 + strlen(sa.sg_data) + 1; if (connect(ds, (struct sockaddr *)&sa, sa.sg_len) < 0) return -1; if (senddata) { memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; strcpy(sa.sg_data, "d"); sa.sg_len = 2 + strlen(sa.sg_data) + 1; if (sendto(ds, buf, sizeof(buf), 0, (struct sockaddr *)&sa, sa.sg_len) != (ssize_t)sizeof(buf)) return -1; } usleep(20000); close(ds); close(cs); } close(master); if (ioctl(slave, TIOCSETD, &zero) < 0) { perror("TIOCSETD0"); return -1; } close(slave); return 0; } static int cycle_socksock(void) { int csA, csB, ds; struct ngm_connect_ con; struct sockaddr_ng_ sa; static char buf[1500]; u_int32_t id; csA = socket(AF_NG, SOCK_DGRAM, NG_CONTROL); csB = socket(AF_NG, SOCK_DGRAM, NG_CONTROL); ds = socket(AF_NG, SOCK_DGRAM, NG_DATA); if (csA < 0 || csB < 0 || ds < 0) return -1; if (myid(csA, &id) < 0) return -1; memset(&con, 0, sizeof(con)); snprintf(con.path, sizeof(con.path), "[%x]:", id); strcpy(con.ourhook, "x"); strcpy(con.peerhook, "y"); if (ngm(csB, ".", NGM_CONNECT, &con, sizeof(con), NULL) < 0) { fprintf(stderr, "socksock connect: %s\n", strerror(errno)); return -1; } if (myid(csB, &id) < 0) return -1; memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; snprintf(sa.sg_data, sizeof(sa.sg_data), "[%x]:", id); sa.sg_len = 2 + strlen(sa.sg_data) + 1; if (connect(ds, (struct sockaddr *)&sa, sa.sg_len) < 0) return -1; memset(&sa, 0, sizeof(sa)); sa.sg_family = AF_NG; strcpy(sa.sg_data, "x"); sa.sg_len = 2 + strlen(sa.sg_data) + 1; if (sendto(ds, buf, sizeof(buf), 0, (struct sockaddr *)&sa, sa.sg_len) != (ssize_t)sizeof(buf)) return -1; usleep(20000); close(ds); close(csA); close(csB); return 0; } int main(int argc, char **argv) { const char *mode = argc > 1 ? argv[1] : "full"; int rounds = argc > 2 ? atoi(argv[2]) : 500, i; for (i = 0; i < rounds; i++) { if (!strcmp(mode, "nodd")) { if (cycle_tty(0, 0) < 0) exit(1); } else if (!strcmp(mode, "nodata")) { if (cycle_tty(1, 0) < 0) exit(1); } else if (!strcmp(mode, "full")) { if (cycle_tty(1, 1) < 0) exit(1); } else if (!strcmp(mode, "socksock")) { if (cycle_socksock() < 0) exit(1); } if (i % 200 == 199) { printf("... %d\n", i + 1); fflush(stdout); } } printf("done %s %d\n", mode, rounds); return 0; } |