X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=slirp%2Fip_icmp.c;h=9f1cb08a18ce775ed4674ff654ff0dc540645993;hb=30c367ed446b6ea53245589a5cf373578ac075d7;hp=61dcaf821b48cac919eb5291b58986f0354d69bd;hpb=511d2b140f3ff2f80d14637cdc2f29743a2daa51;p=qemu.git diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 61dcaf821..9f1cb08a1 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -33,10 +33,6 @@ #include "slirp.h" #include "ip_icmp.h" -#ifdef LOG_ENABLED -struct icmpstat icmpstat; -#endif - /* The message sent when emulating PING */ /* Be nice and tell them it's just a pseudo-ping packet */ static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; @@ -64,6 +60,59 @@ static const int icmp_flush[19] = { /* ADDR MASK REPLY (18) */ 0 }; +void icmp_init(Slirp *slirp) +{ + slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp; + slirp->icmp_last_so = &slirp->icmp; +} + +void icmp_cleanup(Slirp *slirp) +{ + while (slirp->icmp.so_next != &slirp->icmp) { + icmp_detach(slirp->icmp.so_next); + } +} + +static int icmp_send(struct socket *so, struct mbuf *m, int hlen) +{ + struct ip *ip = mtod(m, struct ip *); + struct sockaddr_in addr; + + so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + if (so->s == -1) { + return -1; + } + + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_laddr = ip->ip_src; + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + so->so_expire = curtime + SO_EXPIRE; + + addr.sin_family = AF_INET; + addr.sin_addr = so->so_faddr; + + insque(so, &so->slirp->icmp); + + if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) { + DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n", + errno, strerror(errno))); + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); + icmp_detach(so); + } + + return 0; +} + +void icmp_detach(struct socket *so) +{ + closesocket(so->s); + sofree(so); +} + /* * Process a received ICMP message. */ @@ -73,22 +122,19 @@ icmp_input(struct mbuf *m, int hlen) register struct icmp *icp; register struct ip *ip=mtod(m, struct ip *); int icmplen=ip->ip_len; - /* int code; */ + Slirp *slirp = m->slirp; DEBUG_CALL("icmp_input"); DEBUG_ARG("m = %lx", (long )m); DEBUG_ARG("m_len = %d", m->m_len); - STAT(icmpstat.icps_received++); - /* * Locate icmp structure in mbuf, and check * that its not corrupted and of at least minimum length. */ if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ - STAT(icmpstat.icps_tooshort++); freeit: - m_freem(m); + m_free(m); goto end_error; } @@ -96,26 +142,26 @@ icmp_input(struct mbuf *m, int hlen) m->m_data += hlen; icp = mtod(m, struct icmp *); if (cksum(m, icmplen)) { - STAT(icmpstat.icps_checksum++); goto freeit; } m->m_len += hlen; m->m_data -= hlen; - /* icmpstat.icps_inhist[icp->icmp_type]++; */ - /* code = icp->icmp_code; */ - DEBUG_ARG("icmp_type = %d", icp->icmp_type); switch (icp->icmp_type) { case ICMP_ECHO: - icp->icmp_type = ICMP_ECHOREPLY; ip->ip_len += hlen; /* since ip_input subtracts this */ - if (ip->ip_dst.s_addr == alias_addr.s_addr) { + if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) { icmp_reflect(m); + } else if (slirp->restricted) { + goto freeit; } else { struct socket *so; struct sockaddr_in addr; - if ((so = socreate()) == NULL) goto freeit; + if ((so = socreate(slirp)) == NULL) goto freeit; + if (icmp_send(so, m, hlen) == 0) { + return; + } if(udp_attach(so) == -1) { DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", errno,strerror(errno))); @@ -134,16 +180,14 @@ icmp_input(struct mbuf *m, int hlen) /* Send the packet */ addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { /* It's an alias */ - switch(ntohl(so->so_faddr.s_addr) & 0xff) { - case CTL_DNS: - addr.sin_addr = dns_addr; - break; - case CTL_ALIAS: - default: + if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { + if (get_dns_addr(&addr.sin_addr) < 0) + addr.sin_addr = loopback_addr; + } else { addr.sin_addr = loopback_addr; - break; } } else { addr.sin_addr = so->so_faddr; @@ -166,13 +210,11 @@ icmp_input(struct mbuf *m, int hlen) case ICMP_TSTAMP: case ICMP_MASKREQ: case ICMP_REDIRECT: - STAT(icmpstat.icps_notsupp++); - m_freem(m); + m_free(m); break; default: - STAT(icmpstat.icps_badtype++); - m_freem(m); + m_free(m); } /* swith */ end_error: @@ -227,6 +269,11 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, #endif if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + /* Do not reply to source-only IPs */ + if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) { + goto end_error; + } + shlen=ip->ip_hl << 2; s_ip_len=ip->ip_len; if(ip->ip_p == IPPROTO_ICMP) { @@ -239,7 +286,11 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, } /* make a copy */ - if(!(m=m_get())) goto end_error; /* get mbuf */ + m = m_get(msrc->slirp); + if (!m) { + goto end_error; + } + { int new_m_size; new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; if(new_m_size>m->m_size) m_inc(m, new_m_size); @@ -301,13 +352,11 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, ip->ip_ttl = MAXTTL; ip->ip_p = IPPROTO_ICMP; - ip->ip_dst = ip->ip_src; /* ip adresses */ - ip->ip_src = alias_addr; + ip->ip_dst = ip->ip_src; /* ip addresses */ + ip->ip_src = m->slirp->vhost_addr; (void ) ip_output((struct socket *)NULL, m); - STAT(icmpstat.icps_reflect++); - end_error: return; } @@ -332,6 +381,7 @@ icmp_reflect(struct mbuf *m) m->m_len -= hlen; icp = mtod(m, struct icmp *); + icp->icmp_type = ICMP_ECHOREPLY; icp->icmp_cksum = 0; icp->icmp_cksum = cksum(m, ip->ip_len - hlen); @@ -361,6 +411,40 @@ icmp_reflect(struct mbuf *m) } (void ) ip_output((struct socket *)NULL, m); +} - STAT(icmpstat.icps_reflect++); +void icmp_receive(struct socket *so) +{ + struct mbuf *m = so->so_m; + struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + u_char error_code; + struct icmp *icp; + int id, len; + + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + id = icp->icmp_id; + len = qemu_recv(so->s, icp, m->m_len, 0); + icp->icmp_id = id; + + m->m_data -= hlen; + m->m_len += hlen; + + if (len == -1 || len == 0) { + if (errno == ENETUNREACH) { + error_code = ICMP_UNREACH_NET; + } else { + error_code = ICMP_UNREACH_HOST; + } + DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno, + strerror(errno))); + icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = NULL; /* Don't m_free() it again! */ + } + icmp_detach(so); }