Registers an SNS topic in your AWS account as a source of server-initiated UDP packets for a Listener. Once created, your application publishes messages to the topic and Proxylity delivers the corresponding UDP packets to the specified remote clients — without requiring any inbound request to trigger the delivery.
See Packet Sources for a conceptual overview and per-listener-type usage guidance.
To declare this entity in your AWS CloudFormation template, use the following syntax:
{
"Type" : "Custom::ProxylityUdpGatewayPacketSource",
"Properties" : {
"ServiceToken" : String,
"ApiKey" : String,
"ListenerName" : String,
"SnsTopicSource" : {
"TopicArn" : String,
"Role" : String
},
"Description" : String
}
}
Type: Custom::ProxylityUdpGatewayPacketSource
Properties:
ServiceToken: String
ApiKey: String
ListenerName: String
SnsTopicSource:
TopicArn: String
Role: String
Description: String
The ARN of the Proxylity custom resource handler in the deployment region, found in the customer configuration provided by Proxylity. See AWS::CloudFormation::CustomResource.
Required: Yes
Type: String
Update requires: Replacement
The API key provided to you by Proxylity for your account.
Required: Yes
Type: String
Update requires: No interruption
The name of the Custom::ProxylityUdpGatewayListener to bind. Proxylity uses this Listener as the
egress endpoint for packets published to the SNS topic. The Listener must exist in the same AWS account and
region as the stack.
Required: Yes
Type: String
Update requires: Replacement
Identifies the SNS topic that will supply packets and the IAM role Proxylity must assume to subscribe to it.
Required: Yes
Type: Object
Update requires: No interruption
The ARN of the SNS topic in your account. The topic must be in the same region as the CloudFormation stack.
Proxylity subscribes its delivery queues to this topic using the role specified in
SnsTopicSource.Role, so messages published to the topic are automatically delivered to the
Listener's egress path.
Required: Yes
Type: String (ARN)
Update requires: No interruption
The ARN of the IAM role that Proxylity assumes to subscribe its SQS delivery queues to your SNS topic. The role must grant the following permissions on the topic resource:
sns:Subscribesns:Unsubscribesns:ListSubscriptionsByTopicSee Connect Your AWS Account for guidance on setting up cross-account role trust relationships with Proxylity.
Required: Yes
Type: String (ARN)
Update requires: No interruption
A short human-readable description of this Packet Source for your reference.
Required: No
Type: String
Update requires: No interruption
When you pass the logical ID of this resource to the intrinsic Ref function, Ref returns the
internal identifier assigned to the Packet Source.
Each message published to the SNS topic must contain a JSON object with a Messages array. Each
element of the array represents one UDP packet to deliver.
{
"Messages": [
{
"Data": "String",
"Formatter": "String",
"Tag": "String",
"Remote": {
"Address": "String",
"Port": Number,
"PeerKey": "String"
},
"Inner": {
"SourceAddress": "String",
"SourcePort": Number,
"DestinationAddress": "String",
"DestinationPort": Number,
"Version": Number,
"Protocol": Number
}
}
]
}
In addition to the message body, you must set the EgressRegion SNS message
attribute to the AWS region where the packet should exit the Proxylity network. Proxylity
subscribes one SQS delivery queue per supported region, each filtered on this attribute. Messages
published without a matching EgressRegion attribute will not be delivered to any queue
and will be silently discarded.
MessageAttributes={
"EgressRegion": {
"DataType": "String",
"StringValue": "us-east-1" # the region where the packet should egress
}
}
A single SNS publish can include multiple packets in the Messages array. All packets in the array
are processed independently; a delivery failure for one packet does not affect the others.
The UDP payload to send. The encoding is determined by Formatter.
Required: Yes
Type: String
The encoding used for Data. Supported values: base64 (default), hex,
utf8, ascii, coap. When omitted, base64 is assumed.
Required: No
Type: String (enum)
Default: base64
An optional correlation identifier. When provided, this value is recorded in delivery telemetry and can be used to correlate a sourced packet with a prior inbound request.
Required: No
Type: String
Identifies the UDP client that should receive the packet.
Required: Yes
The IPv4 or IPv6 address of the destination client.
Required: Yes
Type: String
The UDP port number of the destination client.
Required: Yes
Type: Number
The base64-encoded WireGuard public key of the target peer. Required when the bound Listener is a WireGuard listener; Proxylity uses this key to select the correct WireGuard session and encrypt the packet before delivery. Ignored for plain UDP listeners.
Required: Yes (WireGuard listeners only)
Type: String (base64-encoded 32 bytes)
Provides inner IP/UDP addressing for WireGuard Listeners that have
DecapsulatedDelivery enabled. When
DecapsulatedDelivery is true, Proxylity re-encapsulates the payload into an inner
IP/UDP frame using these addresses before encrypting and sending via WireGuard. This allows the WireGuard peer
to see a packet that appears to originate from an inner network address rather than from the gateway itself.
The Inner block is required for WireGuard Listeners with
DecapsulatedDelivery enabled, and ignored for all other listeners.
The source IP address to set in the inner IP header.
Required: Yes (when Inner is present)
Type: String
The source UDP port to set in the inner UDP header.
Required: Yes (when Inner is present)
Type: Number
The destination IP address to set in the inner IP header.
Required: Yes (when Inner is present)
Type: String
The destination UDP port to set in the inner UDP header.
Required: Yes (when Inner is present)
Type: Number
The IP version for the inner packet (4 or 6). When omitted, the version is inferred
from the address family of Inner.SourceAddress.
Required: No
Type: Number
The IP protocol number for the inner packet. When omitted, defaults to 17 (UDP).
Required: No
Type: Number
Default: 17
An SNS message attribute (not part of the message body) that identifies the AWS region through which Proxylity should send the packet. Proxylity maintains one regional delivery queue per supported region, each with an SNS filter policy matching this attribute value. Set this to the region closest to your target client, or to the region where the client's WireGuard session was originally established.
For replies to inbound packets, use the ingress region recorded in the original packet JSON envelope — this ensures the reply egresses from the same region the client's traffic entered, which is required for WireGuard session compatibility.
Required: Yes
Type: SNS message attribute (String)
This example creates a Packet Source binding an SNS topic to a UDP Listener. The application publishes to the SNS topic to send packets to remote clients.
ReplyTopic:
Type: AWS::SNS::Topic
PacketSourceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${ProxylityAccountId}:root"
Action: sts:AssumeRole
Policies:
- PolicyName: AllowSnsSubscription
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- sns:Subscribe
- sns:Unsubscribe
- sns:ListSubscriptionsByTopic
Resource: !Ref ReplyTopic
MyPacketSource:
Type: Custom::ProxylityUdpGatewayPacketSource
Properties:
ServiceToken: !Ref ProxylityServiceToken
ListenerName: !GetAtt MyListener.Name
SnsTopicSource:
TopicArn: !Ref ReplyTopic
Role: !GetAtt PacketSourceRole.Arn
Description: "Sourced replies for MyListener"
import boto3, json, base64
sns = boto3.client("sns")
payload = b"\x01\x02\x03\x04" # your UDP payload
sns.publish(
TopicArn="arn:aws:sns:us-east-1:123456789012:ReplyTopic",
MessageAttributes={
"EgressRegion": {"DataType": "String", "StringValue": "us-east-1"}
},
Message=json.dumps({
"Messages": [
{
"Data": base64.b64encode(payload).decode(),
"Remote": {
"Address": "203.0.113.42",
"Port": 4567
}
}
]
})
)
WireGuard Listeners require the PeerKey field so Proxylity can select the correct encrypted
session. If the Listener has DecapsulatedDelivery enabled, each packet must also include an
Inner block with the inner IP addressing.
This pattern is taken from the Raptor open-source project, which uses a Packet Source to send RaptorQ block-completion acknowledgements back to a WireGuard-connected encoder client.
var reply = new ProxylityResponse(Messages: [
new ProxylityReplyMessage(
Remote: new ProxylityEndpoint(
Address: remoteEndpoint.Address.ToString(),
Port: remoteEndpoint.Port,
PeerKey: peerKey),
Data: Convert.ToBase64String(payload)
)
]);
await sns.PublishAsync(new PublishRequest
{
TopicArn = REPLY_TOPIC_ARN,
MessageAttributes = new()
{
["EgressRegion"] = new MessageAttributeValue
{
DataType = "String",
StringValue = egressRegion // ingress region from the original inbound packet
}
},
Message = JsonSerializer.Serialize(reply)
}, token);
sns.publish(
TopicArn="arn:aws:sns:us-east-1:123456789012:WireGuardReplyTopic",
MessageAttributes={
"EgressRegion": {"DataType": "String", "StringValue": "us-east-1"}
},
Message=json.dumps({
"Messages": [
{
"Data": base64.b64encode(payload).decode(),
"Remote": {
"Address": "203.0.113.42",
"Port": 51820,
"PeerKey": "base64encodedWireGuardPublicKey=="
},
"Inner": {
"SourceAddress": "10.0.0.1",
"SourcePort": 53,
"DestinationAddress": "10.0.0.2",
"DestinationPort": 12345
}
}
]
})
)
A single SNS publish can fan out to multiple clients by including several entries in the
Messages array. All packets in a single publish must target the same
EgressRegion.
sns.publish(
TopicArn="...",
MessageAttributes={
"EgressRegion": {"DataType": "String", "StringValue": "us-east-1"}
},
Message=json.dumps({
"Messages": [
{
"Data": base64.b64encode(payload).decode(),
"Remote": { "Address": "203.0.113.1", "Port": 4567 }
},
{
"Data": base64.b64encode(payload).decode(),
"Remote": { "Address": "203.0.113.2", "Port": 4567 }
}
]
})
)
Packet Sources inherit UDP semantics: delivery is best-effort and unacknowledged. If Proxylity cannot deliver a
sourced packet (the remote address is unreachable, the Remote object is malformed, or other
errors), the packet is silently discarded.
To capture undeliverable messages, attach a dead-letter queue to your SNS topic. Structured delivery error events are also emitted to the Listener's CloudWatch log stream alongside inbound packet events.
Packets delivered via a Packet Source are billed at the same per-packet rate as inbound packets, consistent with your AWS Marketplace subscription tier.