diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index e8187dc2c4027..dafca974bec0e 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -15,7 +15,7 @@ use hash;
 use io;
 use libc::{self, socklen_t, sa_family_t};
 use mem;
-use net::{lookup_host, ntoh, hton, Ipv4Addr, Ipv6Addr};
+use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
 use option;
 use sys_common::{FromInner, AsInner, IntoInner};
 use vec;
@@ -47,6 +47,15 @@ pub struct SocketAddrV4 { inner: libc::sockaddr_in }
 pub struct SocketAddrV6 { inner: libc::sockaddr_in6 }
 
 impl SocketAddr {
+    /// Gets the IP address associated with this socket address.
+    #[unstable(feature = "ip_addr", reason = "recent addition")]
+    pub fn ip(&self) -> IpAddr {
+        match *self {
+            SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
+            SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
+        }
+    }
+
     /// Gets the port number associated with this socket address
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
@@ -333,6 +342,18 @@ impl ToSocketAddrs for SocketAddrV6 {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToSocketAddrs for (IpAddr, u16) {
+    type Iter = option::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+        let (ip, port) = *self;
+        match ip {
+            IpAddr::V4(ref a) => (*a, port).to_socket_addrs(),
+            IpAddr::V6(ref a) => (*a, port).to_socket_addrs(),
+        }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToSocketAddrs for (Ipv4Addr, u16) {
     type Iter = option::IntoIter<SocketAddr>;
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index d737ad17ff8ec..c8b1928747705 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -21,6 +21,16 @@ use libc;
 use sys_common::{AsInner, FromInner};
 use net::{hton, ntoh};
 
+/// An IP address, either a IPv4 or IPv6 address.
+#[unstable(feature = "ip_addr", reason = "recent addition")]
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+    /// Representation of an IPv4 address.
+    V4(Ipv4Addr),
+    /// Representation of an IPv6 address.
+    V6(Ipv6Addr),
+}
+
 /// Representation of an IPv4 address.
 #[derive(Copy)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -139,6 +149,16 @@ impl Ipv4Addr {
 
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            IpAddr::V4(ref a) => a.fmt(fmt),
+            IpAddr::V6(ref a) => a.fmt(fmt),
+        }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv4Addr {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
index 48b3247f2127a..7f51b1cba3fe7 100644
--- a/src/libstd/net/mod.rs
+++ b/src/libstd/net/mod.rs
@@ -21,7 +21,7 @@ use io::{self, Error, ErrorKind};
 use num::Int;
 use sys_common::net2 as net_imp;
 
-pub use self::ip::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
 pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 pub use self::tcp::{TcpStream, TcpListener};
 pub use self::udp::UdpSocket;
@@ -74,10 +74,14 @@ fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
 }
 
 /// An iterator over `SocketAddr` values returned from a host lookup operation.
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+                                              iterator and returning socket \
+                                              addresses")]
 pub struct LookupHost(net_imp::LookupHost);
 
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+                                              iterator and returning socket \
+                                              addresses")]
 impl Iterator for LookupHost {
     type Item = io::Result<SocketAddr>;
     fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
@@ -91,7 +95,7 @@ impl Iterator for LookupHost {
 /// # Examples
 ///
 /// ```no_run
-/// # #![feature(net)]
+/// # #![feature(lookup_host)]
 /// use std::net;
 ///
 /// # fn foo() -> std::io::Result<()> {
@@ -101,7 +105,9 @@ impl Iterator for LookupHost {
 /// # Ok(())
 /// # }
 /// ```
-#[stable(feature = "rust1", since = "1.0.0")]
+#[unstable(feature = "lookup_host", reason = "unsure about the returned \
+                                              iterator and returning socket \
+                                              addresses")]
 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
     net_imp::lookup_host(host).map(LookupHost)
 }
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index e593bbe8e489b..811511149628e 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -14,7 +14,7 @@
 use prelude::v1::*;
 
 use io::{self, Error, ErrorKind};
-use net::{ToSocketAddrs, SocketAddr};
+use net::{ToSocketAddrs, SocketAddr, IpAddr};
 use sys_common::net2 as net_imp;
 use sys_common::AsInner;
 
@@ -116,12 +116,12 @@ impl UdpSocket {
     }
 
     /// Joins a multicast IP address (becomes a member of it)
-    pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
+    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
         self.0.join_multicast(multi)
     }
 
     /// Leaves a multicast IP address (drops membership from it)
-    pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
+    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
         self.0.leave_multicast(multi)
     }
 
diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs
index 25aeab1b4ff74..e213a86644fe1 100644
--- a/src/libstd/sys/common/net2.rs
+++ b/src/libstd/sys/common/net2.rs
@@ -14,7 +14,7 @@ use ffi::CString;
 use io::{self, Error, ErrorKind};
 use libc::{self, c_int, c_char, c_void, socklen_t};
 use mem;
-use net::{SocketAddr, Shutdown};
+use net::{SocketAddr, Shutdown, IpAddr};
 use sys::c;
 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
 use sys_common::{AsInner, FromInner, IntoInner};
@@ -334,39 +334,39 @@ impl UdpSocket {
                    libc::IP_MULTICAST_LOOP, on as c_int)
     }
 
-    pub fn join_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
+    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
         match *multi {
-            SocketAddr::V4(..) => {
+            IpAddr::V4(..) => {
                 self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
             }
-            SocketAddr::V6(..) => {
+            IpAddr::V6(..) => {
                 self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
             }
         }
     }
-    pub fn leave_multicast(&self, multi: &SocketAddr) -> io::Result<()> {
+    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
         match *multi {
-            SocketAddr::V4(..) => {
+            IpAddr::V4(..) => {
                 self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
             }
-            SocketAddr::V6(..) => {
+            IpAddr::V6(..) => {
                 self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
             }
         }
     }
-    fn set_membership(&self, addr: &SocketAddr, opt: c_int) -> io::Result<()> {
+    fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
         match *addr {
-            SocketAddr::V4(ref addr) => {
+            IpAddr::V4(ref addr) => {
                 let mreq = libc::ip_mreq {
-                    imr_multiaddr: *addr.ip().as_inner(),
+                    imr_multiaddr: *addr.as_inner(),
                     // interface == INADDR_ANY
                     imr_interface: libc::in_addr { s_addr: 0x0 },
                 };
                 setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
             }
-            SocketAddr::V6(ref addr) => {
+            IpAddr::V6(ref addr) => {
                 let mreq = libc::ip6_mreq {
-                    ipv6mr_multiaddr: *addr.ip().as_inner(),
+                    ipv6mr_multiaddr: *addr.as_inner(),
                     ipv6mr_interface: 0,
                 };
                 setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)