From 5070c8135661b8a9b0e5ae817e4e573f4c5ddfff Mon Sep 17 00:00:00 2001 From: Dwi Siswanto Date: Sun, 20 Feb 2022 17:49:02 +0700 Subject: [PATCH] init 1 --- .github/FUNDING.yml | 1 + .github/workflows/build.yaml | 23 + .github/workflows/release.yaml | 27 + .github/workflows/update.yaml | 43 + .gitignore | 1 + .goreleaser.yml | 21 + LICENSE | 21 + README.md | 59 ++ availability.go | 35 + consts.go | 18 + db/db.go | 8 + db/tlds.txt | 1488 ++++++++++++++++++++++++++++++++ db/vars.go | 9 + fingerprint/available.txt | 37 + fingerprint/fingerprint.go | 7 + fingerprint/registered.txt | 3 + fingerprint/unregistered.txt | 52 ++ fingerprint/vars.go | 14 + go.mod | 14 + go.sum | 51 ++ init.go | 37 + main.go | 36 + options.go | 6 + utils.go | 26 + validate.go | 22 + vars.go | 15 + whois.go | 25 + 27 files changed, 2099 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 .github/workflows/update.yaml create mode 100644 .gitignore create mode 100644 .goreleaser.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 availability.go create mode 100644 consts.go create mode 100644 db/db.go create mode 100644 db/tlds.txt create mode 100644 db/vars.go create mode 100644 fingerprint/available.txt create mode 100644 fingerprint/fingerprint.go create mode 100644 fingerprint/registered.txt create mode 100644 fingerprint/unregistered.txt create mode 100644 fingerprint/vars.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 init.go create mode 100644 main.go create mode 100644 options.go create mode 100644 utils.go create mode 100644 validate.go create mode 100644 vars.go create mode 100644 whois.go diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7dc0bf7 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["https://paypal.me/dw1s", "https://saweria.co/dwisiswant0"] \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..3925cad --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,23 @@ +name: Build +on: + push: + branches: + - master + pull_request: + +jobs: + build: + name: Dependencies + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + + - name: Check out code + uses: actions/checkout@v2 + + - name: Build + run: go build . + working-directory: ./ \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..377e298 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,27 @@ +name: Release +on: + create: + tags: + - v* + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: "Check out code" + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: "Set up Go" + uses: actions/setup-go@v2 + with: + go-version: 1.17 + + - name: "Create release on GitHub" + uses: goreleaser/goreleaser-action@v2 + with: + args: "release --rm-dist" + version: latest + env: + GITHUB_TOKEN: "${{ secrets.RELEASE_TOKEN }}" \ No newline at end of file diff --git a/.github/workflows/update.yaml b/.github/workflows/update.yaml new file mode 100644 index 0000000..5d6abba --- /dev/null +++ b/.github/workflows/update.yaml @@ -0,0 +1,43 @@ +name: Update DB +on: + schedule: + - cron: "0 0 * * 0" # at 00:00 on Sunday + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + steps: + - name: "Install dependencies" + run: sudo apt install curl -y + + - name: "Check for updates" + run: | + if [[ "$(curl -skL ${{ secrets.LOCAL_DB }} | wc -l)" == "$(curl -skL ${{ secrets.REMOTE_DB }} | wc -l)" ]]; then + echo "::set-output name=isUpdated::true" + else + echo "::set-output name=isUpdated::false" + fi + + echo "::set-output name=date::$(date)" + + - name: "Check out code" + if: steps.check.isUpdated == 'false' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: "Update DB..." + run: curl -kLo db/tlds.txt ${{ secrets.REMOTE_DB }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + body: "Automated update TLDs data." + branch-suffix: "short-commit-hash" + branch: "update/db" + commit-message: "db: Update DB ${{ steps.check.date }}" + committer: "Dwi Siswanto " + delete-branch: true + reviewers: "dwisiswant0" + title: "db: Update DB ${{ steps.check.date }}" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f179430 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tlder \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..9b9fbd7 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,21 @@ +builds: + - binary: tlder + main: . + goos: + - linux + - windows + - darwin + goarch: + - amd64 + - 386 + - arm + - arm64 + +archives: + - id: tgz + format: tar.gz + replacements: + darwin: macOS + format_overrides: + - goos: windows + format: zip \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b8081b0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Dwi Siswanto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cda94cd --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# TLD:er + +TLDs finder — check domain name availability across all valid top-level domains. + +## Installation + +- Get pre-built binary from [releases page](https://github.com/dwisiswant0/tlder/releases), or +- If you have [Go1.17+](https://go.dev/dl/) compiler installed & configured: `go install github.com/dwisiswant0/tlder@latest`. + +## Usage + +```console +> tlder -h + ________ ___ + /_ __/ / / _ \___ ____ + / / / /_/ // / -_) __/ + /_/ /___/____/\__/_/ + --- + @dwisiswant0 + + +Usage: + tlder -d NAME + +Options: + -d, --domain Domain NAME to permutate + -s, --silent Silent mode + --unreg Show unregistered TLDs only +``` + +## Data + +TLDs data taken from [data.iana.org](https://data.iana.org/TLD/). Checks for data updates are carried out weekly by [GitHub workflow](https://github.com/dwisiswant0/tlder/actions/workflows/update.yaml). + +## Library + +You can use **TLDer** as library. For example: + +```go +package main + +import "github.com/dwisiswant0/tlder" + +func main() { + name := "dw1" + ext := "io" + + avail, err := tlder.IsAvailable(name, ext) + if err != nil { + panic(err) + } + + print(avail) +} +``` + +## License + +**tlder** is distributed under MIT, contributions are welcome! See `LICENSE`. \ No newline at end of file diff --git a/availability.go b/availability.go new file mode 100644 index 0000000..0bc591b --- /dev/null +++ b/availability.go @@ -0,0 +1,35 @@ +package main + +import ( + "strings" + + "github.com/dwisiswant0/tlder/fingerprint" +) + +// IsAvailable domain check from whois response with predefined fingerprint +func IsAvailable(domain string, extension string) (bool, error) { + var s bool + + resp, err := whoIs(domain, extension) + if err != nil { + return s, err + } + + if len([]byte(resp)) == 0 { + return s, errNoResponses + } + + if strings.Contains(resp, "RATE LIMIT EXCEEDED") { + return s, errRateLimited + } + + a := sliceContains(strings.ToLower(resp), fingerprint.Available) + u := sliceContains(resp, fingerprint.Unregistered) + // r := sliceContains(resp, fingerprint.Registered) + + if a || u { + return !s, nil + } + + return s, nil +} diff --git a/consts.go b/consts.go new file mode 100644 index 0000000..2521e1a --- /dev/null +++ b/consts.go @@ -0,0 +1,18 @@ +package main + +const ( + banner = ` + ________ ___ + /_ __/ / / _ \___ ____ + / / / /_/ // / -_) __/ + /_/ /___/____/\__/_/ ` + author = "@dwisiswant0" + usage = ` +Usage: + tlder -d NAME + +Options: + -d, --domain Domain NAME to permutate + -s, --silent Silent mode + --unreg Show unregistered TLDs only` +) diff --git a/db/db.go b/db/db.go new file mode 100644 index 0000000..c8f65f0 --- /dev/null +++ b/db/db.go @@ -0,0 +1,8 @@ +package db + +import "strings" + +func init() { + List = strings.Split(tlds, "\n") + List = List[1 : len(List)-1] +} diff --git a/db/tlds.txt b/db/tlds.txt new file mode 100644 index 0000000..d04649c --- /dev/null +++ b/db/tlds.txt @@ -0,0 +1,1488 @@ +# Version 2022021600, Last Updated Wed Feb 16 07:07:02 2022 UTC +AAA +AARP +ABARTH +ABB +ABBOTT +ABBVIE +ABC +ABLE +ABOGADO +ABUDHABI +AC +ACADEMY +ACCENTURE +ACCOUNTANT +ACCOUNTANTS +ACO +ACTOR +AD +ADAC +ADS +ADULT +AE +AEG +AERO +AETNA +AF +AFL +AFRICA +AG +AGAKHAN +AGENCY +AI +AIG +AIRBUS +AIRFORCE +AIRTEL +AKDN +AL +ALFAROMEO +ALIBABA +ALIPAY +ALLFINANZ +ALLSTATE +ALLY +ALSACE +ALSTOM +AM +AMAZON +AMERICANEXPRESS +AMERICANFAMILY +AMEX +AMFAM +AMICA +AMSTERDAM +ANALYTICS +ANDROID +ANQUAN +ANZ +AO +AOL +APARTMENTS +APP +APPLE +AQ +AQUARELLE +AR +ARAB +ARAMCO +ARCHI +ARMY +ARPA +ART +ARTE +AS +ASDA +ASIA +ASSOCIATES +AT +ATHLETA +ATTORNEY +AU +AUCTION +AUDI +AUDIBLE +AUDIO +AUSPOST +AUTHOR +AUTO +AUTOS +AVIANCA +AW +AWS +AX +AXA +AZ +AZURE +BA +BABY +BAIDU +BANAMEX +BANANAREPUBLIC +BAND +BANK +BAR +BARCELONA +BARCLAYCARD +BARCLAYS +BAREFOOT +BARGAINS +BASEBALL +BASKETBALL +BAUHAUS +BAYERN +BB +BBC +BBT +BBVA +BCG +BCN +BD +BE +BEATS +BEAUTY +BEER +BENTLEY +BERLIN +BEST +BESTBUY +BET +BF +BG +BH +BHARTI +BI +BIBLE +BID +BIKE +BING +BINGO +BIO +BIZ +BJ +BLACK +BLACKFRIDAY +BLOCKBUSTER +BLOG +BLOOMBERG +BLUE +BM +BMS +BMW +BN +BNPPARIBAS +BO +BOATS +BOEHRINGER +BOFA +BOM +BOND +BOO +BOOK +BOOKING +BOSCH +BOSTIK +BOSTON +BOT +BOUTIQUE +BOX +BR +BRADESCO +BRIDGESTONE +BROADWAY +BROKER +BROTHER +BRUSSELS +BS +BT +BUDAPEST +BUGATTI +BUILD +BUILDERS +BUSINESS +BUY +BUZZ +BV +BW +BY +BZ +BZH +CA +CAB +CAFE +CAL +CALL +CALVINKLEIN +CAM +CAMERA +CAMP +CANCERRESEARCH +CANON +CAPETOWN +CAPITAL +CAPITALONE +CAR +CARAVAN +CARDS +CARE +CAREER +CAREERS +CARS +CASA +CASE +CASH +CASINO +CAT +CATERING +CATHOLIC +CBA +CBN +CBRE +CBS +CC +CD +CENTER +CEO +CERN +CF +CFA +CFD +CG +CH +CHANEL +CHANNEL +CHARITY +CHASE +CHAT +CHEAP +CHINTAI +CHRISTMAS +CHROME +CHURCH +CI +CIPRIANI +CIRCLE +CISCO +CITADEL +CITI +CITIC +CITY +CITYEATS +CK +CL +CLAIMS +CLEANING +CLICK +CLINIC +CLINIQUE +CLOTHING +CLOUD +CLUB +CLUBMED +CM +CN +CO +COACH +CODES +COFFEE +COLLEGE +COLOGNE +COM +COMCAST +COMMBANK +COMMUNITY +COMPANY +COMPARE +COMPUTER +COMSEC +CONDOS +CONSTRUCTION +CONSULTING +CONTACT +CONTRACTORS +COOKING +COOKINGCHANNEL +COOL +COOP +CORSICA +COUNTRY +COUPON +COUPONS +COURSES +CPA +CR +CREDIT +CREDITCARD +CREDITUNION +CRICKET +CROWN +CRS +CRUISE +CRUISES +CU +CUISINELLA +CV +CW +CX +CY +CYMRU +CYOU +CZ +DABUR +DAD +DANCE +DATA +DATE +DATING +DATSUN +DAY +DCLK +DDS +DE +DEAL +DEALER +DEALS +DEGREE +DELIVERY +DELL +DELOITTE +DELTA +DEMOCRAT +DENTAL +DENTIST +DESI +DESIGN +DEV +DHL +DIAMONDS +DIET +DIGITAL +DIRECT +DIRECTORY +DISCOUNT +DISCOVER +DISH +DIY +DJ +DK +DM +DNP +DO +DOCS +DOCTOR +DOG +DOMAINS +DOT +DOWNLOAD +DRIVE +DTV +DUBAI +DUNLOP +DUPONT +DURBAN +DVAG +DVR +DZ +EARTH +EAT +EC +ECO +EDEKA +EDU +EDUCATION +EE +EG +EMAIL +EMERCK +ENERGY +ENGINEER +ENGINEERING +ENTERPRISES +EPSON +EQUIPMENT +ER +ERICSSON +ERNI +ES +ESQ +ESTATE +ET +ETISALAT +EU +EUROVISION +EUS +EVENTS +EXCHANGE +EXPERT +EXPOSED +EXPRESS +EXTRASPACE +FAGE +FAIL +FAIRWINDS +FAITH +FAMILY +FAN +FANS +FARM +FARMERS +FASHION +FAST +FEDEX +FEEDBACK +FERRARI +FERRERO +FI +FIAT +FIDELITY +FIDO +FILM +FINAL +FINANCE +FINANCIAL +FIRE +FIRESTONE +FIRMDALE +FISH +FISHING +FIT +FITNESS +FJ +FK +FLICKR +FLIGHTS +FLIR +FLORIST +FLOWERS +FLY +FM +FO +FOO +FOOD +FOODNETWORK +FOOTBALL +FORD +FOREX +FORSALE +FORUM +FOUNDATION +FOX +FR +FREE +FRESENIUS +FRL +FROGANS +FRONTDOOR +FRONTIER +FTR +FUJITSU +FUN +FUND +FURNITURE +FUTBOL +FYI +GA +GAL +GALLERY +GALLO +GALLUP +GAME +GAMES +GAP +GARDEN +GAY +GB +GBIZ +GD +GDN +GE +GEA +GENT +GENTING +GEORGE +GF +GG +GGEE +GH +GI +GIFT +GIFTS +GIVES +GIVING +GL +GLASS +GLE +GLOBAL +GLOBO +GM +GMAIL +GMBH +GMO +GMX +GN +GODADDY +GOLD +GOLDPOINT +GOLF +GOO +GOODYEAR +GOOG +GOOGLE +GOP +GOT +GOV +GP +GQ +GR +GRAINGER +GRAPHICS +GRATIS +GREEN +GRIPE +GROCERY +GROUP +GS +GT +GU +GUARDIAN +GUCCI +GUGE +GUIDE +GUITARS +GURU +GW +GY +HAIR +HAMBURG +HANGOUT +HAUS +HBO +HDFC +HDFCBANK +HEALTH +HEALTHCARE +HELP +HELSINKI +HERE +HERMES +HGTV +HIPHOP +HISAMITSU +HITACHI +HIV +HK +HKT +HM +HN +HOCKEY +HOLDINGS +HOLIDAY +HOMEDEPOT +HOMEGOODS +HOMES +HOMESENSE +HONDA +HORSE +HOSPITAL +HOST +HOSTING +HOT +HOTELES +HOTELS +HOTMAIL +HOUSE +HOW +HR +HSBC +HT +HU +HUGHES +HYATT +HYUNDAI +IBM +ICBC +ICE +ICU +ID +IE +IEEE +IFM +IKANO +IL +IM +IMAMAT +IMDB +IMMO +IMMOBILIEN +IN +INC +INDUSTRIES +INFINITI +INFO +ING +INK +INSTITUTE +INSURANCE +INSURE +INT +INTERNATIONAL +INTUIT +INVESTMENTS +IO +IPIRANGA +IQ +IR +IRISH +IS +ISMAILI +IST +ISTANBUL +IT +ITAU +ITV +JAGUAR +JAVA +JCB +JE +JEEP +JETZT +JEWELRY +JIO +JLL +JM +JMP +JNJ +JO +JOBS +JOBURG +JOT +JOY +JP +JPMORGAN +JPRS +JUEGOS +JUNIPER +KAUFEN +KDDI +KE +KERRYHOTELS +KERRYLOGISTICS +KERRYPROPERTIES +KFH +KG +KH +KI +KIA +KIM +KINDER +KINDLE +KITCHEN +KIWI +KM +KN +KOELN +KOMATSU +KOSHER +KP +KPMG +KPN +KR +KRD +KRED +KUOKGROUP +KW +KY +KYOTO +KZ +LA +LACAIXA +LAMBORGHINI +LAMER +LANCASTER +LANCIA +LAND +LANDROVER +LANXESS +LASALLE +LAT +LATINO +LATROBE +LAW +LAWYER +LB +LC +LDS +LEASE +LECLERC +LEFRAK +LEGAL +LEGO +LEXUS +LGBT +LI +LIDL +LIFE +LIFEINSURANCE +LIFESTYLE +LIGHTING +LIKE +LILLY +LIMITED +LIMO +LINCOLN +LINDE +LINK +LIPSY +LIVE +LIVING +LK +LLC +LLP +LOAN +LOANS +LOCKER +LOCUS +LOFT +LOL +LONDON +LOTTE +LOTTO +LOVE +LPL +LPLFINANCIAL +LR +LS +LT +LTD +LTDA +LU +LUNDBECK +LUXE +LUXURY +LV +LY +MA +MACYS +MADRID +MAIF +MAISON +MAKEUP +MAN +MANAGEMENT +MANGO +MAP +MARKET +MARKETING +MARKETS +MARRIOTT +MARSHALLS +MASERATI +MATTEL +MBA +MC +MCKINSEY +MD +ME +MED +MEDIA +MEET +MELBOURNE +MEME +MEMORIAL +MEN +MENU +MERCKMSD +MG +MH +MIAMI +MICROSOFT +MIL +MINI +MINT +MIT +MITSUBISHI +MK +ML +MLB +MLS +MM +MMA +MN +MO +MOBI +MOBILE +MODA +MOE +MOI +MOM +MONASH +MONEY +MONSTER +MORMON +MORTGAGE +MOSCOW +MOTO +MOTORCYCLES +MOV +MOVIE +MP +MQ +MR +MS +MSD +MT +MTN +MTR +MU +MUSEUM +MUSIC +MUTUAL +MV +MW +MX +MY +MZ +NA +NAB +NAGOYA +NAME +NATURA +NAVY +NBA +NC +NE +NEC +NET +NETBANK +NETFLIX +NETWORK +NEUSTAR +NEW +NEWS +NEXT +NEXTDIRECT +NEXUS +NF +NFL +NG +NGO +NHK +NI +NICO +NIKE +NIKON +NINJA +NISSAN +NISSAY +NL +NO +NOKIA +NORTHWESTERNMUTUAL +NORTON +NOW +NOWRUZ +NOWTV +NP +NR +NRA +NRW +NTT +NU +NYC +NZ +OBI +OBSERVER +OFFICE +OKINAWA +OLAYAN +OLAYANGROUP +OLDNAVY +OLLO +OM +OMEGA +ONE +ONG +ONL +ONLINE +OOO +OPEN +ORACLE +ORANGE +ORG +ORGANIC +ORIGINS +OSAKA +OTSUKA +OTT +OVH +PA +PAGE +PANASONIC +PARIS +PARS +PARTNERS +PARTS +PARTY +PASSAGENS +PAY +PCCW +PE +PET +PF +PFIZER +PG +PH +PHARMACY +PHD +PHILIPS +PHONE +PHOTO +PHOTOGRAPHY +PHOTOS +PHYSIO +PICS +PICTET +PICTURES +PID +PIN +PING +PINK +PIONEER +PIZZA +PK +PL +PLACE +PLAY +PLAYSTATION +PLUMBING +PLUS +PM +PN +PNC +POHL +POKER +POLITIE +PORN +POST +PR +PRAMERICA +PRAXI +PRESS +PRIME +PRO +PROD +PRODUCTIONS +PROF +PROGRESSIVE +PROMO +PROPERTIES +PROPERTY +PROTECTION +PRU +PRUDENTIAL +PS +PT +PUB +PW +PWC +PY +QA +QPON +QUEBEC +QUEST +RACING +RADIO +RE +READ +REALESTATE +REALTOR +REALTY +RECIPES +RED +REDSTONE +REDUMBRELLA +REHAB +REISE +REISEN +REIT +RELIANCE +REN +RENT +RENTALS +REPAIR +REPORT +REPUBLICAN +REST +RESTAURANT +REVIEW +REVIEWS +REXROTH +RICH +RICHARDLI +RICOH +RIL +RIO +RIP +RO +ROCHER +ROCKS +RODEO +ROGERS +ROOM +RS +RSVP +RU +RUGBY +RUHR +RUN +RW +RWE +RYUKYU +SA +SAARLAND +SAFE +SAFETY +SAKURA +SALE +SALON +SAMSCLUB +SAMSUNG +SANDVIK +SANDVIKCOROMANT +SANOFI +SAP +SARL +SAS +SAVE +SAXO +SB +SBI +SBS +SC +SCA +SCB +SCHAEFFLER +SCHMIDT +SCHOLARSHIPS +SCHOOL +SCHULE +SCHWARZ +SCIENCE +SCOT +SD +SE +SEARCH +SEAT +SECURE +SECURITY +SEEK +SELECT +SENER +SERVICES +SES +SEVEN +SEW +SEX +SEXY +SFR +SG +SH +SHANGRILA +SHARP +SHAW +SHELL +SHIA +SHIKSHA +SHOES +SHOP +SHOPPING +SHOUJI +SHOW +SHOWTIME +SI +SILK +SINA +SINGLES +SITE +SJ +SK +SKI +SKIN +SKY +SKYPE +SL +SLING +SM +SMART +SMILE +SN +SNCF +SO +SOCCER +SOCIAL +SOFTBANK +SOFTWARE +SOHU +SOLAR +SOLUTIONS +SONG +SONY +SOY +SPA +SPACE +SPORT +SPOT +SR +SRL +SS +ST +STADA +STAPLES +STAR +STATEBANK +STATEFARM +STC +STCGROUP +STOCKHOLM +STORAGE +STORE +STREAM +STUDIO +STUDY +STYLE +SU +SUCKS +SUPPLIES +SUPPLY +SUPPORT +SURF +SURGERY +SUZUKI +SV +SWATCH +SWISS +SX +SY +SYDNEY +SYSTEMS +SZ +TAB +TAIPEI +TALK +TAOBAO +TARGET +TATAMOTORS +TATAR +TATTOO +TAX +TAXI +TC +TCI +TD +TDK +TEAM +TECH +TECHNOLOGY +TEL +TEMASEK +TENNIS +TEVA +TF +TG +TH +THD +THEATER +THEATRE +TIAA +TICKETS +TIENDA +TIFFANY +TIPS +TIRES +TIROL +TJ +TJMAXX +TJX +TK +TKMAXX +TL +TM +TMALL +TN +TO +TODAY +TOKYO +TOOLS +TOP +TORAY +TOSHIBA +TOTAL +TOURS +TOWN +TOYOTA +TOYS +TR +TRADE +TRADING +TRAINING +TRAVEL +TRAVELCHANNEL +TRAVELERS +TRAVELERSINSURANCE +TRUST +TRV +TT +TUBE +TUI +TUNES +TUSHU +TV +TVS +TW +TZ +UA +UBANK +UBS +UG +UK +UNICOM +UNIVERSITY +UNO +UOL +UPS +US +UY +UZ +VA +VACATIONS +VANA +VANGUARD +VC +VE +VEGAS +VENTURES +VERISIGN +VERSICHERUNG +VET +VG +VI +VIAJES +VIDEO +VIG +VIKING +VILLAS +VIN +VIP +VIRGIN +VISA +VISION +VIVA +VIVO +VLAANDEREN +VN +VODKA +VOLKSWAGEN +VOLVO +VOTE +VOTING +VOTO +VOYAGE +VU +VUELOS +WALES +WALMART +WALTER +WANG +WANGGOU +WATCH +WATCHES +WEATHER +WEATHERCHANNEL +WEBCAM +WEBER +WEBSITE +WED +WEDDING +WEIBO +WEIR +WF +WHOSWHO +WIEN +WIKI +WILLIAMHILL +WIN +WINDOWS +WINE +WINNERS +WME +WOLTERSKLUWER +WOODSIDE +WORK +WORKS +WORLD +WOW +WS +WTC +WTF +XBOX +XEROX +XFINITY +XIHUAN +XIN +XN--11B4C3D +XN--1CK2E1B +XN--1QQW23A +XN--2SCRJ9C +XN--30RR7Y +XN--3BST00M +XN--3DS443G +XN--3E0B707E +XN--3HCRJ9C +XN--3PXU8K +XN--42C2D9A +XN--45BR5CYL +XN--45BRJ9C +XN--45Q11C +XN--4DBRK0CE +XN--4GBRIM +XN--54B7FTA0CC +XN--55QW42G +XN--55QX5D +XN--5SU34J936BGSG +XN--5TZM5G +XN--6FRZ82G +XN--6QQ986B3XL +XN--80ADXHKS +XN--80AO21A +XN--80AQECDR1A +XN--80ASEHDB +XN--80ASWG +XN--8Y0A063A +XN--90A3AC +XN--90AE +XN--90AIS +XN--9DBQ2A +XN--9ET52U +XN--9KRT00A +XN--B4W605FERD +XN--BCK1B9A5DRE4C +XN--C1AVG +XN--C2BR7G +XN--CCK2B3B +XN--CCKWCXETD +XN--CG4BKI +XN--CLCHC0EA0B2G2A9GCD +XN--CZR694B +XN--CZRS0T +XN--CZRU2D +XN--D1ACJ3B +XN--D1ALF +XN--E1A4C +XN--ECKVDTC9D +XN--EFVY88H +XN--FCT429K +XN--FHBEI +XN--FIQ228C5HS +XN--FIQ64B +XN--FIQS8S +XN--FIQZ9S +XN--FJQ720A +XN--FLW351E +XN--FPCRJ9C3D +XN--FZC2C9E2C +XN--FZYS8D69UVGM +XN--G2XX48C +XN--GCKR3F0F +XN--GECRJ9C +XN--GK3AT1E +XN--H2BREG3EVE +XN--H2BRJ9C +XN--H2BRJ9C8C +XN--HXT814E +XN--I1B6B1A6A2E +XN--IMR513N +XN--IO0A7I +XN--J1AEF +XN--J1AMH +XN--J6W193G +XN--JLQ480N2RG +XN--JLQ61U9W7B +XN--JVR189M +XN--KCRX77D1X4A +XN--KPRW13D +XN--KPRY57D +XN--KPUT3I +XN--L1ACC +XN--LGBBAT1AD8J +XN--MGB9AWBF +XN--MGBA3A3EJT +XN--MGBA3A4F16A +XN--MGBA7C0BBN0A +XN--MGBAAKC7DVF +XN--MGBAAM7A8H +XN--MGBAB2BD +XN--MGBAH1A3HJKRD +XN--MGBAI9AZGQP6J +XN--MGBAYH7GPA +XN--MGBBH1A +XN--MGBBH1A71E +XN--MGBC0A9AZCG +XN--MGBCA7DZDO +XN--MGBCPQ6GPA1A +XN--MGBERP4A5D4AR +XN--MGBGU82A +XN--MGBI4ECEXP +XN--MGBPL2FH +XN--MGBT3DHD +XN--MGBTX2B +XN--MGBX4CD0AB +XN--MIX891F +XN--MK1BU44C +XN--MXTQ1M +XN--NGBC5AZD +XN--NGBE9E0A +XN--NGBRX +XN--NODE +XN--NQV7F +XN--NQV7FS00EMA +XN--NYQY26A +XN--O3CW4H +XN--OGBPF8FL +XN--OTU796D +XN--P1ACF +XN--P1AI +XN--PGBS0DH +XN--PSSY2U +XN--Q7CE6A +XN--Q9JYB4C +XN--QCKA1PMC +XN--QXA6A +XN--QXAM +XN--RHQV96G +XN--ROVU88B +XN--RVC1E0AM3E +XN--S9BRJ9C +XN--SES554G +XN--T60B56A +XN--TCKWE +XN--TIQ49XQYJ +XN--UNUP4Y +XN--VERMGENSBERATER-CTB +XN--VERMGENSBERATUNG-PWB +XN--VHQUV +XN--VUQ861B +XN--W4R85EL8FHU5DNRA +XN--W4RS40L +XN--WGBH1C +XN--WGBL6A +XN--XHQ521B +XN--XKC2AL3HYE2A +XN--XKC2DL3A5EE0H +XN--Y9A3AQ +XN--YFRO4I67O +XN--YGBI2AMMX +XN--ZFR164B +XXX +XYZ +YACHTS +YAHOO +YAMAXUN +YANDEX +YE +YODOBASHI +YOGA +YOKOHAMA +YOU +YOUTUBE +YT +YUN +ZA +ZAPPOS +ZARA +ZERO +ZIP +ZM +ZONE +ZUERICH +ZW diff --git a/db/vars.go b/db/vars.go new file mode 100644 index 0000000..24795e4 --- /dev/null +++ b/db/vars.go @@ -0,0 +1,9 @@ +package db + +import _ "embed" + +var ( + //go:embed tlds.txt + tlds string + List []string +) diff --git a/fingerprint/available.txt b/fingerprint/available.txt new file mode 100644 index 0000000..f3a9e34 --- /dev/null +++ b/fingerprint/available.txt @@ -0,0 +1,37 @@ +220 available +available for purchase +but this server does not have +domain not found +domain status: free +dominio no se encuentra registrado +error. +invalid domain name +invalid input +invalid query or domain not known +is available for registration +is free +name or service not known +no data found +no data was found +no entries found +no found +no information available about domain name +no match +no matching record +no object found +no such domain +not find matchingrecord +not found +not registered +nothing found +object does not exist +object_not_found +status: available +status: free +temporary failure in name resolution +the domain has not been registered +the queried object does not exist +the requested domain was not found in the registry +this domain name has not been registered +this is not a registered domain +was not found \ No newline at end of file diff --git a/fingerprint/fingerprint.go b/fingerprint/fingerprint.go new file mode 100644 index 0000000..8d76bda --- /dev/null +++ b/fingerprint/fingerprint.go @@ -0,0 +1,7 @@ +package fingerprint + +import "strings" + +func init() { + Available, Registered, Unregistered = strings.Split(ava, "\n"), strings.Split(reg, "\n"), strings.Split(unr, "\n") +} diff --git a/fingerprint/registered.txt b/fingerprint/registered.txt new file mode 100644 index 0000000..0d686a7 --- /dev/null +++ b/fingerprint/registered.txt @@ -0,0 +1,3 @@ +registered +reserved +unavailable \ No newline at end of file diff --git a/fingerprint/unregistered.txt b/fingerprint/unregistered.txt new file mode 100644 index 0000000..f6dd959 --- /dev/null +++ b/fingerprint/unregistered.txt @@ -0,0 +1,52 @@ +220 Available +Available +AVAILABLE +available for purchase +but this server does not have +Domain not found +DOMAIN NOT FOUND +DOMINIO NO REGISTRADO +Error. +free +Invalid domain name +Invalid input +Invalid pattern +Invalid query or domain name not known +Invalid query or domain name not known in Dominio GQ Domain Registry +Invalid query or domain name not known in Dot TK Domain Registry +Invalid query or domain name not known in My GA Domain Registry +is available for registration +is free +Name or service not known +No Data Found +No data was found to match the request criteria +no entries found +No entries found +No Found +No information available about domain name +No match +NO MATCH +No match for +No matching record +No Object Found +NO OBJECT FOUND +No such domain +Not find MatchingRecord +not found +Not found +Not Found +NOT FOUND +not found in database +not registered +Not Registered +nothing found +Nothing found for this query +Object does not exist +Object_Not_Found +Temporary failure in name resolution +The domain has not been registered. +The queried object does not exist +The requested domain was not found in the Registry +This domain name has not been registered +This is not a Registered Domain under LK Domain Registry +was not found \ No newline at end of file diff --git a/fingerprint/vars.go b/fingerprint/vars.go new file mode 100644 index 0000000..13de956 --- /dev/null +++ b/fingerprint/vars.go @@ -0,0 +1,14 @@ +package fingerprint + +import _ "embed" + +var ( + //go:embed available.txt + ava string + //go:embed registered.txt + reg string + //go:embed unregistered.txt + unr string // Available but lowercase + + Available, Registered, Unregistered []string +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a6ef59f --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module github.com/dwisiswant0/tlder + +go 1.17 + +require github.com/domainr/whois v0.0.0-20220214181047-4fc93982fd9b + +require ( + github.com/PuerkitoBio/goquery v1.8.0 // indirect + github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect + github.com/zonedb/zonedb v1.0.3544 // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/text v0.3.7 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0bb7bab --- /dev/null +++ b/go.sum @@ -0,0 +1,51 @@ +github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= +github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/domainr/whois v0.0.0-20220214181047-4fc93982fd9b h1:Ps5raguPg7YdRJ+jjAc/3hPyE2icsXG4J2ue3472/es= +github.com/domainr/whois v0.0.0-20220214181047-4fc93982fd9b/go.mod h1:/6Ej6qU9Xcl/8we/QKFWhJlvUlqmEDGXgHzOwbazVpo= +github.com/domainr/whoistest v0.0.0-20180714175718-26cad4b7c941 h1:E7ehdIemEeScp8nVs0JXNXEbzb2IsHCk13ijvwKqRWI= +github.com/domainr/whoistest v0.0.0-20180714175718-26cad4b7c941/go.mod h1:iuCHv1qZDoHJNQs56ZzzoKRSKttGgTr2yByGpSlKsII= +github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= +github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zonedb/zonedb v1.0.3544 h1:u5a3xOaI338FclecJ/H6J7fiImVEZ/qZomJnVYIlTeM= +github.com/zonedb/zonedb v1.0.3544/go.mod h1:h9mfHV/S6lboOkltULrbNY52cd7JZo6MbxIiqKMWPLg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/init.go b/init.go new file mode 100644 index 0000000..1b0668a --- /dev/null +++ b/init.go @@ -0,0 +1,37 @@ +package main + +import ( + "flag" + "log" +) + +func init() { + var e error + + opt = options{} + + flag.StringVar(&opt.domain, "d", "", "") + flag.StringVar(&opt.domain, "domain", "", "") + + flag.BoolVar(&opt.silent, "s", false, "") + flag.BoolVar(&opt.silent, "silent", false, "") + + flag.BoolVar(&opt.unreg, "unreg", false, "") + + flag.Usage = func() { + showUsage(true) + } + flag.Parse() + + if opt.domain != "" { + if !opt.silent { + showUsage(false) + } + + if opt.domain, e = validate(opt.domain); e != nil { + log.Fatal(e) + } + } else { + showUsage(true) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..1070529 --- /dev/null +++ b/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/dwisiswant0/tlder/db" +) + +func main() { + for _, ext := range db.List { + ext = strings.ToLower(ext) + + wg.Add(1) + go func(domain string, extension string) { + defer wg.Done() + + a, e := IsAvailable(domain, extension) + if e != nil && !opt.silent { + fmt.Fprintln(os.Stderr, e) + return + } + + d := fmt.Sprint(domain, ".", extension) + + if !a { + fmt.Println("-", d) + } else if opt.unreg { + fmt.Println("-", d) + } + }(opt.domain, ext) + } + + wg.Wait() +} diff --git a/options.go b/options.go new file mode 100644 index 0000000..5a7d46c --- /dev/null +++ b/options.go @@ -0,0 +1,6 @@ +package main + +type options struct { + domain string + unreg, silent bool +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..97457cb --- /dev/null +++ b/utils.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "os" + "strings" +) + +func showUsage(u bool) { + fmt.Fprintf(os.Stderr, "%s\n ---\n %s\n\n", banner, author) + + if u { + fmt.Fprintf(os.Stderr, "%s\n\n", usage) + os.Exit(2) + } +} + +func sliceContains(s string, subslc []string) bool { + for _, slice := range subslc { + if strings.Contains(s, slice) { + return true + } + } + + return false +} diff --git a/validate.go b/validate.go new file mode 100644 index 0000000..4d66aef --- /dev/null +++ b/validate.go @@ -0,0 +1,22 @@ +package main + +import ( + "regexp" + "strings" +) + +func validate(domain string) (string, error) { + domain = strings.ToLower(domain) + + d, _ := regexp.MatchString(`^-`, domain) + if d { + return domain, errInputDomain + } + + r, _ := regexp.MatchString(`^[a-z0-9-]{1,63}$`, domain) + if !r { + return domain, errInputDomain + } + + return domain, nil +} diff --git a/vars.go b/vars.go new file mode 100644 index 0000000..8c62c1b --- /dev/null +++ b/vars.go @@ -0,0 +1,15 @@ +package main + +import ( + "errors" + "sync" +) + +var ( + opt options + wg sync.WaitGroup + + errInputDomain = errors.New("invalid input domain") + errRateLimited = errors.New("whois query rate-limited, please wait & try again") + errNoResponses = errors.New("no query responses from whois") +) diff --git a/whois.go b/whois.go new file mode 100644 index 0000000..3e43586 --- /dev/null +++ b/whois.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/domainr/whois" +) + +func whoIs(domain string, extension string) (string, error) { + extension = strings.ToLower(extension) + query := fmt.Sprint(domain, ".", extension) + + req, err := whois.NewRequest(query) + if err != nil { + return "", err + } + + res, err := whois.DefaultClient.Fetch(req) + if err != nil { + return "", err + } + + return string(res.Body), nil +}