├── main.py ├── src ├── requirements.txt ├── Dockerfile └── main.py ├── .npmignore ├── Serverless_DOH.png ├── .gitignore ├── jest.config.js ├── bin └── aws-serverless-httpdns.ts ├── CODE_OF_CONDUCT.md ├── package.json ├── test └── aws-serverless-httpdns.test.ts ├── tsconfig.json ├── LICENSE ├── lib ├── aws-serverless-httpdns-stack.ts └── aws-serverless-httpdns-regional-stack.ts ├── cdk.json ├── CONTRIBUTING.md └── README.md /main.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/requirements.txt: -------------------------------------------------------------------------------- 1 | dnspython -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /Serverless_DOH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/serverless-httpdns/HEAD/Serverless_DOH.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.12 2 | 3 | WORKDIR ${LAMBDA_TASK_ROOT} 4 | COPY . . 5 | RUN pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" 6 | 7 | CMD ["main.lambda_handler"] 8 | -------------------------------------------------------------------------------- /bin/aws-serverless-httpdns.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from 'aws-cdk-lib'; 3 | import 'source-map-support/register'; 4 | import { AwsServerlessHttpdnsStack } from '../lib/aws-serverless-httpdns-stack'; 5 | 6 | 7 | const app = new cdk.App(); 8 | new AwsServerlessHttpdnsStack(app, 'AwsServerlessHttpdns') -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-serverless-httpdns", 3 | "version": "0.1.0", 4 | "bin": { 5 | "aws-serverless-httpdns": "bin/aws-serverless-httpdns.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^29.4.0", 15 | "@types/node": "18.14.6", 16 | "jest": "^29.5.0", 17 | "ts-jest": "^29.0.5", 18 | "aws-cdk": "2.76.0", 19 | "ts-node": "^10.9.1", 20 | "typescript": "~4.9.5" 21 | }, 22 | "dependencies": { 23 | "aws-cdk-lib": "2.80.0", 24 | "constructs": "^10.0.0", 25 | "source-map-support": "^0.5.21" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/aws-serverless-httpdns.test.ts: -------------------------------------------------------------------------------- 1 | // import * as cdk from 'aws-cdk-lib'; 2 | // import { Template } from 'aws-cdk-lib/assertions'; 3 | // import * as AwsServerlessHttpdns from '../lib/aws-serverless-httpdns-stack'; 4 | 5 | // example test. To run these tests, uncomment this file along with the 6 | // example resource in lib/aws-serverless-httpdns-stack.ts 7 | test('SQS Queue Created', () => { 8 | // const app = new cdk.App(); 9 | // // WHEN 10 | // const stack = new AwsServerlessHttpdns.AwsServerlessHttpdnsStack(app, 'MyTestStack'); 11 | // // THEN 12 | // const template = Template.fromStack(stack); 13 | 14 | // template.hasResourceProperties('AWS::SQS::Queue', { 15 | // VisibilityTimeout: 300 16 | // }); 17 | }); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /lib/aws-serverless-httpdns-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import { Accelerator } from 'aws-cdk-lib/aws-globalaccelerator'; 3 | import { ApplicationLoadBalancerEndpoint } from 'aws-cdk-lib/aws-globalaccelerator-endpoints'; 4 | import { Construct } from 'constructs'; 5 | import { AwsServerlessHttpdnsRegionalStack } from './aws-serverless-httpdns-regional-stack'; 6 | 7 | export class AwsServerlessHttpdnsStack extends cdk.Stack { 8 | 9 | constructor(scope: Construct, id: string, props?: cdk.StackProps) { 10 | super(scope, id, props); 11 | 12 | const regionalStack = new AwsServerlessHttpdnsRegionalStack(this, 'AwsServerlessHttpdnsStack') 13 | 14 | const accelerator = new Accelerator(this, 'Accelerator') 15 | const listener = accelerator.addListener('Listener', { portRanges: [{ fromPort: 80 }] }); 16 | listener.addEndpointGroup('endpoint-1', { endpoints: [new ApplicationLoadBalancerEndpoint(regionalStack.alb)] }) 17 | 18 | new cdk.CfnOutput(this, 'GLOBAL_ACCELERATOR_ARN', { value: accelerator.acceleratorArn }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/aws-serverless-httpdns-regional-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import { IpAddresses, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2'; 3 | import { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; 4 | import { LambdaTarget } from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets'; 5 | import { DockerImageCode, DockerImageFunction } from 'aws-cdk-lib/aws-lambda'; 6 | import { Construct } from 'constructs'; 7 | import path = require('path'); 8 | 9 | export class AwsServerlessHttpdnsRegionalStack extends cdk.Stack { 10 | 11 | alb: ApplicationLoadBalancer 12 | 13 | constructor(scope: Construct, id: string, props?: cdk.StackProps) { 14 | super(scope, id, props); 15 | 16 | const lambda = new DockerImageFunction(this, 'httpdns-lamdba-function', { 17 | description: 'httpdns core function', code: DockerImageCode.fromImageAsset(path.join(__dirname, '../src')), 18 | }) 19 | new cdk.CfnOutput(this, 'Lambda Function', { value: lambda.functionName }) 20 | 21 | const vpc = new Vpc(this, 'httpdns-hosting-vpc', { 22 | ipAddresses: IpAddresses.cidr('100.64.0.0/24'), 23 | maxAzs: 3, 24 | subnetConfiguration: [{ name: 'public-ingress', cidrMask: 28, subnetType: SubnetType.PUBLIC }] 25 | }) 26 | new cdk.CfnOutput(this, 'Hosting VPC ARN', { value: vpc.vpcArn }) 27 | 28 | 29 | const alb = new ApplicationLoadBalancer(this, 'httpdns-ingress-alb', { vpc: vpc, internetFacing: true }) 30 | const listener = alb.addListener("Listener", { port: 80 }) 31 | listener.addTargets('Targets', { targets: [new LambdaTarget(lambda)] }) 32 | new cdk.CfnOutput(this, 'ALB DNS', { value: alb.loadBalancerDnsName }) 33 | 34 | 35 | this.alb = alb; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/aws-serverless-httpdns.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## build a serverless httpdns resolver on aws 2 | 3 | ![image](https://github.com/aws-samples/serverless-httpdns/blob/main/Serverless_DOH.png) 4 | 5 | This solution is built on a Serverless architecture, using AGA+ALB+Lambda to implement an httpDNS system. The fully Serverless architecture eliminates the need for operations and maintenance costs. Lambda is a managed service that supports multi-Availability Zone deployment and comes with built-in high availability features. The solution can be quickly deployed with AWS CDK. 6 | 7 | 8 | * To achieve global access with low latency and high performance, this solution uses AWS Global Accelerator to provide access to the nearest edge location. By leveraging the performance, security, and availability of AWS's global infrastructure, users can access the system through an anycast IP static address, without relying on DNS. 9 | * Global Accelerator allows each listener to bind to different endpoint groups in various regions. Depending on the user's location, Global Accelerator sends requests to the nearest target in the AWS region. Global Accelerator also provides endpoint health checks and prevents requests from being sent to unhealthy targets. 10 | * ALB+Lambda provides an httpProxy that uses the X-Forwarded-For (XFF) header to determine the client's real IP address and apply a geolocation-based DNS resolution strategy. 11 | * Lambda is a highly available service that supports multi-Availability Zone deployment. Deploying Lambda functions across multiple regions provides even greater reliability and reduces global user access latency. 12 | * Lambda itself is a highly available service that supports multi-Availability Zone deployment. Deploying Lambda functions across multiple regions provides even greater reliability and reduces global user access latency. 13 | * This solution also supports IPv4 and IPv6 dual-stack resolution. 14 | 15 | ### Build 16 | * Make sure you follow the [AWS CDK Prerequisites][1] before you build the project. 17 | * Clone this project and change the directory to the root folder of the project, and run below commands: 18 | ``` 19 | $ npm install -g aws-cdk 20 | $ npm install 21 | $ cdk bootstrap —region ${AWS_REGION_CODE} aws://${YOUR_ACCOUNT_ID}/${AWS_REGION_CODE} 22 | ``` 23 | 24 | ### Deploy 25 | Run commands as below: 26 | ``` 27 | $ cdk synth 28 | $ cdk deploy --all 29 | ``` 30 | 31 | ### Verify 32 | ``` 33 | curl -XPOST http://${GA_STATIC_IP_ADDRESS} \ 34 | -H 'Content-Type: application/json' \ 35 | -d '{"recordName":"www.amazon.com","recordType":"A"}' 36 | 37 | "d3ag4hukkh62yn.cloudfront.net. 60 IN A 143.204.81.223"% 38 | ``` 39 | 40 | ### Clean 41 | Run commands as below: 42 | ``` 43 | $ cdk destroy 44 | ``` 45 | 46 | ### Takeaway 47 | HTTPDNS can be used as a backup for normal UDP DNS resolution failure in client/APP, ensuring correct resolution results in the event of LocalDNS hijacking, and improving the availability of the client system. Deploying HTTPDNS based on Lambda takes advantage of Lambda's features to achieve high availability while reducing deployment complexity. In addition, Serverless is billed on a usage basis, which means no cost is incurred if no queries are made, and multiple-region deployment of Lambda can provide near-zero-cost HA disaster recovery. 48 | 49 | [1]: https://docs.aws.amazon.com/cdk/latest/guide/work-with.html#work-with-prerequisites 50 | 51 | ## Security 52 | 53 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 54 | 55 | ## License 56 | 57 | This library is licensed under the MIT-0 License. See the LICENSE file. 58 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2012 OpenDNS, Inc. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # * Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # * Neither the name of the OpenDNS nor the names of its contributors may be 14 | # used to endorse or promote products derived from this software without 15 | # specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL OPENDNS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | """ Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as 29 | draft-vandergaast-edns-client-subnet. 30 | 31 | The contained class supports both IPv4 and IPv6 addresses. 32 | Requirements: 33 | dnspython (http://www.dnspython.org/) 34 | """ 35 | from __future__ import division, print_function 36 | 37 | import json 38 | import socket 39 | import struct 40 | from ipaddress import IPv4Address, ip_address 41 | 42 | import dns 43 | import dns.edns 44 | import dns.flags 45 | import dns.message 46 | import dns.query 47 | import dns.resolver 48 | 49 | 50 | def calculateMask(IP: str) -> int: 51 | try: 52 | if type(ip_address(IP)) is IPv4Address: 53 | return 24 54 | else: 55 | return 56 56 | except ValueError: 57 | return -1 58 | 59 | 60 | ASSIGNED_OPTION_CODE = 0x0008 61 | DRAFT_OPTION_CODE = 0x50FA 62 | 63 | FAMILY_IPV4 = 1 64 | FAMILY_IPV6 = 2 65 | SUPPORTED_FAMILIES = (FAMILY_IPV4, FAMILY_IPV6) 66 | DNS_RESOLVER = '8.8.8.8' 67 | 68 | 69 | def getDnsResult(resolverIP, recordName, recordType, clientIP, mask): 70 | addr = socket.gethostbyname(resolverIP) 71 | # mask = 24 72 | option_code = ASSIGNED_OPTION_CODE 73 | # print("Testing for edns-clientsubnet using option code", hex(option_code)) 74 | 75 | message = dns.message.make_query(recordName, recordType, options=[ 76 | dns.edns.ECSOption(clientIP, mask)]) 77 | 78 | 79 | r = dns.query.udp(message, addr, timeout=10) 80 | 81 | error = False 82 | found = False 83 | recordData = "" 84 | for options in r.options: 85 | for rdata in r.answer: 86 | recordData = rdata 87 | 88 | return recordData 89 | 90 | 91 | def lambda_handler(event, context): 92 | body = json.loads(event['body']) 93 | recordName = body['recordName'] 94 | recordType = body['recordType'] 95 | clientIP = event['headers']['x-forwarded-for'] 96 | 97 | mask = calculateMask(clientIP) 98 | 99 | if recordType == 'CNAME': 100 | cnameData = getDnsResult( 101 | DNS_RESOLVER, recordName, recordType, clientIP, mask) 102 | print(cnameData) 103 | recordData = getDnsResult( 104 | DNS_RESOLVER, cnameData[0].to_text(), 'A', clientIP, mask) 105 | else: 106 | recordData = getDnsResult( 107 | DNS_RESOLVER, recordName, recordType, clientIP, mask) 108 | 109 | return { 110 | "statusCode": 200, 111 | "statusDescription": "200 OK", 112 | "isBase64Encoded": False, 113 | "headers": { 114 | "Content-Type": "text/html" 115 | }, 116 | "body": json.dumps(recordData.to_text()) 117 | } 118 | --------------------------------------------------------------------------------