diff --git a/ethereum.go b/ethereum.go
index 0137f68de14633e4e1efc594fe38a7a67dc4d9a1..b192b544d81d1402f241078712f06667f8d81e4d 100644
--- a/ethereum.go
+++ b/ethereum.go
@@ -8,6 +8,7 @@ import (
 	"github.com/ethereum/ethwire-go"
 	"log"
 	"net"
+	"strconv"
 	"sync/atomic"
 	"time"
 )
@@ -40,6 +41,10 @@ type Ethereum struct {
 	peers *list.List
 	// Nonce
 	Nonce uint64
+
+	Addr net.Addr
+
+	nat NAT
 }
 
 func New() (*Ethereum, error) {
@@ -51,12 +56,20 @@ func New() (*Ethereum, error) {
 
 	ethutil.Config.Db = db
 
+	/*
+		nat, err := Discover()
+		if err != nil {
+			log.Printf("Can'them discover upnp: %v", err)
+		}
+	*/
+
 	nonce, _ := ethutil.RandomUint64()
 	ethereum := &Ethereum{
 		shutdownChan: make(chan bool),
 		db:           db,
 		peers:        list.New(),
 		Nonce:        nonce,
+		//nat:          nat,
 	}
 	ethereum.TxPool = ethchain.NewTxPool()
 	ethereum.TxPool.Speaker = ethereum
@@ -179,18 +192,59 @@ func (s *Ethereum) ReapDeadPeers() {
 	}
 }
 
+// FIXME
+func (s *Ethereum) upnpUpdateThread() {
+	// Go off immediately to prevent code duplication, thereafter we renew
+	// lease every 15 minutes.
+	timer := time.NewTimer(0 * time.Second)
+	lport, _ := strconv.ParseInt("30303", 10, 16)
+	first := true
+out:
+	for {
+		select {
+		case <-timer.C:
+			listenPort, err := s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60)
+			if err != nil {
+				log.Printf("can't add UPnP port mapping: %v\n", err)
+			}
+			if first && err == nil {
+				externalip, err := s.nat.GetExternalAddress()
+				if err != nil {
+					log.Printf("UPnP can't get external address: %v\n", err)
+					continue out
+				}
+				// externalip, listenport
+				log.Println("Successfully bound via UPnP to", externalip, listenPort)
+				first = false
+			}
+			timer.Reset(time.Minute * 15)
+		case <-s.shutdownChan:
+			break out
+		}
+	}
+
+	timer.Stop()
+
+	if err := s.nat.DeletePortMapping("tcp", int(lport), int(lport)); err != nil {
+		log.Printf("unable to remove UPnP port mapping: %v\n", err)
+	} else {
+		log.Printf("succesfully disestablished UPnP port mapping\n")
+	}
+}
+
 // Start the ethereum
 func (s *Ethereum) Start() {
 	// Bind to addr and port
 	ln, err := net.Listen("tcp", ":30303")
 	if err != nil {
 		// This is mainly for testing to create a "network"
-		if ethutil.Config.Debug {
-			log.Println("Connection listening disabled. Acting as client")
-		} else {
-			log.Fatal(err)
-		}
+		//if ethutil.Config.Debug {
+		//log.Println("Connection listening disabled. Acting as client")
+		//} else {
+		log.Fatal(err)
+		//}
 	} else {
+		s.Addr = ln.Addr()
 		// Starting accepting connections
 		go func() {
 			log.Println("Ready and accepting connections")
diff --git a/peer.go b/peer.go
index c91df79dbc1063b7118d1f05271c21d8c452af85..5d22b545c79c493032196595d0491f1306512a22 100644
--- a/peer.go
+++ b/peer.go
@@ -253,22 +253,21 @@ out:
 			case ethwire.MsgPeersTy:
 				// Received a list of peers (probably because MsgGetPeersTy was send)
 				// Only act on message if we actually requested for a peers list
-				if p.requestedPeerList {
-					data := msg.Data
-					// Create new list of possible peers for the ethereum to process
-					peers := make([]string, data.Length())
-					// Parse each possible peer
-					for i := 0; i < data.Length(); i++ {
-						peers[i] = unpackAddr(data.Get(i).Get(0).AsBytes(), data.Get(i).Get(1).AsUint())
-						log.Println(peers[i])
-					}
+				//if p.requestedPeerList {
+				data := msg.Data
+				// Create new list of possible peers for the ethereum to process
+				peers := make([]string, data.Length())
+				// Parse each possible peer
+				for i := 0; i < data.Length(); i++ {
+					peers[i] = unpackAddr(data.Get(i).Get(0), data.Get(i).Get(1).AsUint())
+				}
 
-					// Connect to the list of peers
-					p.ethereum.ProcessPeerList(peers)
-					// Mark unrequested again
-					p.requestedPeerList = false
+				// Connect to the list of peers
+				p.ethereum.ProcessPeerList(peers)
+				// Mark unrequested again
+				p.requestedPeerList = false
 
-				}
+				//}
 			case ethwire.MsgGetChainTy:
 				var parent *ethchain.Block
 				// Length minus one since the very last element in the array is a count
@@ -326,15 +325,11 @@ func packAddr(address, port string) ([]byte, uint16) {
 	return host, uint16(prt)
 }
 
-func unpackAddr(h []byte, p uint64) string {
-	if len(h) != 4 {
-		return ""
-	}
-
-	a := strconv.Itoa(int(h[0]))
-	b := strconv.Itoa(int(h[1]))
-	c := strconv.Itoa(int(h[2]))
-	d := strconv.Itoa(int(h[3]))
+func unpackAddr(value *ethutil.RlpValue, p uint64) string {
+	a := strconv.Itoa(int(value.Get(0).AsUint()))
+	b := strconv.Itoa(int(value.Get(1).AsUint()))
+	c := strconv.Itoa(int(value.Get(2).AsUint()))
+	d := strconv.Itoa(int(value.Get(3).AsUint()))
 	host := strings.Join([]string{a, b, c, d}, ".")
 	port := strconv.Itoa(int(p))
 
@@ -349,9 +344,9 @@ func (p *Peer) Start(seed bool) {
 	if peerHost == servHost {
 		log.Println("Connected to self")
 
-		//p.Stop()
+		p.Stop()
 
-		//return
+		return
 	}
 
 	if p.inbound {
diff --git a/upnp.go b/upnp.go
new file mode 100644
index 0000000000000000000000000000000000000000..c84ed04f8dc624d2b8cce41526d99f8eeba07ca6
--- /dev/null
+++ b/upnp.go
@@ -0,0 +1,405 @@
+package eth
+
+// Upnp code taken from Taipei Torrent license is below:
+// Copyright (c) 2010 Jack Palevich. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Just enough UPnP to be able to forward ports
+//
+
+import (
+	"bytes"
+	"encoding/xml"
+	"errors"
+	"net"
+	"net/http"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// NAT is an interface representing a NAT traversal options for example UPNP or
+// NAT-PMP. It provides methods to query and manipulate this traversal to allow
+// access to services.
+type NAT interface {
+	// Get the external address from outside the NAT.
+	GetExternalAddress() (addr net.IP, err error)
+	// Add a port mapping for protocol ("udp" or "tcp") from externalport to
+	// internal port with description lasting for timeout.
+	AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error)
+	// Remove a previously added port mapping from externalport to
+	// internal port.
+	DeletePortMapping(protocol string, externalPort, internalPort int) (err error)
+}
+
+type upnpNAT struct {
+	serviceURL string
+	ourIP      string
+}
+
+// Discover searches the local network for a UPnP router returning a NAT
+// for the network if so, nil if not.
+func Discover() (nat NAT, err error) {
+	ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
+	if err != nil {
+		return
+	}
+	conn, err := net.ListenPacket("udp4", ":0")
+	if err != nil {
+		return
+	}
+	socket := conn.(*net.UDPConn)
+	defer socket.Close()
+
+	err = socket.SetDeadline(time.Now().Add(3 * time.Second))
+	if err != nil {
+		return
+	}
+
+	st := "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
+	buf := bytes.NewBufferString(
+		"M-SEARCH * HTTP/1.1\r\n" +
+			"HOST: 239.255.255.250:1900\r\n" +
+			st +
+			"MAN: \"ssdp:discover\"\r\n" +
+			"MX: 2\r\n\r\n")
+	message := buf.Bytes()
+	answerBytes := make([]byte, 1024)
+	for i := 0; i < 3; i++ {
+		_, err = socket.WriteToUDP(message, ssdp)
+		if err != nil {
+			return
+		}
+		var n int
+		n, _, err = socket.ReadFromUDP(answerBytes)
+		if err != nil {
+			continue
+			// socket.Close()
+			// return
+		}
+		answer := string(answerBytes[0:n])
+		if strings.Index(answer, "\r\n"+st) < 0 {
+			continue
+		}
+		// HTTP header field names are case-insensitive.
+		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+		locString := "\r\nlocation: "
+		answer = strings.ToLower(answer)
+		locIndex := strings.Index(answer, locString)
+		if locIndex < 0 {
+			continue
+		}
+		loc := answer[locIndex+len(locString):]
+		endIndex := strings.Index(loc, "\r\n")
+		if endIndex < 0 {
+			continue
+		}
+		locURL := loc[0:endIndex]
+		var serviceURL string
+		serviceURL, err = getServiceURL(locURL)
+		if err != nil {
+			return
+		}
+		var ourIP string
+		ourIP, err = getOurIP()
+		if err != nil {
+			return
+		}
+		nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP}
+		return
+	}
+	err = errors.New("UPnP port discovery failed")
+	return
+}
+
+// service represents the Service type in an UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type service struct {
+	ServiceType string `xml:"serviceType"`
+	ControlURL  string `xml:"controlURL"`
+}
+
+// deviceList represents the deviceList type in an UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type deviceList struct {
+	XMLName xml.Name `xml:"deviceList"`
+	Device  []device `xml:"device"`
+}
+
+// serviceList represents the serviceList type in an UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type serviceList struct {
+	XMLName xml.Name  `xml:"serviceList"`
+	Service []service `xml:"service"`
+}
+
+// device represents the device type in an UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type device struct {
+	XMLName     xml.Name    `xml:"device"`
+	DeviceType  string      `xml:"deviceType"`
+	DeviceList  deviceList  `xml:"deviceList"`
+	ServiceList serviceList `xml:"serviceList"`
+}
+
+// specVersion represents the specVersion in a UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type specVersion struct {
+	XMLName xml.Name `xml:"specVersion"`
+	Major   int      `xml:"major"`
+	Minor   int      `xml:"minor"`
+}
+
+// root represents the Root document for a UPnP xml description.
+// Only the parts we care about are present and thus the xml may have more
+// fields than present in the structure.
+type root struct {
+	XMLName     xml.Name `xml:"root"`
+	SpecVersion specVersion
+	Device      device
+}
+
+// getChildDevice searches the children of device for a device with the given
+// type.
+func getChildDevice(d *device, deviceType string) *device {
+	for i := range d.DeviceList.Device {
+		if d.DeviceList.Device[i].DeviceType == deviceType {
+			return &d.DeviceList.Device[i]
+		}
+	}
+	return nil
+}
+
+// getChildDevice searches the service list of device for a service with the
+// given type.
+func getChildService(d *device, serviceType string) *service {
+	for i := range d.ServiceList.Service {
+		if d.ServiceList.Service[i].ServiceType == serviceType {
+			return &d.ServiceList.Service[i]
+		}
+	}
+	return nil
+}
+
+// getOurIP returns a best guess at what the local IP is.
+func getOurIP() (ip string, err error) {
+	hostname, err := os.Hostname()
+	if err != nil {
+		return
+	}
+	return net.LookupCNAME(hostname)
+}
+
+// getServiceURL parses the xml description at the given root url to find the
+// url for the WANIPConnection service to be used for port forwarding.
+func getServiceURL(rootURL string) (url string, err error) {
+	r, err := http.Get(rootURL)
+	if err != nil {
+		return
+	}
+	defer r.Body.Close()
+	if r.StatusCode >= 400 {
+		err = errors.New(string(r.StatusCode))
+		return
+	}
+	var root root
+	err = xml.NewDecoder(r.Body).Decode(&root)
+	if err != nil {
+		return
+	}
+	a := &root.Device
+	if a.DeviceType != "urn:schemas-upnp-org:device:InternetGatewayDevice:1" {
+		err = errors.New("no InternetGatewayDevice")
+		return
+	}
+	b := getChildDevice(a, "urn:schemas-upnp-org:device:WANDevice:1")
+	if b == nil {
+		err = errors.New("no WANDevice")
+		return
+	}
+	c := getChildDevice(b, "urn:schemas-upnp-org:device:WANConnectionDevice:1")
+	if c == nil {
+		err = errors.New("no WANConnectionDevice")
+		return
+	}
+	d := getChildService(c, "urn:schemas-upnp-org:service:WANIPConnection:1")
+	if d == nil {
+		err = errors.New("no WANIPConnection")
+		return
+	}
+	url = combineURL(rootURL, d.ControlURL)
+	return
+}
+
+// combineURL appends subURL onto rootURL.
+func combineURL(rootURL, subURL string) string {
+	protocolEnd := "://"
+	protoEndIndex := strings.Index(rootURL, protocolEnd)
+	a := rootURL[protoEndIndex+len(protocolEnd):]
+	rootIndex := strings.Index(a, "/")
+	return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
+}
+
+// soapBody represents the <s:Body> element in a SOAP reply.
+// fields we don't care about are elided.
+type soapBody struct {
+	XMLName xml.Name `xml:"Body"`
+	Data    []byte   `xml:",innerxml"`
+}
+
+// soapEnvelope represents the <s:Envelope> element in a SOAP reply.
+// fields we don't care about are elided.
+type soapEnvelope struct {
+	XMLName xml.Name `xml:"Envelope"`
+	Body    soapBody `xml:"Body"`
+}
+
+// soapRequests performs a soap request with the given parameters and returns
+// the xml replied stripped of the soap headers. in the case that the request is
+// unsuccessful the an error is returned.
+func soapRequest(url, function, message string) (replyXML []byte, err error) {
+	fullMessage := "<?xml version=\"1.0\" ?>" +
+		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
+		"<s:Body>" + message + "</s:Body></s:Envelope>"
+
+	req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage))
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"")
+	req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3")
+	//req.Header.Set("Transfer-Encoding", "chunked")
+	req.Header.Set("SOAPAction", "\"urn:schemas-upnp-org:service:WANIPConnection:1#"+function+"\"")
+	req.Header.Set("Connection", "Close")
+	req.Header.Set("Cache-Control", "no-cache")
+	req.Header.Set("Pragma", "no-cache")
+
+	r, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	if r.Body != nil {
+		defer r.Body.Close()
+	}
+
+	if r.StatusCode >= 400 {
+		// log.Stderr(function, r.StatusCode)
+		err = errors.New("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
+		r = nil
+		return
+	}
+	var reply soapEnvelope
+	err = xml.NewDecoder(r.Body).Decode(&reply)
+	if err != nil {
+		return nil, err
+	}
+	return reply.Body.Data, nil
+}
+
+// getExternalIPAddressResponse represents the XML response to a
+// GetExternalIPAddress SOAP request.
+type getExternalIPAddressResponse struct {
+	XMLName           xml.Name `xml:"GetExternalIPAddressResponse"`
+	ExternalIPAddress string   `xml:"NewExternalIPAddress"`
+}
+
+// GetExternalAddress implements the NAT interface by fetching the external IP
+// from the UPnP router.
+func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {
+	message := "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\"/>\r\n"
+	response, err := soapRequest(n.serviceURL, "GetExternalIPAddress", message)
+	if err != nil {
+		return nil, err
+	}
+
+	var reply getExternalIPAddressResponse
+	err = xml.Unmarshal(response, &reply)
+	if err != nil {
+		return nil, err
+	}
+
+	addr = net.ParseIP(reply.ExternalIPAddress)
+	if addr == nil {
+		return nil, errors.New("unable to parse ip address")
+	}
+	return addr, nil
+}
+
+// AddPortMapping implements the NAT interface by setting up a port forwarding
+// from the UPnP router to the local machine with the given ports and protocol.
+func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) {
+	// A single concatenation would break ARM compilation.
+	message := "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
+		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort)
+	message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>"
+	message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
+		"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
+		"<NewEnabled>1</NewEnabled><NewPortMappingDescription>"
+	message += description +
+		"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) +
+		"</NewLeaseDuration></u:AddPortMapping>"
+
+	response, err := soapRequest(n.serviceURL, "AddPortMapping", message)
+	if err != nil {
+		return
+	}
+
+	// TODO: check response to see if the port was forwarded
+	// If the port was not wildcard we don't get an reply with the port in
+	// it. Not sure about wildcard yet. miniupnpc just checks for error
+	// codes here.
+	mappedExternalPort = externalPort
+	_ = response
+	return
+}
+
+// AddPortMapping implements the NAT interface by removing up a port forwarding
+// from the UPnP router to the local machine with the given ports and.
+func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {
+
+	message := "<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
+		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
+		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
+		"</u:DeletePortMapping>"
+
+	response, err := soapRequest(n.serviceURL, "DeletePortMapping", message)
+	if err != nil {
+		return
+	}
+
+	// TODO: check response to see if the port was deleted
+	// log.Println(message, response)
+	_ = response
+	return
+}