00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "libnuclient.h"
00024 #include "proto.h"
00025 #include "tcptable.h"
00026 #include <inttypes.h>
00027 #define USE_JHASH3
00028 #include <jhash.h>
00029 #ifdef FREEBSD
00030
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033 #include <sys/socketvar.h>
00034 #include <sys/param.h>
00035 #include <sys/queue.h>
00036 #include <sys/sysctl.h>
00037 #include <sys/protosw.h>
00038
00039 #include <netinet/tcp_fsm.h>
00040 #include <netinet/in_pcb.h>
00041 #include <netinet/tcp_var.h>
00042
00043 #endif
00044
00045 #include <nubase.h>
00046
00059 #ifdef LINUX
00060
00066 int parse_tcptable_file(nuauth_session_t * session, conntable_t * ct, char *filename,
00067 FILE ** file, int protocol, int use_ipv6)
00068 {
00069 char buf[1024];
00070 conn_t c;
00071 const char state_char = '2';
00072 int state_pos;
00073 int uid_pos;
00074 char session_uid[20];
00075 int session_uid_len;
00076 int ret;
00077 char *pos;
00078
00079
00080 if (*file == NULL) {
00081 *file = fopen(filename, "r");
00082 if (*file == NULL) {
00083 printf("Fail to open %s: %s", filename,
00084 strerror(errno));
00085 return 0;
00086 }
00087 }
00088
00089
00090 rewind(*file);
00091
00092
00093 if (fgets(buf, sizeof(buf), *file) == NULL)
00094 panic("%s: missing header!", filename);
00095
00096
00097 secure_snprintf(session_uid, sizeof(session_uid), "%5lu",
00098 (long)session->userid);
00099 session_uid_len = strlen(session_uid);
00100
00101
00102 pos = strstr(buf, " st ");
00103 if (pos == NULL)
00104 panic
00105 ("Can't find position of state field in /proc/net/tcp header!");
00106 state_pos = pos - buf + 2;
00107
00108
00109 pos = strstr(buf, " retrnsmt ");
00110 if (pos == NULL)
00111 panic
00112 ("Can't find position of user identifier field in /proc/net/tcp header!");
00113 uid_pos = pos - buf + strlen(" retrnsmt ");
00114
00115 while (fgets(buf, sizeof(buf), *file) != NULL) {
00116 #ifdef USE_FILTER
00117 int seen = 0;
00118 #endif
00119
00120
00121 if (buf[state_pos] != state_char) {
00122 continue;
00123 }
00124
00125
00126 if (strncmp(buf + uid_pos, session_uid, session_uid_len) !=
00127 0) {
00128 continue;
00129 }
00130
00131
00132 if (!use_ipv6) {
00133 uint32_t src, dst;
00134 ret = sscanf(buf,
00135 "%*d: "
00136 "%" SCNx32 ":%hx "
00137 "%" SCNx32 ":%hx "
00138 "%*x %*x:%*x %*x:%*x %x "
00139 "%lu %*d %lu",
00140 &src, &c.port_src,
00141 &dst, &c.port_dst,
00142 &c.retransmit, &c.uid,
00143 &c.inode);
00144 if (ret != 7) {
00145 continue;
00146 }
00147 uint32_to_ipv6(src, &c.ip_src);
00148 uint32_to_ipv6(dst, &c.ip_dst);
00149 } else {
00150 char ip_src[33];
00151 char ip_dst[33];
00152 ret = sscanf(buf,
00153 "%*d: "
00154 "%32s"
00155 ":%hx "
00156 "%32s"
00157 ":%hx "
00158 "%*x %*x:%*x %*x:%*x %x "
00159 "%lu %*d %lu",
00160 ip_src,
00161 &c.port_src,
00162 ip_dst,
00163 &c.port_dst,
00164 &c.retransmit, &c.uid, &c.inode);
00165 if (ret != 7) {
00166 continue;
00167 }
00168 if (!hex2ipv6(ip_src, &c.ip_src))
00169 continue;
00170 if (!hex2ipv6(ip_dst, &c.ip_dst))
00171 continue;
00172 }
00173
00174
00175 if (c.inode == 0) {
00176 continue;
00177 }
00178 #if DEBUG
00179
00180 printf("Packet dst = %ld (%lx)\n", c.rmt, c.rmt);
00181 #endif
00182
00183 #ifdef USE_FILTER
00184
00185
00186 if (session->auth_by_default && seen)
00187 continue;
00188 if (!session->auth_by_default && !seen)
00189 continue;
00190 #endif
00191 c.protocol = protocol;
00192 tcptable_add(ct, &c);
00193 }
00194 return 1;
00195 }
00196 #endif
00197
00205 int tcptable_read(nuauth_session_t * session, conntable_t * ct)
00206 {
00207 #ifdef LINUX
00208 static FILE *fd_tcp = NULL;
00209 static FILE *fd_tcp6 = NULL;
00210 static FILE *fd_udp = NULL;
00211
00212 #if DEBUG
00213 assert(ct != NULL);
00214 assert(TCP_SYN_SENT == 2);
00215 #endif
00216
00217 if (!parse_tcptable_file
00218 (session, ct, "/proc/net/tcp", &fd_tcp, IPPROTO_TCP, 0))
00219 return 0;
00220
00221 parse_tcptable_file(session, ct, "/proc/net/tcp6", &fd_tcp6,
00222 IPPROTO_TCP, 1);
00223
00224 if (!parse_tcptable_file
00225 (session, ct, "/proc/net/udp", &fd_udp, IPPROTO_UDP, 0))
00226 return 0;
00227 return 1;
00228 #elif defined(FREEBSD)
00229 conn_t c;
00230 int istcp;
00231 char *buf;
00232 const char *mibvar;
00233 struct tcpcb *tp = NULL;
00234 struct inpcb *inp;
00235 struct xinpgen *xig, *oxig;
00236 struct xsocket *so;
00237 size_t len;
00238 int proto = IPPROTO_TCP;
00239 #if 0
00240 istcp = 0;
00241 switch (proto) {
00242 case IPPROTO_TCP:
00243 #endif
00244 istcp = 1;
00245 mibvar = "net.inet.tcp.pcblist";
00246 #if 0
00247 break;
00248 case IPPROTO_UDP:
00249 mibvar = "net.inet.udp.pcblist";
00250 break;
00251 }
00252 #endif
00253
00254 len = 0;
00255 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
00256 if (errno != ENOENT)
00257 printf("sysctl: %s", mibvar);
00258 return 0;
00259 }
00260 buf = malloc(len);
00261 if (buf == NULL) {
00262 printf("malloc %lu bytes", (u_long) len);
00263 return 0;
00264 }
00265
00266
00267 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
00268 printf("sysctl: %s", mibvar);
00269 free(buf);
00270 return 0;
00271 }
00272
00273 oxig = xig = (struct xinpgen *) buf;
00274 for (xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
00275 xig->xig_len > sizeof(struct xinpgen);
00276 xig = (struct xinpgen *) ((char *) xig + xig->xig_len)) {
00277 if (istcp) {
00278 tp = &((struct xtcpcb *) xig)->xt_tp;
00279 inp = &((struct xtcpcb *) xig)->xt_inp;
00280 so = &((struct xtcpcb *) xig)->xt_socket;
00281 } else {
00282 inp = &((struct xinpcb *) xig)->xi_inp;
00283 so = &((struct xinpcb *) xig)->xi_socket;
00284 }
00285
00286
00287 if (so->xso_protocol != (int) proto)
00288 continue;
00289
00290
00291 if (inp->inp_gencnt > oxig->xig_gen)
00292 continue;
00293
00294
00295 if ((inp->inp_vflag & INP_IPV4) == 0)
00296 continue;
00297
00298
00299 if ((istcp && tp->t_state != TCPS_SYN_SENT)
00300 || (inet_lnaof(inp->inp_laddr) == INADDR_ANY))
00301 continue;
00302
00303 uint32_to_ipv6(inp->inp_laddr.s_addr, &c.ip_src);
00304 c.port_src = ntohs(inp->inp_lport);
00305
00306 uint32_to_ipv6(inp->inp_faddr.s_addr, &c.ip_dst);
00307 c.port_dst = ntohs(inp->inp_fport);
00308 c.protocol = IPPROTO_TCP;
00309
00310 tcptable_add(ct, &c);
00311 }
00312 free(buf);
00313 return 1;
00314 #endif
00315 }
00316
00323 int tcptable_init(conntable_t ** ct)
00324 {
00325 int i;
00326
00327 (*ct) = (conntable_t *) calloc(1, sizeof(conntable_t));
00328 if (*ct == NULL) {
00329 return 0;
00330 }
00331
00332 for (i = 0; i < CONNTABLE_BUCKETS; i++) {
00333 (*ct)->buckets[i] = NULL;
00334 }
00335 return 1;
00336 }
00337
00342 int tcptable_hash(conn_t * c)
00343 {
00344
00345 #ifndef FREEBSD
00346 return (jhash_3words(c->ip_src.s6_addr32[3],
00347 c->ip_dst.s6_addr32[3],
00348 (c->port_dst | c->port_src << 16),
00349 32)) % CONNTABLE_BUCKETS;
00350 #else
00351 return (jhash_3words(c->ip_src.__u6_addr.__u6_addr32[3],
00352 c->ip_dst.__u6_addr.__u6_addr32[3],
00353 (c->port_dst | c->port_src << 16),
00354 32)) % CONNTABLE_BUCKETS;
00355 #endif
00356 }
00357
00361 void tcptable_add(conntable_t * ct, conn_t * c)
00362 {
00363 conn_t *old, *newc;
00364 int bi;
00365 #if DEBUG
00366 assert(ct != NULL);
00367 assert(c != NULL);
00368 #endif
00369
00370 newc = (conn_t *) calloc(1, sizeof(conn_t));
00371 if (!newc) {
00372 panic("memory exhausted");
00373 }
00374
00375 c->createtime = time(NULL);
00376 memcpy(newc, c, sizeof(conn_t));
00377 bi = tcptable_hash(c);
00378 old = ct->buckets[bi];
00379 ct->buckets[bi] = newc;
00380 ct->buckets[bi]->next = old;
00381 }
00382
00388 conn_t *tcptable_find(conntable_t * ct, conn_t * c)
00389 {
00390 conn_t *bucket;
00391 #if DEBUG
00392 assert(ct != NULL);
00393 assert(c != NULL);
00394 #endif
00395 bucket = ct->buckets[tcptable_hash(c)];
00396 while (bucket != NULL) {
00397 if ((c->protocol == bucket->protocol)
00398 && ipv6_equal(&c->ip_dst, &bucket->ip_dst)
00399 && (c->port_dst == bucket->port_dst)
00400 && ipv6_equal(&c->ip_src, &bucket->ip_src)
00401 && (c->port_src == bucket->port_src)
00402 ) {
00403 return bucket;
00404 }
00405 bucket = bucket->next;
00406 }
00407
00408 return NULL;
00409 }
00410
00414 void tcptable_free(conntable_t * ct)
00415 {
00416 int i;
00417
00418 if (ct == NULL)
00419 return;
00420
00421 for (i = 0; i < CONNTABLE_BUCKETS; i++) {
00422 conn_t *c0, *c1;
00423
00424 c0 = ct->buckets[i];
00425 while (c0 != NULL) {
00426 c1 = c0->next;
00427 free(c0);
00428 c0 = c1;
00429 }
00430 ct->buckets[i] = NULL;
00431 }
00432
00433
00434 free(ct);
00435 }
00436