static void i_ipadm_create_ngz_route(int rtsock, char *link, uint8_t *buf, size_t buflen) { struct in6_addr defrouter; boolean_t isv6; struct in_addr gw4; uint8_t *cp; const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 }; if (rtsock == -1) return; for (cp = buf; cp < buf + buflen; cp += sizeof (defrouter)) { bcopy(cp, &defrouter, sizeof (defrouter)); if (IN6_IS_ADDR_UNSPECIFIED(&defrouter)) break; isv6 = !IN6_IS_ADDR_V4MAPPED(&defrouter); if (isv6) { i_ipadm_rtioctl6(rtsock, RTM_ADD, ipv6_all_zeros, defrouter, 0, link, RTF_GATEWAY); } else { IN6_V4MAPPED_TO_INADDR(&defrouter, &gw4); i_ipadm_rtioctl4(rtsock, RTM_ADD, INADDR_ANY, gw4.s_addr, 0, link, 0, RTF_GATEWAY); } } }
/* * This is a wrapper function for inet_ntop(). In case the af is AF_INET6 * and the address pointed by src is a IPv4-mapped IPv6 address, it returns * a printable IPv4 address, not an IPv4-mapped IPv6 address. In other cases it * behaves just like inet_ntop(). */ const char * inet_ntop_native(int af, const void *addr, char *dst, size_t size) { struct in_addr v4addr; if ((af == AF_INET6) && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) { IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr); return (inet_ntop(AF_INET, &v4addr, dst, size)); } else { return (inet_ntop(af, addr, dst, size)); } }
static int print_rh(const char *rh_name) { int herr; struct hostent *hp; in6_addr_t in6; char abuf[INET6_ADDRSTRLEN]; tsol_rhent_t rhent; if ((hp = getipnodebyname(rh_name, AF_INET6, AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &herr)) == NULL) { (void) fprintf(stderr, gettext("tninfo: unknown host or " "invalid literal address: %s\n"), rh_name); if (herr == TRY_AGAIN) (void) fprintf(stderr, gettext("\t(try again later)\n")); return (1); } (void) memset(&rhent, 0, sizeof (rhent)); (void) memcpy(&in6, hp->h_addr, hp->h_length); if (IN6_IS_ADDR_V4MAPPED(&in6)) { rhent.rh_address.ta_family = AF_INET; IN6_V4MAPPED_TO_INADDR(&in6, &rhent.rh_address.ta_addr_v4); (void) inet_ntop(AF_INET, &rhent.rh_address.ta_addr_v4, abuf, sizeof (abuf)); } else { rhent.rh_address.ta_family = AF_INET6; rhent.rh_address.ta_addr_v6 = in6; (void) inet_ntop(AF_INET6, &in6, abuf, sizeof (abuf)); } (void) printf(gettext("IP address= %s\n"), abuf); if (tnrh(TNDB_GET, &rhent) != 0) { if (errno == ENOENT) (void) fprintf(stderr, gettext("tninfo: tnrhdb entry " "%1$s does not exist\n"), abuf); else (void) fprintf(stderr, gettext("tninfo: TNDB_GET(%1$s) " "failed: %2$s\n"), abuf, strerror(errno)); return (1); } if (rhent.rh_template[0] != '\0') (void) printf(gettext("Template = %.*s\n"), TNTNAMSIZ, rhent.rh_template); else (void) printf(gettext("No template exists.\n")); return (0); }
/* * SCTP interface for geting the primary peer address of a sctp_t. */ static int sctp_getpeeraddr(sctp_t *sctp, struct sockaddr *addr) { struct sockaddr_in *sin4; struct sockaddr_in6 *sin6; sctp_faddr_t sctp_primary; in6_addr_t faddr; conn_t *connp = sctp->sctp_connp; if (sctp->sctp_faddrs == NULL) return (-1); addr->sa_family = connp->conn_family; if (mdb_vread(&sctp_primary, sizeof (sctp_faddr_t), (uintptr_t)sctp->sctp_primary) == -1) { mdb_warn("failed to read sctp primary faddr"); return (-1); } faddr = sctp_primary.sf_faddr; switch (connp->conn_family) { case AF_INET: /* LINTED: alignment */ sin4 = (struct sockaddr_in *)addr; IN6_V4MAPPED_TO_INADDR(&faddr, &sin4->sin_addr); sin4->sin_port = connp->conn_fport; sin4->sin_family = AF_INET; break; case AF_INET6: /* LINTED: alignment */ sin6 = (struct sockaddr_in6 *)addr; sin6->sin6_addr = faddr; sin6->sin6_port = connp->conn_fport; sin6->sin6_family = AF_INET6; sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; sin6->__sin6_src_id = 0; break; } return (0); }
/* * Taken from inetd.c * This is a wrapper function for inet_ntop(). In case the af is AF_INET6 * and the address pointed by src is a IPv4-mapped IPv6 address, it * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases * it behaves just like inet_ntop(). */ static const char * inet_ntop_native(int af, const void *src, char *dst, size_t size) { struct in_addr src4; const char *result; if (af == AF_INET6) { if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) { IN6_V4MAPPED_TO_INADDR((struct in6_addr *)src, &src4); result = inet_ntop(AF_INET, &src4, dst, size); } else { result = inet_ntop(AF_INET6, src, dst, size); } } else { result = inet_ntop(af, src, dst, size); } return (result); }
/* * Get the information for the channel structure. */ void get_inet_addr_info(struct sockaddr_in6 *in_ipaddr, gss_buffer_t in_buffer) { size_t length; char *value; if (in_ipaddr == NULL) { in_buffer->length = 0; in_buffer->value = NULL; return; } /* get the initiator address.value and address.length */ if (in_ipaddr->sin6_family == AF_INET6) { struct in_addr in_ipv4addr; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)in_ipaddr; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &in_ipv4addr); in_buffer->length = length = sizeof (struct in_addr); in_buffer->value = value = malloc(length); memcpy(value, &in_ipv4addr, length); } else { in_buffer->length = length = sizeof (struct in6_addr); in_buffer->value = value = malloc(length); memcpy(value, &(sin6->sin6_addr.s6_addr), length); } } else { in_buffer->length = length = sizeof (struct in_addr); in_buffer->value = value = malloc(in_buffer->length); memcpy(value, &((struct sockaddr_in *)(in_ipaddr))->sin_addr, length); } }
/* * SCTP interface for geting the first source address of a sctp_t. */ int sctp_getsockaddr(sctp_t *sctp, struct sockaddr *addr) { int err = -1; int i; int l; sctp_saddr_ipif_t *pobj; sctp_saddr_ipif_t obj; size_t added = 0; sin6_t *sin6; sin_t *sin4; int scanned = 0; boolean_t skip_lback = B_FALSE; conn_t *connp = sctp->sctp_connp; addr->sa_family = connp->conn_family; if (sctp->sctp_nsaddrs == 0) goto done; /* * Skip loopback addresses for non-loopback assoc. */ if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback) { skip_lback = B_TRUE; } for (i = 0; i < SCTP_IPIF_HASH; i++) { if (sctp->sctp_saddrs[i].ipif_count == 0) continue; pobj = list_object(&sctp->sctp_saddrs[i].sctp_ipif_list, sctp->sctp_saddrs[i].sctp_ipif_list.list_head.list_next); if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t), (uintptr_t)pobj) == -1) { mdb_warn("failed to read sctp_saddr_ipif_t"); return (err); } for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) { sctp_ipif_t ipif; in6_addr_t laddr; list_node_t *pnode; list_node_t node; if (mdb_vread(&ipif, sizeof (sctp_ipif_t), (uintptr_t)obj.saddr_ipifp) == -1) { mdb_warn("failed to read sctp_ipif_t"); return (err); } laddr = ipif.sctp_ipif_saddr; scanned++; if ((ipif.sctp_ipif_state == SCTP_IPIFS_CONDEMNED) || SCTP_DONT_SRC(&obj) || (ipif.sctp_ipif_ill->sctp_ill_flags & PHYI_LOOPBACK) && skip_lback) { if (scanned >= sctp->sctp_nsaddrs) goto done; /* LINTED: alignment */ pnode = list_d2l(&sctp->sctp_saddrs[i]. sctp_ipif_list, pobj); if (mdb_vread(&node, sizeof (list_node_t), (uintptr_t)pnode) == -1) { mdb_warn("failed to read list_node_t"); return (err); } pobj = list_object(&sctp->sctp_saddrs[i]. sctp_ipif_list, node.list_next); if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t), (uintptr_t)pobj) == -1) { mdb_warn("failed to read " "sctp_saddr_ipif_t"); return (err); } continue; } switch (connp->conn_family) { case AF_INET: /* LINTED: alignment */ sin4 = (sin_t *)addr; if ((sctp->sctp_state <= SCTPS_LISTEN) && sctp->sctp_bound_to_all) { sin4->sin_addr.s_addr = INADDR_ANY; sin4->sin_port = connp->conn_lport; } else { sin4 += added; sin4->sin_family = AF_INET; sin4->sin_port = connp->conn_lport; IN6_V4MAPPED_TO_INADDR(&laddr, &sin4->sin_addr); } break; case AF_INET6: /* LINTED: alignment */ sin6 = (sin6_t *)addr; if ((sctp->sctp_state <= SCTPS_LISTEN) && sctp->sctp_bound_to_all) { bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr)); sin6->sin6_port = connp->conn_lport; } else { sin6 += added; sin6->sin6_family = AF_INET6; sin6->sin6_port = connp->conn_lport; sin6->sin6_addr = laddr; } sin6->sin6_flowinfo = connp->conn_flowinfo; sin6->sin6_scope_id = 0; sin6->__sin6_src_id = 0; break; } added++; if (added >= 1) { err = 0; goto done; } if (scanned >= sctp->sctp_nsaddrs) goto done; /* LINTED: alignment */ pnode = list_d2l(&sctp->sctp_saddrs[i].sctp_ipif_list, pobj); if (mdb_vread(&node, sizeof (list_node_t), (uintptr_t)pnode) == -1) { mdb_warn("failed to read list_node_t"); return (err); } pobj = list_object(&sctp->sctp_saddrs[i]. sctp_ipif_list, node.list_next); if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t), (uintptr_t)pobj) == -1) { mdb_warn("failed to read sctp_saddr_ipif_t"); return (err); } } } done: return (err); }
static void doit(int f, struct sockaddr_storage *fromp, krb5_context krb_context, int encr_flag, krb5_keytab keytab) { int p, t, on = 1; char c; char abuf[INET6_ADDRSTRLEN]; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; int fromplen; in_port_t port; struct termios tp; boolean_t bad_port; boolean_t no_name; char rhost_addra[INET6_ADDRSTRLEN]; if (!(rlbuf = malloc(BUFSIZ))) { syslog(LOG_ERR, "rlbuf malloc failed\n"); exit(EXIT_FAILURE); } (void) alarm(60); if (read(f, &c, 1) != 1 || c != 0) { syslog(LOG_ERR, "failed to receive protocol zero byte\n"); exit(EXIT_FAILURE); } (void) alarm(0); if (fromp->ss_family == AF_INET) { sin = (struct sockaddr_in *)fromp; port = sin->sin_port = ntohs((ushort_t)sin->sin_port); fromplen = sizeof (struct sockaddr_in); if (!inet_ntop(AF_INET, &sin->sin_addr, rhost_addra, sizeof (rhost_addra))) goto badconversion; } else if (fromp->ss_family == AF_INET6) { sin6 = (struct sockaddr_in6 *)fromp; port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port); fromplen = sizeof (struct sockaddr_in6); if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct in_addr ipv4_addr; IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &ipv4_addr); if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra, sizeof (rhost_addra))) goto badconversion; } else { if (!inet_ntop(AF_INET6, &sin6->sin6_addr, rhost_addra, sizeof (rhost_addra))) goto badconversion; } } else { syslog(LOG_ERR, "unknown address family %d\n", fromp->ss_family); fatal(f, "Permission denied"); } /* * Allow connections only from the "ephemeral" reserved * ports(ports 512 - 1023) by checking the remote port * because other utilities(e.g. in.ftpd) can be used to * allow a unprivileged user to originate a connection * from a privileged port and provide untrustworthy * authentication. */ bad_port = (use_auth != KRB5_RECVAUTH_V5 && (port >= (in_port_t)IPPORT_RESERVED) || (port < (in_port_t)(IPPORT_RESERVED/2))); no_name = getnameinfo((const struct sockaddr *) fromp, fromplen, hostname, sizeof (hostname), NULL, 0, 0) != 0; if (no_name || bad_port) { (void) strlcpy(abuf, rhost_addra, sizeof (abuf)); /* If no host name, use IP address for name later on. */ if (no_name) (void) strlcpy(hostname, abuf, sizeof (hostname)); } if (!no_name) { /* * Even if getnameinfo() succeeded, we still have to check * for spoofing. */ check_address("rlogind", fromp, sin, sin6, rhost_addra, hostname, sizeof (hostname)); } if (bad_port) { if (no_name) syslog(LOG_NOTICE, "connection from %s - bad port\n", abuf); else syslog(LOG_NOTICE, "connection from %s(%s) - bad port\n", hostname, abuf); fatal(f, "Permission denied"); } if (use_auth == KRB5_RECVAUTH_V5) { do_krb_login(f, rhost_addra, hostname, krb_context, encr_flag, keytab); if (krusername != NULL && strlen(krusername)) { /* * Kerberos Authentication succeeded, * so set the proper program name to use * with pam (important during 'cleanup' * routine later). */ pam_prog_name = KRB5_PROG_NAME; } } if (write(f, "", 1) != 1) { syslog(LOG_NOTICE, "send of the zero byte(to %s) failed:" " cannot start data transfer mode\n", (no_name ? abuf : hostname)); exit(EXIT_FAILURE); } if ((p = open("/dev/ptmx", O_RDWR)) == -1) fatalperror(f, "cannot open /dev/ptmx"); if (grantpt(p) == -1) fatal(f, "could not grant slave pty"); if (unlockpt(p) == -1) fatal(f, "could not unlock slave pty"); if ((line = ptsname(p)) == NULL) fatal(f, "could not enable slave pty"); if ((t = open(line, O_RDWR)) == -1) fatal(f, "could not open slave pty"); if (ioctl(t, I_PUSH, "ptem") == -1) fatalperror(f, "ioctl I_PUSH ptem"); if (ioctl(t, I_PUSH, "ldterm") == -1) fatalperror(f, "ioctl I_PUSH ldterm"); if (ioctl(t, I_PUSH, "ttcompat") == -1) fatalperror(f, "ioctl I_PUSH ttcompat"); /* * POP the sockmod and push the rlmod module. * * Note that sockmod has to be removed since readstream assumes * a "raw" TPI endpoint(e.g. it uses getmsg). */ if (removemod(f, "sockmod") < 0) fatalperror(f, "couldn't remove sockmod"); if (encr_flag) { if (ioctl(f, I_PUSH, "cryptmod") < 0) fatalperror(f, "ioctl I_PUSH rlmod"); } if (ioctl(f, I_PUSH, "rlmod") < 0) fatalperror(f, "ioctl I_PUSH rlmod"); if (encr_flag) { /* * Make sure rlmod will pass unrecognized IOCTLs to cryptmod */ uchar_t passthru = 1; struct strioctl rlmodctl; rlmodctl.ic_cmd = CRYPTPASSTHRU; rlmodctl.ic_timout = -1; rlmodctl.ic_len = sizeof (uchar_t); rlmodctl.ic_dp = (char *)&passthru; if (ioctl(f, I_STR, &rlmodctl) < 0) fatal(f, "ioctl CRYPTPASSTHRU failed\n"); } /* * readstream will do a getmsg till it receives * M_PROTO type T_DATA_REQ from rloginmodopen() * indicating all data on the stream prior to pushing rlmod has * been drained at the stream head. */ if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0) fatalperror(f, "readstream failed"); /* * Make sure the pty doesn't modify the strings passed * to login as part of the "rlogin protocol." The login * program should set these flags to apropriate values * after it has read the strings. */ if (ioctl(t, TCGETS, &tp) == -1) fatalperror(f, "ioctl TCGETS"); tp.c_lflag &= ~(ECHO|ICANON); tp.c_oflag &= ~(XTABS|OCRNL); tp.c_iflag &= ~(IGNPAR|ICRNL); if (ioctl(t, TCSETS, &tp) == -1) fatalperror(f, "ioctl TCSETS"); /* * System V ptys allow the TIOC{SG}WINSZ ioctl to be * issued on the master side of the pty. Luckily, that's * the only tty ioctl we need to do do, so we can close the * slave side in the parent process after the fork. */ (void) ioctl(p, TIOCSWINSZ, &win); pid = fork(); if (pid < 0) fatalperror(f, "fork"); if (pid == 0) { int tt; struct utmpx ut; /* System V login expects a utmp entry to already be there */ (void) memset(&ut, 0, sizeof (ut)); (void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user)); (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line)); ut.ut_pid = getpid(); ut.ut_id[0] = 'r'; ut.ut_id[1] = (char)SC_WILDC; ut.ut_id[2] = (char)SC_WILDC; ut.ut_id[3] = (char)SC_WILDC; ut.ut_type = LOGIN_PROCESS; ut.ut_exit.e_termination = 0; ut.ut_exit.e_exit = 0; (void) time(&ut.ut_tv.tv_sec); if (makeutx(&ut) == NULL) syslog(LOG_INFO, "in.rlogind:\tmakeutx failed"); /* controlling tty */ if (setsid() == -1) fatalperror(f, "setsid"); if ((tt = open(line, O_RDWR)) == -1) fatalperror(f, "could not re-open slave pty"); if (close(p) == -1) fatalperror(f, "error closing pty master"); if (close(t) == -1) fatalperror(f, "error closing pty slave" " opened before session established"); /* * If this fails we may or may not be able to output an * error message. */ if (close(f) == -1) fatalperror(f, "error closing deamon stdout"); if (dup2(tt, STDIN_FILENO) == -1 || dup2(tt, STDOUT_FILENO) == -1 || dup2(tt, STDERR_FILENO) == -1) exit(EXIT_FAILURE); /* Disaster! No stderr! */ (void) close(tt); if (use_auth == KRB5_RECVAUTH_V5 && krusername != NULL && strlen(krusername)) { (void) execl(LOGIN_PROGRAM, "login", "-d", line, "-r", hostname, "-u", krusername, /* KRB5 principal name */ "-s", pam_prog_name, "-t", term, /* Remote Terminal */ "-U", rusername, /* Remote User */ "-R", KRB5_REPOSITORY_NAME, lusername, /* local user */ NULL); } else { (void) execl(LOGIN_PROGRAM, "login", "-d", line, "-r", hostname, NULL); } fatalperror(STDERR_FILENO, "/bin/login"); /*NOTREACHED*/ } (void) close(t); (void) ioctl(f, FIONBIO, &on); (void) ioctl(p, FIONBIO, &on); /* * Must ignore SIGTTOU, otherwise we'll stop * when we try and set slave pty's window shape * (our controlling tty is the master pty). * Likewise, we don't want any of the tty-generated * signals from chars passing through. */ (void) sigset(SIGTSTP, SIG_IGN); (void) sigset(SIGINT, SIG_IGN); (void) sigset(SIGQUIT, SIG_IGN); (void) sigset(SIGTTOU, SIG_IGN); (void) sigset(SIGTTIN, SIG_IGN); (void) sigset(SIGCHLD, cleanup); (void) setpgrp(); if (encr_flag) { krb5_data ivec, *ivptr; uint_t ivec_usage; stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT); /* * Configure the STREAMS crypto module. For now, * don't use any IV parameter. KCMDV0.2 support * will require the use of Initialization Vectors * for both encrypt and decrypt modes. */ if (kcmd_protocol == KCMD_OLD_PROTOCOL) { if (session_key->enctype == ENCTYPE_DES_CBC_CRC) { /* * This is gross but necessary for MIT compat. */ ivec.length = session_key->length; ivec.data = (char *)session_key->contents; ivec_usage = IVEC_REUSE; ivptr = &ivec; } else { ivptr = NULL; /* defaults to all 0's */ ivec_usage = IVEC_NEVER; } /* * configure both sides of stream together * since they share the same IV. * This is what makes the OLD KCMD protocol * less secure than the newer one - Bad ivecs. */ if (configure_stream(f, session_key, CRYPT_ENCRYPT|CRYPT_DECRYPT, ivptr, ivec_usage) != 0) fatal(f, "Cannot initialize encryption -" " exiting.\n"); } else { size_t blocksize; if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC || session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { if (configure_stream(f, session_key, CRYPT_ENCRYPT|CRYPT_DECRYPT, NULL, IVEC_NEVER) != 0) fatal(f, "Cannot initialize encryption -" " exiting.\n"); goto startcrypto; } if (krb5_c_block_size(krb_context, session_key->enctype, &blocksize)) { syslog(LOG_ERR, "Cannot determine blocksize " "for encryption type %d", session_key->enctype); fatal(f, "Cannot determine blocksize " "for encryption - exiting.\n"); } ivec.data = (char *)malloc(blocksize); ivec.length = blocksize; if (ivec.data == NULL) fatal(f, "memory error - exiting\n"); /* * Following MIT convention - * encrypt IV = 0x01 x blocksize * decrypt IV = 0x00 x blocksize * ivec_usage = IVEC_ONETIME * * configure_stream separately for encrypt and * decrypt because there are 2 different IVs. * * AES uses 0's for IV. */ if (session_key->enctype == ENCTYPE_AES128_CTS_HMAC_SHA1_96 || session_key->enctype == ENCTYPE_AES256_CTS_HMAC_SHA1_96) (void) memset(ivec.data, 0x00, blocksize); else (void) memset(ivec.data, 0x01, blocksize); if (configure_stream(f, session_key, CRYPT_ENCRYPT, &ivec, IVEC_ONETIME) != 0) fatal(f, "Cannot initialize encryption -" " exiting.\n"); (void) memset(ivec.data, 0x00, blocksize); if (configure_stream(f, session_key, CRYPT_DECRYPT, &ivec, IVEC_ONETIME) != 0) fatal(f, "Cannot initialize encryption -" " exiting.\n"); (void) free(ivec.data); } startcrypto: start_stream(f, CRYPT_ENCRYPT); start_stream(f, CRYPT_DECRYPT); } protocol(f, p, encr_flag); cleanup(0); /*NOTREACHED*/ badconversion: fatalperror(f, "address conversion"); /*NOTREACHED*/ }
/* * Display selected fields of the flow_entry_t structure */ static int mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) { static const mdb_bitmask_t flow_type_bits[] = { {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, {"M", FLOW_MCAST, FLOW_MCAST}, {"O", FLOW_OTHER, FLOW_OTHER}, {"U", FLOW_USER, FLOW_USER}, {"V", FLOW_VNIC, FLOW_VNIC}, {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, { NULL, 0, 0 } }; #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) static const mdb_bitmask_t flow_flag_bits[] = { {"Q", FE_QUIESCE, FE_QUIESCE}, {"W", FE_WAITER, FE_WAITER}, {"T", FE_FLOW_TAB, FE_FLOW_TAB}, {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, {"I", FE_INCIPIENT, FE_INCIPIENT}, {"C", FE_CONDEMNED, FE_CONDEMNED}, {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, { NULL, 0, 0 } }; #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) flow_entry_t fe; mac_client_impl_t mcip; mac_impl_t mip; if (mdb_vread(&fe, sizeof (fe), addr) == -1) { mdb_warn("failed to read struct flow_entry_s at %p", addr); return (DCMD_ERR); } if (args & MAC_FLOW_USER) { args &= ~MAC_FLOW_USER; if (fe.fe_type & FLOW_MCAST) { if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); return (DCMD_OK); } } if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); bzero(&mcip, sizeof (mcip)); bzero(&mip, sizeof (mip)); if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); } switch (args) { case MAC_FLOW_NONE: { mdb_printf("%?p %-20s %4d %?p " "%?p %-16s\n", addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, mcip.mci_mip, mip.mi_name); break; } case MAC_FLOW_ATTR: { struct in_addr in4; uintptr_t desc_addr; flow_desc_t fdesc; desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { mdb_warn("failed to read struct flow_description at %p", desc_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%-7s %6d " "%4d:%-4d ", addr, fe.fe_flow_name, mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, fdesc.fd_dsfield, fdesc.fd_dsfield_mask); if (fdesc.fd_ipversion == IPV4_VERSION) { IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); mdb_printf("%I", in4.s_addr); } else if (fdesc.fd_ipversion == IPV6_VERSION) { mdb_printf("%N", &fdesc.fd_local_addr); } else { mdb_printf("%s", "--"); } mdb_printf("\n"); break; } case MAC_FLOW_PROP: { uintptr_t prop_addr; char bwstr[STRSIZE]; mac_resource_props_t fprop; prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { mdb_warn("failed to read struct mac_resoource_props " "at %p", prop_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%8s %9s\n", addr, fe.fe_flow_name, mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), mac_flow_priority2str(fprop.mrp_priority)); break; } case MAC_FLOW_MISC: { char flow_flags[2 * FLOW_MAX_FLAGS]; char flow_type[2 * FLOW_MAX_TYPE]; GElf_Sym sym; char func_name[MDB_SYM_NAMLEN] = ""; uintptr_t func, match_addr; match_addr = addr + OFFSETOF(flow_entry_t, fe_match); (void) mdb_vread(&func, sizeof (func), match_addr); (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, MDB_SYM_NAMLEN, &sym); mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", fe.fe_flags, flow_flag_bits); mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", fe.fe_type, flow_type_bits); mdb_printf("%?p %-24s %10s %10s %20s\n", addr, fe.fe_flow_name, flow_type, flow_flags, func_name); break; } case MAC_FLOW_RX: { uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; int i; rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); mdb_printf("%?p %-24s %3d ", addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { if (rx_srs[i] == 0) continue; mdb_printf("%p ", rx_srs[i]); } mdb_printf("\n"); break; } case MAC_FLOW_TX: { uintptr_t tx_srs = 0, txaddr; txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); mdb_printf("%?p %-32s %?p\n", addr, fe.fe_flow_name, fe.fe_tx_srs); break; } case MAC_FLOW_STATS: { uint64_t totibytes = 0; uint64_t totobytes = 0; mac_soft_ring_set_t *mac_srs; mac_rx_stats_t mac_rx_stat; mac_tx_stats_t mac_tx_stat; int i; /* * Sum bytes for all Rx SRS. */ for (i = 0; i < fe.fe_rx_srs_cnt; i++) { mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]); if (mdb_vread(&mac_rx_stat, sizeof (mac_rx_stats_t), (uintptr_t)&mac_srs->srs_rx.sr_stat) == -1) { mdb_warn("failed to read mac_rx_stats_t at %p", &mac_srs->srs_rx.sr_stat); return (DCMD_ERR); } totibytes += mac_rx_stat.mrs_intrbytes + mac_rx_stat.mrs_pollbytes + mac_rx_stat.mrs_lclbytes; } /* * Sum bytes for Tx SRS. */ mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs); if (mac_srs != NULL) { if (mdb_vread(&mac_tx_stat, sizeof (mac_tx_stats_t), (uintptr_t)&mac_srs->srs_tx.st_stat) == -1) { mdb_warn("failed to read max_tx_stats_t at %p", &mac_srs->srs_tx.st_stat); return (DCMD_ERR); } totobytes = mac_tx_stat.mts_obytes; } mdb_printf("%?p %-32s %16llu %16llu\n", addr, fe.fe_flow_name, totibytes, totobytes); break; } } return (DCMD_OK); }
void * port_watcher(void *v) { int s, fd, on = 1; char debug[80]; struct sockaddr_in sin_ip; struct sockaddr_in6 sin6_ip; struct sockaddr_storage st; socklen_t socklen; iscsi_conn_t *conn; port_args_t *p = (port_args_t *)v; target_queue_t *q = p->port_mgmtq; int l, accept_err_sleep = 1; pthread_t junk; struct in_addr addr; struct in6_addr addr6; /* * Try creating an IPv6 socket first * If failed, try creating an IPv4 socket */ if ((s = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { queue_str(q, Q_GEN_ERRS, msg_log, "Opening IPv4 socket"); if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { queue_str(q, Q_GEN_ERRS, msg_log, "Can't open socket"); return (NULL); } else { bzero(&sin_ip, sizeof (sin_ip)); sin_ip.sin_family = AF_INET; sin_ip.sin_port = htons(p->port_num); sin_ip.sin_addr.s_addr = INADDR_ANY; (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)); if ((bind(s, (struct sockaddr *)&sin_ip, sizeof (sin_ip))) < 0) { (void) snprintf(debug, sizeof (debug), "bind on port %d failed, errno %d", p->port_num, errno); queue_str(q, Q_GEN_ERRS, msg_status, debug); return (NULL); } } } else { queue_str(q, Q_GEN_DETAILS, msg_log, "Got IPv6 socket"); bzero(&sin6_ip, sizeof (sin6_ip)); sin6_ip.sin6_family = AF_INET6; sin6_ip.sin6_port = htons(p->port_num); sin6_ip.sin6_addr = in6addr_any; (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)); if ((bind(s, (struct sockaddr *)&sin6_ip, sizeof (sin6_ip))) < 0) { (void) snprintf(debug, sizeof (debug), "bind on port %d failed, errno %d", p->port_num, errno); queue_str(q, Q_GEN_ERRS, msg_status, debug); return (NULL); } } if (listen(s, 5) < 0) { queue_str(q, Q_GEN_ERRS, msg_status, "listen failed"); return (NULL); } /*CONSTANTCONDITION*/ while (1) { socklen = sizeof (st); if ((fd = accept(s, (struct sockaddr *)&st, &socklen)) < 0) { accept_err_sleep *= 2; (void) sleep(accept_err_sleep); if (accept_err_sleep > 60) { accept_err_sleep = 1; queue_prt(q, Q_GEN_ERRS, "accept failed, errno %d", errno); } continue; } l = 128 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&l, sizeof (l)) < 0) queue_str(q, Q_GEN_ERRS, msg_status, "setsockopt failed"); if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&l, sizeof (l)) < 0) queue_str(q, Q_GEN_ERRS, msg_status, "setsockopt failed"); l = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&l, sizeof (l)) < 0) queue_str(q, Q_GEN_ERRS, msg_status, "setsockopt keepalive failed"); if ((conn = (iscsi_conn_t *)calloc(sizeof (iscsi_conn_t), 1)) == NULL) { /* * If we fail to get memory this is all rather * pointless, since it's unlikely that queue_str * could malloc memory to send a message. */ queue_str(q, Q_GEN_ERRS, msg_status, "connection malloc failed"); return (NULL); } /* * Save initiator sockaddr for future use */ conn->c_initiator_sockaddr = st; socklen = sizeof (st); if (getsockname(fd, (struct sockaddr *)&st, &socklen) == 0) { /* * Save target sockaddr for future use */ addr6 = ((struct sockaddr_in6 *)&st)->sin6_addr; if (st.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&addr6)) { /* * If target address is IPv4 mapped IPv6 address * convert it to IPv4 address */ IN6_V4MAPPED_TO_INADDR(&addr6, &addr); ((struct sockaddr_in *)&st)->sin_addr = addr; st.ss_family = AF_INET; } conn->c_target_sockaddr = st; } conn->c_fd = fd; conn->c_mgmtq = q; conn->c_up_at = time(NULL); conn->c_state = S1_FREE; (void) pthread_mutex_init(&conn->c_mutex, NULL); (void) pthread_mutex_init(&conn->c_state_mutex, NULL); (void) pthread_mutex_lock(&port_mutex); conn->c_num = port_conn_num++; if (conn_head == NULL) { conn_head = conn; assert(conn_tail == NULL); conn_tail = conn; } else { conn_tail->c_next = conn; conn->c_prev = conn_tail; conn_tail = conn; } (void) pthread_mutex_unlock(&port_mutex); (void) pthread_create(&junk, NULL, conn_process, conn); } return (NULL); }
/* * This routine will convert a mapped v4 hostent (AF_INET6) to a * AF_INET hostent. If no mapped addrs found, then a NULL is returned. * If mapped addrs found, then a new buffer is alloc'd and all the v4 mapped * addresses are extracted and copied to it. On sucess, a pointer to a new * hostent is returned. * There are two possible errors in which case a NULL is returned. * One of two error codes are returned: * * NO_RECOVERY - a malloc failed or the like for which there's no recovery. * NO_ADDRESS - after filtering all the v4, there was nothing left! * * Inputs: * he pointer to hostent with mapped v4 addresses * filter_error pointer to return error code * Return: * pointer to a malloc'd hostent with v4 addresses. * * The results are packed into the res->buffer as follows: * <--------------- buffer + buflen --------------------------------------> * |-----------------|-----------------|----------------|----------------| * | pointers vector | pointers vector | aliases grow | addresses grow | * | for addresses | for aliases | | | * | this way -> | this way -> | <- this way |<- this way | * |-----------------|-----------------|----------------|----------------| * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| */ struct hostent * __mappedtov4(struct hostent *he, int *extract_error) { char *buffer, *limit; nss_XbyY_buf_t *res; int buflen = NSS_BUFLEN_HOSTS; struct in_addr *addr4p; char *buff_locp; struct hostent *host; int count = 0, len, i; char *h_namep; if (he == NULL) { *extract_error = NO_ADDRESS; return (NULL); } if ((__find_mapped(he, 0)) == 0) { *extract_error = NO_ADDRESS; return (NULL); } if ((res = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == 0) { *extract_error = NO_RECOVERY; return (NULL); } limit = res->buffer + buflen; host = (struct hostent *)res->result; buffer = res->buffer; buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in_addr)); host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); if ((char *)host->h_addr_list >= limit || buff_locp <= (char *)host->h_addr_list) goto cleanup; /* * "Unmap" the v4 mapped address(es) into a v4 hostent format. * This is used for getipnodebyaddr() (single address) or for * v4 mapped for getipnodebyname(), which could be multiple * addresses. This could also be a literal address string, * which is why there is a inet_addr() call. */ for (i = 0; he->h_addr_list[i] != NULL; i++) { /* LINTED pointer cast */ if (!IN6_IS_ADDR_V4MAPPED((struct in6_addr *) he->h_addr_list[i])) continue; buff_locp -= sizeof (struct in6_addr); /* * Has to be room for the pointer to the address we're * about to add, as well as the final NULL ptr. */ if (buff_locp <= (char *)&(host->h_addr_list[count + 1])) goto cleanup; /* LINTED pointer cast */ addr4p = (struct in_addr *)buff_locp; host->h_addr_list[count] = (char *)addr4p; bzero((char *)&addr4p->s_addr, sizeof (struct in_addr)); /* LINTED pointer cast */ IN6_V4MAPPED_TO_INADDR( (struct in6_addr *)he->h_addr_list[i], addr4p); ++count; } /* * Set last array element to NULL and add cname as first alias */ host->h_addr_list[count] = NULL; host->h_aliases = host->h_addr_list + count + 1; count = 0; /* Copy official host name */ buff_locp -= (len = strlen(he->h_name) + 1); h_namep = he->h_name; if (buff_locp <= (char *)(host->h_aliases)) goto cleanup; bcopy(h_namep, buff_locp, len); host->h_name = buff_locp; /* * Pass 2 (IPv4 aliases): */ if (he->h_aliases != NULL) { for (i = 0; he->h_aliases[i] != NULL; i++) { buff_locp -= (len = strlen(he->h_aliases[i]) + 1); /* * Has to be room for the pointer to the address we're * about to add, as well as the final NULL ptr. */ if (buff_locp <= (char *)&(host->h_aliases[count + 1])) goto cleanup; host->h_aliases[count] = buff_locp; bcopy((char *)he->h_aliases[i], buff_locp, len); ++count; } } host->h_aliases[count] = NULL; host->h_length = sizeof (struct in_addr); host->h_addrtype = AF_INET; free(res); return (host); cleanup: *extract_error = NO_RECOVERY; (void) __IPv6_cleanup(res); return (NULL); }