mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
slirp: Forward ICMP echo requests via unprivileged sockets
Linux 3.0 gained support for unprivileged ICMP ping sockets. Use this feature to forward guest pings to the outer world. The host admin has to set the ping_group_range in order to grant access to those sockets. To allow ping for the users group (GID 100): echo 100 100 > /proc/sys/net/ipv4/ping_group_range Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
565465fcae
commit
e6d43cfb1f
7 changed files with 147 additions and 1 deletions
|
@ -60,6 +60,52 @@ 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;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -97,7 +143,6 @@ icmp_input(struct mbuf *m, int hlen)
|
|||
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 == slirp->vhost_addr.s_addr) {
|
||||
icmp_reflect(m);
|
||||
|
@ -107,6 +152,9 @@ icmp_input(struct mbuf *m, int hlen)
|
|||
struct socket *so;
|
||||
struct sockaddr_in addr;
|
||||
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)));
|
||||
|
@ -321,6 +369,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);
|
||||
|
||||
|
@ -351,3 +400,39 @@ icmp_reflect(struct mbuf *m)
|
|||
|
||||
(void ) ip_output((struct socket *)NULL, m);
|
||||
}
|
||||
|
||||
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 = 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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue