diff --git a/Signal/src/network/IpAddress.h b/Signal/src/network/IpAddress.h index d6c66438f..5a6759fdf 100644 --- a/Signal/src/network/IpAddress.h +++ b/Signal/src/network/IpAddress.h @@ -27,6 +27,9 @@ +(IpAddress*) ipv4AddressFromSockaddr:(struct sockaddr_in)sockaddr; +(IpAddress*) ipv6AddressFromSockaddr:(struct sockaddr_in6)sockaddr; +@property (nonatomic, readonly) bool isIpv4; +@property (nonatomic, readonly) bool isIpv6; + -(IpEndPoint*) withPort:(in_port_t)port; -(NSData*) sockaddrData; -(NSData*) sockaddrDataWithPort:(in_port_t)port; diff --git a/Signal/src/network/IpAddress.m b/Signal/src/network/IpAddress.m index 9f278d419..f1d4f2dc5 100644 --- a/Signal/src/network/IpAddress.m +++ b/Signal/src/network/IpAddress.m @@ -80,6 +80,16 @@ return a; } +- (bool)isIpv4 +{ + return isIpv4; +} + +- (bool)isIpv6 +{ + return isIpv6; +} + -(IpEndPoint*) withPort:(in_port_t)port { return [IpEndPoint ipEndPointAtAddress:self onPort:port]; } diff --git a/Signal/src/network/IpEndPoint.h b/Signal/src/network/IpEndPoint.h index 319baf150..e8fad928d 100644 --- a/Signal/src/network/IpEndPoint.h +++ b/Signal/src/network/IpEndPoint.h @@ -21,12 +21,15 @@ +(IpEndPoint*) ipEndPointAtAddress:(IpAddress*)address onPort:(in_port_t)port; -+(IpEndPoint*) ipEndPointAtUnspecifiedAddressOnPort:(in_port_t)port; ++ (IpEndPoint *)ipv4EndPointAtUnspecifiedAddressOnPort:(in_port_t)port; ++ (IpEndPoint *)ipv6EndPointAtUnspecifiedAddressOnPort:(in_port_t)port; +(IpEndPoint*) ipEndPointFromSockaddrData:(NSData*)sockaddrData; +(IpEndPoint*) ipv4EndPointFromSockaddrData:(NSData*)sockaddrData; +(IpEndPoint*) ipv6EndPointFromSockaddrData:(NSData*)sockaddrData; +- (IpEndPoint *)correspondingLocalEndpointWithPort:(in_port_t)specifiedLocalPort; + -(in_port_t) port; -(IpAddress*) address; -(NSData*) sockaddrData; diff --git a/Signal/src/network/IpEndPoint.m b/Signal/src/network/IpEndPoint.m index a6fd85ef9..4c4f9bbc6 100644 --- a/Signal/src/network/IpEndPoint.m +++ b/Signal/src/network/IpEndPoint.m @@ -14,7 +14,8 @@ return p; } -+(IpEndPoint*) ipEndPointAtUnspecifiedAddressOnPort:(in_port_t)port { ++ (IpEndPoint *)ipv4EndPointAtUnspecifiedAddressOnPort:(in_port_t)port +{ struct sockaddr_in s; memset(&s, 0, sizeof(struct sockaddr_in)); s.sin_len = sizeof(struct sockaddr_in); @@ -27,6 +28,20 @@ return a; } ++ (IpEndPoint *)ipv6EndPointAtUnspecifiedAddressOnPort:(in_port_t)port +{ + struct sockaddr_in6 address; + bzero(&address, sizeof(address)); + address.sin6_len = sizeof(address); + address.sin6_family = AF_INET6; + address.sin6_port = htons(port); + + IpEndPoint *a = [IpEndPoint new]; + a->address = [IpAddress ipv6AddressFromString:@"0:0:0:0:0:0:0:0"]; + a->port = port; + return a; +} + +(IpEndPoint*) ipEndPointFromSockaddrData:(NSData*)sockaddrData { ows_require(sockaddrData != nil); ows_require(sockaddrData.length >= sizeof(struct sockaddr)); @@ -59,6 +74,17 @@ return [[IpAddress ipv6AddressFromSockaddr:s] withPort:ntohs(s.sin6_port)]; } +- (IpEndPoint *)correspondingLocalEndpointWithPort:(in_port_t)specifiedLocalPort +{ + if (self.address.isIpv4) { + DDLogDebug(@"%@ Connecting via IPv4", self.tag); + return [IpEndPoint ipv4EndPointAtUnspecifiedAddressOnPort:specifiedLocalPort]; + } else { + DDLogDebug(@"%@ Connecting via IPv6", self.tag); + return [IpEndPoint ipv6EndPointAtUnspecifiedAddressOnPort:specifiedLocalPort]; + } +} + -(IpAddress*) address { return address; } @@ -92,4 +118,16 @@ return [TOCFuture futureWithResult:@[self]]; } +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + @end diff --git a/Signal/src/network/udp/UdpSocket.m b/Signal/src/network/udp/UdpSocket.m index 024a3b47a..a2c6de136 100644 --- a/Signal/src/network/udp/UdpSocket.m +++ b/Signal/src/network/udp/UdpSocket.m @@ -1,6 +1,7 @@ #import "Constraints.h" #import "ThreadManager.h" #import "UdpSocket.h" +#import "IPAddress.h" @implementation UdpSocket @@ -131,8 +132,14 @@ void onReceivedData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef add } -(void) setupLocalEndPoint { - IpEndPoint* specifiedLocalEndPoint = [IpEndPoint ipEndPointAtUnspecifiedAddressOnPort:specifiedLocalPort]; - + IpEndPoint *specifiedLocalEndPoint; + if (self.isRemoteEndPointKnown) { + specifiedLocalEndPoint = [specifiedRemoteEndPoint correspondingLocalEndpointWithPort:specifiedLocalPort]; + } else { + DDLogWarn(@"%@ no remote end point. This is only used in unit tests.", self.tag); + specifiedLocalEndPoint = [IpEndPoint ipv4EndPointAtUnspecifiedAddressOnPort:specifiedLocalPort]; + } + CFSocketError setAddressResult = CFSocketSetAddress(socket, (__bridge CFDataRef)[specifiedLocalEndPoint sockaddrData]); checkOperationDescribe(setAddressResult == kCFSocketSuccess, ([NSString stringWithFormat:@"CFSocketSetAddress failed with error code: %ld", setAddressResult])); @@ -165,9 +172,16 @@ void onReceivedData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef add @try { CFSocketContext socketContext = { 0, (__bridge void *)self, CFRetain, CFRelease, CFCopyDescription }; - + + SInt32 protocolFamily; + if (self.isRemoteEndPointKnown) { + protocolFamily = specifiedRemoteEndPoint.address.isIpv4 ? PF_INET : PF_INET6; + } else { + DDLogWarn(@"Uknown remote endpoint. This is only used in testing."); + protocolFamily = PF_INET; + } socket = CFSocketCreate(kCFAllocatorDefault, - PF_INET, + protocolFamily, SOCK_DGRAM, IPPROTO_UDP, kCFSocketDataCallBack, @@ -194,4 +208,16 @@ void onReceivedData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef add } } +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + @end