Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix IPv6 parsing errors in semconv.NetAttributesFromHTTPRequest #2285

Merged
merged 9 commits into from Oct 18, 2021
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -16,6 +16,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- Adds `otlptracegrpc.WithGRPCConn` and `otlpmetricgrpc.WithGRPCConn` for reusing existing gRPC connection. (#2002)

### Fixed

- `semconv.NetAttributesFromHTTPRequest()` correctly handles IPv6 addresses. (#2285)

## [1.0.1] - 2021-10-01

### Fixed
Expand Down
82 changes: 31 additions & 51 deletions semconv/v1.4.0/http.go
Expand Up @@ -19,7 +19,6 @@ import (
"net"
"net/http"
"strconv"
"strings"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
Expand Down Expand Up @@ -51,64 +50,22 @@ func NetAttributesFromHTTPRequest(network string, request *http.Request) []attri
attrs = append(attrs, NetTransportOther)
}

peerName, peerIP, peerPort := "", "", 0
{
hostPart := request.RemoteAddr
portPart := ""
if idx := strings.LastIndex(hostPart, ":"); idx >= 0 {
hostPart = request.RemoteAddr[:idx]
portPart = request.RemoteAddr[idx+1:]
}
if hostPart != "" {
if ip := net.ParseIP(hostPart); ip != nil {
peerIP = ip.String()
} else {
peerName = hostPart
}

if portPart != "" {
numPort, err := strconv.ParseUint(portPart, 10, 16)
if err == nil {
peerPort = (int)(numPort)
} else {
peerName, peerIP = "", ""
}
}
}
peerIP, peerName, peerPort := hostIPNamePort(request.RemoteAddr)
if peerIP != "" {
attrs = append(attrs, NetPeerIPKey.String(peerIP))
}
if peerName != "" {
attrs = append(attrs, NetPeerNameKey.String(peerName))
}
if peerIP != "" {
attrs = append(attrs, NetPeerIPKey.String(peerIP))
}
if peerPort != 0 {
attrs = append(attrs, NetPeerPortKey.Int(peerPort))
attrs = append(attrs, NetPeerPortKey.Int64(int64(peerPort)))
}

hostIP, hostName, hostPort := "", "", 0
hostIP, hostName, hostPort := "", "", uint64(0)
for _, someHost := range []string{request.Host, request.Header.Get("Host"), request.URL.Host} {
hostPart := ""
if idx := strings.LastIndex(someHost, ":"); idx >= 0 {
strPort := someHost[idx+1:]
numPort, err := strconv.ParseUint(strPort, 10, 16)
if err == nil {
hostPort = (int)(numPort)
}
hostPart = someHost[:idx]
} else {
hostPart = someHost
}
if hostPart != "" {
ip := net.ParseIP(hostPart)
if ip != nil {
hostIP = ip.String()
} else {
hostName = hostPart
}
hostIP, hostName, hostPort = hostIPNamePort(someHost)
if hostIP != "" || hostName != "" || hostPort != 0 {
break
} else {
hostPort = 0
}
}
if hostIP != "" {
Expand All @@ -118,12 +75,35 @@ func NetAttributesFromHTTPRequest(network string, request *http.Request) []attri
attrs = append(attrs, NetHostNameKey.String(hostName))
}
if hostPort != 0 {
attrs = append(attrs, NetHostPortKey.Int(hostPort))
attrs = append(attrs, NetHostPortKey.Int64(int64(hostPort)))
}

return attrs
}

// hostIPNamePort extracts the IP address, name and (optional) port from hostWithPort.
// It handles both IPv4 and IPv6 addresses. If the host portion is not recognized
// as a valid IPv4 or IPv6 address, the `ip` result will be empty and the
// host portion will instead be returned in `name`.
func hostIPNamePort(hostWithPort string) (ip string, name string, port uint64) {
var (
hostPart, portPart string
err error
)
if hostPart, portPart, err = net.SplitHostPort(hostWithPort); err != nil {
hostPart, portPart = hostWithPort, ""
}
if parsedIP := net.ParseIP(hostPart); parsedIP != nil {
ip = parsedIP.String()
} else {
name = hostPart
}
if port, err = strconv.ParseUint(portPart, 10, 16); err != nil {
port = 0
}
return
}

// EndUserAttributesFromHTTPRequest generates attributes of the
// enduser namespace as specified by the OpenTelemetry specification
// for a span.
Expand Down