DF-3545 / sampledemo.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 169 170 171 172 173 174 175 176 177 178 179 | /* * DF-3545 demo: ng7 ng_sample downstream_hook.dlci is never initialized * to -1 (constructor M_ZERO leaves it 0), so data received on the * "downstream" hook takes the DLCI branch (dlci != -1) and is reflected * back out the same hook (sys/netgraph7/ng_sample.c:339-350). The * decode branch (:351-376) is unreachable. * * Graph: control node C --(C.sd <-> sample:downstream)-- sample node S. * Write "PING" on the data socket via hook "sd"; if the bug is live the * frame comes straight back and is readable on the same socket, and * GET_STATUS shows packets_out (not packets_in) incremented. * * Uses the netgraph7 ng_mesg layout (arglen u32 @4, cmd @8, flags @12, * token @16, typecookie @20, cmdstr[32] @24, data @56). */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #ifndef AF_NETGRAPH #define AF_NETGRAPH 32 #endif #define NG_AF AF_NETGRAPH #define NG_PROTO_CONTROL 2 #define NG_PROTO_DATA 1 #define NG_VERSION 8 #define NG_GENERIC_COOKIE 1137070366u #define NGM_MKPEER 2 #define NGM_NAME 4 #define NGM_XXX_COOKIE 915491374u #define NGM_XXX_GET_STATUS 2 struct ng7_mesg { unsigned char version; unsigned char spare; unsigned short spare2; unsigned int arglen; unsigned int cmd; unsigned int flags; unsigned int token; unsigned int typecookie; unsigned char cmdstr[32]; char data[2048]; }; #define NG7_HDRSZ 56 struct sockaddr_ng_t { unsigned char sg_len; unsigned char sg_family; char sg_data[64]; }; struct ngm_mkpeer_t { char type[32]; char ourhook[32]; char peerhook[32]; }; struct ngm_name_t { char name[32]; }; static void mkaddr(struct sockaddr_ng_t *sa, const char *path) { size_t n = strlen(path) + 1; memset(sa, 0, sizeof(*sa)); sa->sg_len = 2 + n; sa->sg_family = NG_AF; memcpy(sa->sg_data, path, n); } static int send_ctrl(int cs, const char *path, unsigned int cookie, unsigned int cmd, const void *arg, size_t arglen) { struct sockaddr_ng_t sa; struct ng7_mesg msg; ssize_t n; memset(&msg, 0, sizeof(msg)); msg.version = NG_VERSION; msg.arglen = arglen; msg.typecookie = cookie; msg.cmd = cmd; msg.token = 0x666; if (arglen) memcpy(msg.data, arg, arglen); mkaddr(&sa, path); n = sendto(cs, &msg, NG7_HDRSZ + arglen, 0, (struct sockaddr *)&sa, sa.sg_len); return (n < 0) ? errno : 0; } int main(void) { struct ngm_name_t nm; struct ngm_mkpeer_t mk; struct sockaddr_ng_t sa; struct ng7_mesg msg; char namebuf[32], abspath[64], buf[256]; int cs, ds, i, n, e, got = 0; unsigned int pin = 0, pout = 0; snprintf(namebuf, sizeof(namebuf), "q%d", getpid()); snprintf(abspath, sizeof(abspath), "%s:", namebuf); cs = socket(NG_AF, SOCK_DGRAM, NG_PROTO_CONTROL); if (cs < 0) { perror("control socket"); exit(1); } ds = socket(NG_AF, SOCK_DGRAM, NG_PROTO_DATA); if (ds < 0) { perror("data socket"); exit(1); } memset(&nm, 0, sizeof(nm)); strcpy(nm.name, namebuf); e = send_ctrl(cs, ".", NG_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)); if (e) { fprintf(stderr, "NGM_NAME: %s\n", strerror(e)); exit(1); } usleep(300000); mkaddr(&sa, abspath); if (connect(ds, (struct sockaddr *)&sa, sa.sg_len) < 0) { perror("data connect"); exit(1); } memset(&mk, 0, sizeof(mk)); strcpy(mk.type, "sample"); strcpy(mk.ourhook, "sd"); strcpy(mk.peerhook, "downstream"); e = send_ctrl(cs, ".", NG_GENERIC_COOKIE, NGM_MKPEER, &mk, sizeof(mk)); if (e) { fprintf(stderr, "mkpeer: %s\n", strerror(e)); exit(1); } usleep(300000); /* push data into the sample node's downstream hook */ mkaddr(&sa, "sd"); strcpy(buf, "PING\n"); for (i = 0; i < 20; i++) { n = sendto(ds, buf, 5, 0, (struct sockaddr *)&sa, sa.sg_len); if (n >= 0) break; usleep(100000); } if (n < 0) { fprintf(stderr, "sendto failed: %s\n", strerror(errno)); exit(1); } /* see if the frame comes back */ memset(buf, 0, sizeof(buf)); for (i = 0; i < 40 && !got; i++) { n = recv(ds, buf, sizeof(buf) - 1, MSG_DONTWAIT); if (n > 0) got = 1; else usleep(100000); } /* query GET_STATUS (no args) addressed to the sample node */ memset(&msg, 0, sizeof(msg)); msg.version = NG_VERSION; msg.arglen = 0; msg.typecookie = NGM_XXX_COOKIE; msg.cmd = NGM_XXX_GET_STATUS; msg.token = 0x777; mkaddr(&sa, "sd"); sendto(cs, &msg, NG7_HDRSZ, 0, (struct sockaddr *)&sa, sa.sg_len); usleep(300000); n = recv(cs, &msg, sizeof(msg), MSG_DONTWAIT); if (n >= NG7_HDRSZ + 8) { memcpy(&pin, msg.data, 4); memcpy(&pout, msg.data + 4, 4); } if (got) printf("RESULT: REFLECTED - received %d bytes back: '%s'\n", n, buf); else printf("RESULT: no data reflected back (decode branch taken)\n"); printf("GET_STATUS: packets_in=%u packets_out=%u " "(expect in=0,out>=1 if misrouted as DLCI traffic)\n", pin, pout); return (got ? 0 : 2); } |