Initial commit
This commit is contained in:
commit
e48ae45ca1
|
@ -0,0 +1,2 @@
|
|||
node/node_modules/*
|
||||
.idea/
|
|
@ -0,0 +1,22 @@
|
|||
# Selfhosting Trashmail API
|
||||
|
||||
Basic self hosting trashmail API using docker NodeJS, Redis, NGINX + LUA
|
||||
|
||||
|
||||
Requirements
|
||||
---
|
||||
* Docker
|
||||
* [Docker-Compose](https://docs.docker.com/compose/)
|
||||
|
||||
|
||||
Installation
|
||||
---
|
||||
You need to set permissions right to allow npm to run `npm install`
|
||||
```
|
||||
chmod -R 777 node
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Use the `-d` option to run the containers in daemon mode, and `docker-compose logs -f` to watch logs
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
version: '3'
|
||||
services:
|
||||
node:
|
||||
image: node:9.2.0-alpine
|
||||
user: node
|
||||
working_dir: /home/node/app
|
||||
volumes:
|
||||
- ./node/:/home/node/app
|
||||
command: /bin/sh -c "npm i && node ."
|
||||
depends_on:
|
||||
- redis
|
||||
redis:
|
||||
image: redis:3.2.11-alpine
|
||||
restart: always
|
||||
ports:
|
||||
- 6379:6379
|
||||
nginx:
|
||||
image: registry.lumen.sh/lumen/docker-alpine-nginx-lua:1.13.7
|
||||
volumes:
|
||||
- ./nginx/conf/:/etc/nginx
|
||||
- ./nginx/lua/:/etc/nginx/lua
|
||||
restart: always
|
||||
depends_on:
|
||||
- redis
|
||||
ports:
|
||||
- 80:80
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
# This map is not a full koi8-r <> utf8 map: it does not contain
|
||||
# box-drawing and some other characters. Besides this map contains
|
||||
# several koi8-u and Byelorussian letters which are not in koi8-r.
|
||||
# If you need a full and standard map, use contrib/unicode2nginx/koi-utf
|
||||
# map instead.
|
||||
|
||||
charset_map koi8-r utf-8 {
|
||||
|
||||
80 E282AC ; # euro
|
||||
|
||||
95 E280A2 ; # bullet
|
||||
|
||||
9A C2A0 ; #
|
||||
|
||||
9E C2B7 ; # ·
|
||||
|
||||
A3 D191 ; # small yo
|
||||
A4 D194 ; # small Ukrainian ye
|
||||
|
||||
A6 D196 ; # small Ukrainian i
|
||||
A7 D197 ; # small Ukrainian yi
|
||||
|
||||
AD D291 ; # small Ukrainian soft g
|
||||
AE D19E ; # small Byelorussian short u
|
||||
|
||||
B0 C2B0 ; # °
|
||||
|
||||
B3 D081 ; # capital YO
|
||||
B4 D084 ; # capital Ukrainian YE
|
||||
|
||||
B6 D086 ; # capital Ukrainian I
|
||||
B7 D087 ; # capital Ukrainian YI
|
||||
|
||||
B9 E28496 ; # numero sign
|
||||
|
||||
BD D290 ; # capital Ukrainian soft G
|
||||
BE D18E ; # capital Byelorussian short U
|
||||
|
||||
BF C2A9 ; # (C)
|
||||
|
||||
C0 D18E ; # small yu
|
||||
C1 D0B0 ; # small a
|
||||
C2 D0B1 ; # small b
|
||||
C3 D186 ; # small ts
|
||||
C4 D0B4 ; # small d
|
||||
C5 D0B5 ; # small ye
|
||||
C6 D184 ; # small f
|
||||
C7 D0B3 ; # small g
|
||||
C8 D185 ; # small kh
|
||||
C9 D0B8 ; # small i
|
||||
CA D0B9 ; # small j
|
||||
CB D0BA ; # small k
|
||||
CC D0BB ; # small l
|
||||
CD D0BC ; # small m
|
||||
CE D0BD ; # small n
|
||||
CF D0BE ; # small o
|
||||
|
||||
D0 D0BF ; # small p
|
||||
D1 D18F ; # small ya
|
||||
D2 D180 ; # small r
|
||||
D3 D181 ; # small s
|
||||
D4 D182 ; # small t
|
||||
D5 D183 ; # small u
|
||||
D6 D0B6 ; # small zh
|
||||
D7 D0B2 ; # small v
|
||||
D8 D18C ; # small soft sign
|
||||
D9 D18B ; # small y
|
||||
DA D0B7 ; # small z
|
||||
DB D188 ; # small sh
|
||||
DC D18D ; # small e
|
||||
DD D189 ; # small shch
|
||||
DE D187 ; # small ch
|
||||
DF D18A ; # small hard sign
|
||||
|
||||
E0 D0AE ; # capital YU
|
||||
E1 D090 ; # capital A
|
||||
E2 D091 ; # capital B
|
||||
E3 D0A6 ; # capital TS
|
||||
E4 D094 ; # capital D
|
||||
E5 D095 ; # capital YE
|
||||
E6 D0A4 ; # capital F
|
||||
E7 D093 ; # capital G
|
||||
E8 D0A5 ; # capital KH
|
||||
E9 D098 ; # capital I
|
||||
EA D099 ; # capital J
|
||||
EB D09A ; # capital K
|
||||
EC D09B ; # capital L
|
||||
ED D09C ; # capital M
|
||||
EE D09D ; # capital N
|
||||
EF D09E ; # capital O
|
||||
|
||||
F0 D09F ; # capital P
|
||||
F1 D0AF ; # capital YA
|
||||
F2 D0A0 ; # capital R
|
||||
F3 D0A1 ; # capital S
|
||||
F4 D0A2 ; # capital T
|
||||
F5 D0A3 ; # capital U
|
||||
F6 D096 ; # capital ZH
|
||||
F7 D092 ; # capital V
|
||||
F8 D0AC ; # capital soft sign
|
||||
F9 D0AB ; # capital Y
|
||||
FA D097 ; # capital Z
|
||||
FB D0A8 ; # capital SH
|
||||
FC D0AD ; # capital E
|
||||
FD D0A9 ; # capital SHCH
|
||||
FE D0A7 ; # capital CH
|
||||
FF D0AA ; # capital hard sign
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
charset_map koi8-r windows-1251 {
|
||||
|
||||
80 88 ; # euro
|
||||
|
||||
95 95 ; # bullet
|
||||
|
||||
9A A0 ; #
|
||||
|
||||
9E B7 ; # ·
|
||||
|
||||
A3 B8 ; # small yo
|
||||
A4 BA ; # small Ukrainian ye
|
||||
|
||||
A6 B3 ; # small Ukrainian i
|
||||
A7 BF ; # small Ukrainian yi
|
||||
|
||||
AD B4 ; # small Ukrainian soft g
|
||||
AE A2 ; # small Byelorussian short u
|
||||
|
||||
B0 B0 ; # °
|
||||
|
||||
B3 A8 ; # capital YO
|
||||
B4 AA ; # capital Ukrainian YE
|
||||
|
||||
B6 B2 ; # capital Ukrainian I
|
||||
B7 AF ; # capital Ukrainian YI
|
||||
|
||||
B9 B9 ; # numero sign
|
||||
|
||||
BD A5 ; # capital Ukrainian soft G
|
||||
BE A1 ; # capital Byelorussian short U
|
||||
|
||||
BF A9 ; # (C)
|
||||
|
||||
C0 FE ; # small yu
|
||||
C1 E0 ; # small a
|
||||
C2 E1 ; # small b
|
||||
C3 F6 ; # small ts
|
||||
C4 E4 ; # small d
|
||||
C5 E5 ; # small ye
|
||||
C6 F4 ; # small f
|
||||
C7 E3 ; # small g
|
||||
C8 F5 ; # small kh
|
||||
C9 E8 ; # small i
|
||||
CA E9 ; # small j
|
||||
CB EA ; # small k
|
||||
CC EB ; # small l
|
||||
CD EC ; # small m
|
||||
CE ED ; # small n
|
||||
CF EE ; # small o
|
||||
|
||||
D0 EF ; # small p
|
||||
D1 FF ; # small ya
|
||||
D2 F0 ; # small r
|
||||
D3 F1 ; # small s
|
||||
D4 F2 ; # small t
|
||||
D5 F3 ; # small u
|
||||
D6 E6 ; # small zh
|
||||
D7 E2 ; # small v
|
||||
D8 FC ; # small soft sign
|
||||
D9 FB ; # small y
|
||||
DA E7 ; # small z
|
||||
DB F8 ; # small sh
|
||||
DC FD ; # small e
|
||||
DD F9 ; # small shch
|
||||
DE F7 ; # small ch
|
||||
DF FA ; # small hard sign
|
||||
|
||||
E0 DE ; # capital YU
|
||||
E1 C0 ; # capital A
|
||||
E2 C1 ; # capital B
|
||||
E3 D6 ; # capital TS
|
||||
E4 C4 ; # capital D
|
||||
E5 C5 ; # capital YE
|
||||
E6 D4 ; # capital F
|
||||
E7 C3 ; # capital G
|
||||
E8 D5 ; # capital KH
|
||||
E9 C8 ; # capital I
|
||||
EA C9 ; # capital J
|
||||
EB CA ; # capital K
|
||||
EC CB ; # capital L
|
||||
ED CC ; # capital M
|
||||
EE CD ; # capital N
|
||||
EF CE ; # capital O
|
||||
|
||||
F0 CF ; # capital P
|
||||
F1 DF ; # capital YA
|
||||
F2 D0 ; # capital R
|
||||
F3 D1 ; # capital S
|
||||
F4 D2 ; # capital T
|
||||
F5 D3 ; # capital U
|
||||
F6 C6 ; # capital ZH
|
||||
F7 C2 ; # capital V
|
||||
F8 DC ; # capital soft sign
|
||||
F9 DB ; # capital Y
|
||||
FA C7 ; # capital Z
|
||||
FB D8 ; # capital SH
|
||||
FC DD ; # capital E
|
||||
FD D9 ; # capital SHCH
|
||||
FE D7 ; # capital CH
|
||||
FF DA ; # capital hard sign
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
../../usr/lib/nginx/modules
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
#user nobody;
|
||||
worker_processes auto;
|
||||
worker_rlimit_nofile 100000;
|
||||
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
events {
|
||||
worker_connections 65535;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
access_log off;
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
keepalive_timeout 30;
|
||||
|
||||
client_header_timeout 10;
|
||||
client_body_timeout 10;
|
||||
send_timeout 10;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
lua_package_path '/etc/nginx/lua/modules/?.lua;;';
|
||||
lua_socket_log_errors off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
location ~ ^/(check|10minutemail|disposable)/(raw|json|xml|status)$ {
|
||||
add_header X-Request-Id $request_id;
|
||||
content_by_lua_file lua/mail.lua;
|
||||
}
|
||||
location ~ ^/(validate|valid)/(raw|json|xml|status)$ {
|
||||
if ($request_method != POST) {
|
||||
return 400;
|
||||
}
|
||||
content_by_lua_file lua/validator.lua;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/mysql/admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/mysql/dbadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/mysql/sqlmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/mysql/mysqlmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpmyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpMyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpMyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpmyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:31 +0000] "HEAD http://178.62.212.150:80/phpmyadmin3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/phpmyadmin4/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/2phpmyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/phpmy/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/phppma/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/myadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/shopdb/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/MyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/program/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/PMA/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/dbadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/pma/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/db/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/mysql/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/database/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:32 +0000] "HEAD http://178.62.212.150:80/db/phpmyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/db/phpMyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/sqlmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/mysqlmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/php-myadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/phpmy-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/mysqladmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/mysql-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/phpmyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/phpMyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/sysadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/sqladmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/db/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/web/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/admin/pMA/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:33 +0000] "HEAD http://178.62.212.150:80/mysql/pma/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/mysql/db/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/mysql/web/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/mysql/pMA/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/phpmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/php-myadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/phpmy-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/sql/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/myadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/webadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/sqlweb/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/websql/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/webdb/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/sqladmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/sql-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/phpmyadmin2/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:34 +0000] "HEAD http://178.62.212.150:80/sql/phpMyAdmin2/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/sql/phpMyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/myadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/webadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/dbweb/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/websql/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/webdb/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/dbadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/db-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/phpmyadmin3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/phpMyAdmin3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/db/phpMyAdmin-3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/phpmyadmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/phpMyAdmin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/db/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/web/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/pma/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/PMA/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:35 +0000] "HEAD http://178.62.212.150:80/administrator/admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/phpMyAdmin2/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/phpMyAdmin3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/phpMyAdmin4/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/phpMyAdmin-3/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/php-my-admin/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2011/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2012/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2013/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2014/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2015/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2016/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2017/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/PMA2018/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/pma2011/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/pma2012/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/pma2013/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/pma2014/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:36 +0000] "HEAD http://178.62.212.150:80/pma2015/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/pma2016/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/pma2017/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/pma2018/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2011/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2012/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2013/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2014/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2016/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:37 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2017/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:38 +0000] "HEAD http://178.62.212.150:80/phpmyadmin2018/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
2.82.138.16 - - [06/Dec/2017:16:14:38 +0000] "HEAD http://178.62.212.150:80/phpmanager/ HTTP/1.1" 404 0 "-" "Mozilla/5.0 Jorgee"
|
||||
37.58.58.232 - - [06/Dec/2017:17:20:13 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:21:27 +0000] "POST /check/json/test HTTP/1.1" 200 71 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:21:31 +0000] "POST /check/json/test HTTP/1.1" 200 71 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:21:43 +0000] "POST /check/json/test HTTP/1.1" 400 166 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:21:49 +0000] "POST /check/json/test HTTP/1.1" 200 69 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:25:27 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:25:48 +0000] "POST /check/json/test HTTP/1.1" 200 69 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:39:34 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:39:43 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:40:10 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:40:15 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:41:01 +0000] "POST /check/json/test HTTP/1.1" 503 206 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:41:07 +0000] "POST /check/json/test HTTP/1.1" 503 206 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:41:11 +0000] "POST /check/json/test HTTP/1.1" 503 206 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:41:32 +0000] "POST /check/json/test HTTP/1.1" 503 206 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:43:20 +0000] "POST /check/json/test HTTP/1.1" 200 69 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:46:09 +0000] "POST /check/json/test HTTP/1.1" 500 186 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:46:50 +0000] "POST /check/json/test HTTP/1.1" 200 69 "-" "PostmanRuntime/6.3.2"
|
||||
37.58.58.232 - - [06/Dec/2017:17:54:31 +0000] "POST /check/json/test HTTP/1.1" 200 69 "-" "PostmanRuntime/6.3.2"
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
# This map is not a full windows-1251 <> utf8 map: it does not
|
||||
# contain Serbian and Macedonian letters. If you need a full map,
|
||||
# use contrib/unicode2nginx/win-utf map instead.
|
||||
|
||||
charset_map windows-1251 utf-8 {
|
||||
|
||||
82 E2809A ; # single low-9 quotation mark
|
||||
|
||||
84 E2809E ; # double low-9 quotation mark
|
||||
85 E280A6 ; # ellipsis
|
||||
86 E280A0 ; # dagger
|
||||
87 E280A1 ; # double dagger
|
||||
88 E282AC ; # euro
|
||||
89 E280B0 ; # per mille
|
||||
|
||||
91 E28098 ; # left single quotation mark
|
||||
92 E28099 ; # right single quotation mark
|
||||
93 E2809C ; # left double quotation mark
|
||||
94 E2809D ; # right double quotation mark
|
||||
95 E280A2 ; # bullet
|
||||
96 E28093 ; # en dash
|
||||
97 E28094 ; # em dash
|
||||
|
||||
99 E284A2 ; # trade mark sign
|
||||
|
||||
A0 C2A0 ; #
|
||||
A1 D18E ; # capital Byelorussian short U
|
||||
A2 D19E ; # small Byelorussian short u
|
||||
|
||||
A4 C2A4 ; # currency sign
|
||||
A5 D290 ; # capital Ukrainian soft G
|
||||
A6 C2A6 ; # borken bar
|
||||
A7 C2A7 ; # section sign
|
||||
A8 D081 ; # capital YO
|
||||
A9 C2A9 ; # (C)
|
||||
AA D084 ; # capital Ukrainian YE
|
||||
AB C2AB ; # left-pointing double angle quotation mark
|
||||
AC C2AC ; # not sign
|
||||
AD C2AD ; # soft hypen
|
||||
AE C2AE ; # (R)
|
||||
AF D087 ; # capital Ukrainian YI
|
||||
|
||||
B0 C2B0 ; # °
|
||||
B1 C2B1 ; # plus-minus sign
|
||||
B2 D086 ; # capital Ukrainian I
|
||||
B3 D196 ; # small Ukrainian i
|
||||
B4 D291 ; # small Ukrainian soft g
|
||||
B5 C2B5 ; # micro sign
|
||||
B6 C2B6 ; # pilcrow sign
|
||||
B7 C2B7 ; # ·
|
||||
B8 D191 ; # small yo
|
||||
B9 E28496 ; # numero sign
|
||||
BA D194 ; # small Ukrainian ye
|
||||
BB C2BB ; # right-pointing double angle quotation mark
|
||||
|
||||
BF D197 ; # small Ukrainian yi
|
||||
|
||||
C0 D090 ; # capital A
|
||||
C1 D091 ; # capital B
|
||||
C2 D092 ; # capital V
|
||||
C3 D093 ; # capital G
|
||||
C4 D094 ; # capital D
|
||||
C5 D095 ; # capital YE
|
||||
C6 D096 ; # capital ZH
|
||||
C7 D097 ; # capital Z
|
||||
C8 D098 ; # capital I
|
||||
C9 D099 ; # capital J
|
||||
CA D09A ; # capital K
|
||||
CB D09B ; # capital L
|
||||
CC D09C ; # capital M
|
||||
CD D09D ; # capital N
|
||||
CE D09E ; # capital O
|
||||
CF D09F ; # capital P
|
||||
|
||||
D0 D0A0 ; # capital R
|
||||
D1 D0A1 ; # capital S
|
||||
D2 D0A2 ; # capital T
|
||||
D3 D0A3 ; # capital U
|
||||
D4 D0A4 ; # capital F
|
||||
D5 D0A5 ; # capital KH
|
||||
D6 D0A6 ; # capital TS
|
||||
D7 D0A7 ; # capital CH
|
||||
D8 D0A8 ; # capital SH
|
||||
D9 D0A9 ; # capital SHCH
|
||||
DA D0AA ; # capital hard sign
|
||||
DB D0AB ; # capital Y
|
||||
DC D0AC ; # capital soft sign
|
||||
DD D0AD ; # capital E
|
||||
DE D0AE ; # capital YU
|
||||
DF D0AF ; # capital YA
|
||||
|
||||
E0 D0B0 ; # small a
|
||||
E1 D0B1 ; # small b
|
||||
E2 D0B2 ; # small v
|
||||
E3 D0B3 ; # small g
|
||||
E4 D0B4 ; # small d
|
||||
E5 D0B5 ; # small ye
|
||||
E6 D0B6 ; # small zh
|
||||
E7 D0B7 ; # small z
|
||||
E8 D0B8 ; # small i
|
||||
E9 D0B9 ; # small j
|
||||
EA D0BA ; # small k
|
||||
EB D0BB ; # small l
|
||||
EC D0BC ; # small m
|
||||
ED D0BD ; # small n
|
||||
EE D0BE ; # small o
|
||||
EF D0BF ; # small p
|
||||
|
||||
F0 D180 ; # small r
|
||||
F1 D181 ; # small s
|
||||
F2 D182 ; # small t
|
||||
F3 D183 ; # small u
|
||||
F4 D184 ; # small f
|
||||
F5 D185 ; # small kh
|
||||
F6 D186 ; # small ts
|
||||
F7 D187 ; # small ch
|
||||
F8 D188 ; # small sh
|
||||
F9 D189 ; # small shch
|
||||
FA D18A ; # small hard sign
|
||||
FB D18B ; # small y
|
||||
FC D18C ; # small soft sign
|
||||
FD D18D ; # small e
|
||||
FE D18E ; # small yu
|
||||
FF D18F ; # small ya
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
local request = require 'request'
|
||||
local response = require 'response'
|
||||
local helper = require 'helper'
|
||||
|
||||
local request_uri
|
||||
local response_type
|
||||
local domain
|
||||
local result
|
||||
local err
|
||||
local red = helper.redis.connect()
|
||||
|
||||
request_uri = helper.parseURL()
|
||||
if type(request_uri) ~= "table" or table.getn(request_uri) < 2 then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
local response_type = request_uri[2]
|
||||
if not response.isValidResponseType(response_type) then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
local data = request.getPostData()
|
||||
if data == nil or data['email'] == nil then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
domain = helper.getDomain(data['email'])
|
||||
if not domain then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
result = helper.redis.checkDomain(red, 'disposable', domain)
|
||||
|
||||
response.createResponse(response_type, data['email'], domain, result)
|
|
@ -0,0 +1,981 @@
|
|||
-- Copyright (C) Yichun Zhang (agentzh)
|
||||
|
||||
|
||||
-- local socket = require "socket"
|
||||
local bit = require "bit"
|
||||
local udp = ngx.socket.udp
|
||||
local rand = math.random
|
||||
local char = string.char
|
||||
local byte = string.byte
|
||||
local find = string.find
|
||||
local gsub = string.gsub
|
||||
local sub = string.sub
|
||||
local rep = string.rep
|
||||
local format = string.format
|
||||
local band = bit.band
|
||||
local rshift = bit.rshift
|
||||
local lshift = bit.lshift
|
||||
local insert = table.insert
|
||||
local concat = table.concat
|
||||
local re_sub = ngx.re.sub
|
||||
local tcp = ngx.socket.tcp
|
||||
local log = ngx.log
|
||||
local DEBUG = ngx.DEBUG
|
||||
local unpack = unpack
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
|
||||
|
||||
local ok, new_tab = pcall(require, "table.new")
|
||||
if not ok then
|
||||
new_tab = function (narr, nrec) return {} end
|
||||
end
|
||||
|
||||
|
||||
local DOT_CHAR = byte(".")
|
||||
local ZERO_CHAR = byte("0")
|
||||
local COLON_CHAR = byte(":")
|
||||
|
||||
local IP6_ARPA = "ip6.arpa"
|
||||
|
||||
local TYPE_A = 1
|
||||
local TYPE_NS = 2
|
||||
local TYPE_CNAME = 5
|
||||
local TYPE_SOA = 6
|
||||
local TYPE_PTR = 12
|
||||
local TYPE_MX = 15
|
||||
local TYPE_TXT = 16
|
||||
local TYPE_AAAA = 28
|
||||
local TYPE_SRV = 33
|
||||
local TYPE_SPF = 99
|
||||
|
||||
local CLASS_IN = 1
|
||||
|
||||
local SECTION_AN = 1
|
||||
local SECTION_NS = 2
|
||||
local SECTION_AR = 3
|
||||
|
||||
|
||||
local _M = {
|
||||
_VERSION = '0.21',
|
||||
TYPE_A = TYPE_A,
|
||||
TYPE_NS = TYPE_NS,
|
||||
TYPE_CNAME = TYPE_CNAME,
|
||||
TYPE_SOA = TYPE_SOA,
|
||||
TYPE_PTR = TYPE_PTR,
|
||||
TYPE_MX = TYPE_MX,
|
||||
TYPE_TXT = TYPE_TXT,
|
||||
TYPE_AAAA = TYPE_AAAA,
|
||||
TYPE_SRV = TYPE_SRV,
|
||||
TYPE_SPF = TYPE_SPF,
|
||||
CLASS_IN = CLASS_IN,
|
||||
SECTION_AN = SECTION_AN,
|
||||
SECTION_NS = SECTION_NS,
|
||||
SECTION_AR = SECTION_AR
|
||||
}
|
||||
|
||||
|
||||
local resolver_errstrs = {
|
||||
"format error", -- 1
|
||||
"server failure", -- 2
|
||||
"name error", -- 3
|
||||
"not implemented", -- 4
|
||||
"refused", -- 5
|
||||
}
|
||||
|
||||
local soa_int32_fields = { "serial", "refresh", "retry", "expire", "minimum" }
|
||||
|
||||
local mt = { __index = _M }
|
||||
|
||||
|
||||
local arpa_tmpl = new_tab(72, 0)
|
||||
|
||||
for i = 1, #IP6_ARPA do
|
||||
arpa_tmpl[64 + i] = byte(IP6_ARPA, i)
|
||||
end
|
||||
|
||||
for i = 2, 64, 2 do
|
||||
arpa_tmpl[i] = DOT_CHAR
|
||||
end
|
||||
|
||||
|
||||
function _M.new(class, opts)
|
||||
if not opts then
|
||||
return nil, "no options table specified"
|
||||
end
|
||||
|
||||
local servers = opts.nameservers
|
||||
if not servers or #servers == 0 then
|
||||
return nil, "no nameservers specified"
|
||||
end
|
||||
|
||||
local timeout = opts.timeout or 2000 -- default 2 sec
|
||||
|
||||
local n = #servers
|
||||
|
||||
local socks = {}
|
||||
|
||||
for i = 1, n do
|
||||
local server = servers[i]
|
||||
local sock, err = udp()
|
||||
if not sock then
|
||||
return nil, "failed to create udp socket: " .. err
|
||||
end
|
||||
|
||||
local host, port
|
||||
if type(server) == 'table' then
|
||||
host = server[1]
|
||||
port = server[2] or 53
|
||||
|
||||
else
|
||||
host = server
|
||||
port = 53
|
||||
servers[i] = {host, port}
|
||||
end
|
||||
|
||||
local ok, err = sock:setpeername(host, port)
|
||||
if not ok then
|
||||
return nil, "failed to set peer name: " .. err
|
||||
end
|
||||
|
||||
sock:settimeout(timeout)
|
||||
|
||||
insert(socks, sock)
|
||||
end
|
||||
|
||||
local tcp_sock, err = tcp()
|
||||
if not tcp_sock then
|
||||
return nil, "failed to create tcp socket: " .. err
|
||||
end
|
||||
|
||||
tcp_sock:settimeout(timeout)
|
||||
|
||||
return setmetatable(
|
||||
{ cur = rand(1, n), socks = socks,
|
||||
tcp_sock = tcp_sock,
|
||||
servers = servers,
|
||||
retrans = opts.retrans or 5,
|
||||
no_recurse = opts.no_recurse,
|
||||
}, mt)
|
||||
end
|
||||
|
||||
|
||||
local function pick_sock(self, socks)
|
||||
local cur = self.cur
|
||||
|
||||
if cur == #socks then
|
||||
self.cur = 1
|
||||
else
|
||||
self.cur = cur + 1
|
||||
end
|
||||
|
||||
return socks[cur]
|
||||
end
|
||||
|
||||
|
||||
local function _get_cur_server(self)
|
||||
local cur = self.cur
|
||||
|
||||
local servers = self.servers
|
||||
|
||||
if cur == 1 then
|
||||
return servers[#servers]
|
||||
end
|
||||
|
||||
return servers[cur - 1]
|
||||
end
|
||||
|
||||
|
||||
function _M.set_timeout(self, timeout)
|
||||
local socks = self.socks
|
||||
if not socks then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
for i = 1, #socks do
|
||||
local sock = socks[i]
|
||||
sock:settimeout(timeout)
|
||||
end
|
||||
|
||||
local tcp_sock = self.tcp_sock
|
||||
if not tcp_sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
tcp_sock:settimeout(timeout)
|
||||
end
|
||||
|
||||
|
||||
local function _encode_name(s)
|
||||
return char(#s) .. s
|
||||
end
|
||||
|
||||
|
||||
local function _decode_name(buf, pos)
|
||||
local labels = {}
|
||||
local nptrs = 0
|
||||
local p = pos
|
||||
while nptrs < 128 do
|
||||
local fst = byte(buf, p)
|
||||
|
||||
if not fst then
|
||||
return nil, 'truncated';
|
||||
end
|
||||
|
||||
-- print("fst at ", p, ": ", fst)
|
||||
|
||||
if fst == 0 then
|
||||
if nptrs == 0 then
|
||||
pos = pos + 1
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
if band(fst, 0xc0) ~= 0 then
|
||||
-- being a pointer
|
||||
if nptrs == 0 then
|
||||
pos = pos + 2
|
||||
end
|
||||
|
||||
nptrs = nptrs + 1
|
||||
|
||||
local snd = byte(buf, p + 1)
|
||||
if not snd then
|
||||
return nil, 'truncated'
|
||||
end
|
||||
|
||||
p = lshift(band(fst, 0x3f), 8) + snd + 1
|
||||
|
||||
-- print("resolving ptr ", p, ": ", byte(buf, p))
|
||||
|
||||
else
|
||||
-- being a label
|
||||
local label = sub(buf, p + 1, p + fst)
|
||||
insert(labels, label)
|
||||
|
||||
-- print("resolved label ", label)
|
||||
|
||||
p = p + fst + 1
|
||||
|
||||
if nptrs == 0 then
|
||||
pos = p
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return concat(labels, "."), pos
|
||||
end
|
||||
|
||||
|
||||
local function _build_request(qname, id, no_recurse, opts)
|
||||
local qtype
|
||||
|
||||
if opts then
|
||||
qtype = opts.qtype
|
||||
end
|
||||
|
||||
if not qtype then
|
||||
qtype = 1 -- A record
|
||||
end
|
||||
|
||||
local ident_hi = char(rshift(id, 8))
|
||||
local ident_lo = char(band(id, 0xff))
|
||||
|
||||
local flags
|
||||
if no_recurse then
|
||||
-- print("found no recurse")
|
||||
flags = "\0\0"
|
||||
else
|
||||
flags = "\1\0"
|
||||
end
|
||||
|
||||
local nqs = "\0\1"
|
||||
local nan = "\0\0"
|
||||
local nns = "\0\0"
|
||||
local nar = "\0\0"
|
||||
local typ = char(rshift(qtype, 8), band(qtype, 0xff))
|
||||
local class = "\0\1" -- the Internet class
|
||||
|
||||
if byte(qname, 1) == DOT_CHAR then
|
||||
return nil, "bad name"
|
||||
end
|
||||
|
||||
local name = gsub(qname, "([^.]+)%.?", _encode_name) .. '\0'
|
||||
|
||||
return {
|
||||
ident_hi, ident_lo, flags, nqs, nan, nns, nar,
|
||||
name, typ, class
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
local function parse_section(answers, section, buf, start_pos, size,
|
||||
should_skip)
|
||||
local pos = start_pos
|
||||
|
||||
for _ = 1, size do
|
||||
-- print(format("ans %d: qtype:%d qclass:%d", i, qtype, qclass))
|
||||
local ans = {}
|
||||
|
||||
if not should_skip then
|
||||
insert(answers, ans)
|
||||
end
|
||||
|
||||
ans.section = section
|
||||
|
||||
local name
|
||||
name, pos = _decode_name(buf, pos)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
ans.name = name
|
||||
|
||||
-- print("name: ", name)
|
||||
|
||||
local type_hi = byte(buf, pos)
|
||||
local type_lo = byte(buf, pos + 1)
|
||||
local typ = lshift(type_hi, 8) + type_lo
|
||||
|
||||
ans.type = typ
|
||||
|
||||
-- print("type: ", typ)
|
||||
|
||||
local class_hi = byte(buf, pos + 2)
|
||||
local class_lo = byte(buf, pos + 3)
|
||||
local class = lshift(class_hi, 8) + class_lo
|
||||
|
||||
ans.class = class
|
||||
|
||||
-- print("class: ", class)
|
||||
|
||||
local byte_1, byte_2, byte_3, byte_4 = byte(buf, pos + 4, pos + 7)
|
||||
|
||||
local ttl = lshift(byte_1, 24) + lshift(byte_2, 16)
|
||||
+ lshift(byte_3, 8) + byte_4
|
||||
|
||||
-- print("ttl: ", ttl)
|
||||
|
||||
ans.ttl = ttl
|
||||
|
||||
local len_hi = byte(buf, pos + 8)
|
||||
local len_lo = byte(buf, pos + 9)
|
||||
local len = lshift(len_hi, 8) + len_lo
|
||||
|
||||
-- print("record len: ", len)
|
||||
|
||||
pos = pos + 10
|
||||
|
||||
if typ == TYPE_A then
|
||||
|
||||
if len ~= 4 then
|
||||
return nil, "bad A record value length: " .. len
|
||||
end
|
||||
|
||||
local addr_bytes = { byte(buf, pos, pos + 3) }
|
||||
local addr = concat(addr_bytes, ".")
|
||||
-- print("ipv4 address: ", addr)
|
||||
|
||||
ans.address = addr
|
||||
|
||||
pos = pos + 4
|
||||
|
||||
elseif typ == TYPE_CNAME then
|
||||
|
||||
local cname, p = _decode_name(buf, pos)
|
||||
if not cname then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
if p - pos ~= len then
|
||||
return nil, format("bad cname record length: %d ~= %d",
|
||||
p - pos, len)
|
||||
end
|
||||
|
||||
pos = p
|
||||
|
||||
-- print("cname: ", cname)
|
||||
|
||||
ans.cname = cname
|
||||
|
||||
elseif typ == TYPE_AAAA then
|
||||
|
||||
if len ~= 16 then
|
||||
return nil, "bad AAAA record value length: " .. len
|
||||
end
|
||||
|
||||
local addr_bytes = { byte(buf, pos, pos + 15) }
|
||||
local flds = {}
|
||||
for i = 1, 16, 2 do
|
||||
local a = addr_bytes[i]
|
||||
local b = addr_bytes[i + 1]
|
||||
if a == 0 then
|
||||
insert(flds, format("%x", b))
|
||||
|
||||
else
|
||||
insert(flds, format("%x%02x", a, b))
|
||||
end
|
||||
end
|
||||
|
||||
-- we do not compress the IPv6 addresses by default
|
||||
-- due to performance considerations
|
||||
|
||||
ans.address = concat(flds, ":")
|
||||
|
||||
pos = pos + 16
|
||||
|
||||
elseif typ == TYPE_MX then
|
||||
|
||||
-- print("len = ", len)
|
||||
|
||||
if len < 3 then
|
||||
return nil, "bad MX record value length: " .. len
|
||||
end
|
||||
|
||||
local pref_hi = byte(buf, pos)
|
||||
local pref_lo = byte(buf, pos + 1)
|
||||
|
||||
ans.preference = lshift(pref_hi, 8) + pref_lo
|
||||
|
||||
local host, p = _decode_name(buf, pos + 2)
|
||||
if not host then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
if p - pos ~= len then
|
||||
return nil, format("bad cname record length: %d ~= %d",
|
||||
p - pos, len)
|
||||
end
|
||||
|
||||
ans.exchange = host
|
||||
|
||||
pos = p
|
||||
|
||||
elseif typ == TYPE_SRV then
|
||||
if len < 7 then
|
||||
return nil, "bad SRV record value length: " .. len
|
||||
end
|
||||
|
||||
local prio_hi = byte(buf, pos)
|
||||
local prio_lo = byte(buf, pos + 1)
|
||||
ans.priority = lshift(prio_hi, 8) + prio_lo
|
||||
|
||||
local weight_hi = byte(buf, pos + 2)
|
||||
local weight_lo = byte(buf, pos + 3)
|
||||
ans.weight = lshift(weight_hi, 8) + weight_lo
|
||||
|
||||
local port_hi = byte(buf, pos + 4)
|
||||
local port_lo = byte(buf, pos + 5)
|
||||
ans.port = lshift(port_hi, 8) + port_lo
|
||||
|
||||
local name, p = _decode_name(buf, pos + 6)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
if p - pos ~= len then
|
||||
return nil, format("bad srv record length: %d ~= %d",
|
||||
p - pos, len)
|
||||
end
|
||||
|
||||
ans.target = name
|
||||
|
||||
pos = p
|
||||
|
||||
elseif typ == TYPE_NS then
|
||||
|
||||
local name, p = _decode_name(buf, pos)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
if p - pos ~= len then
|
||||
return nil, format("bad cname record length: %d ~= %d",
|
||||
p - pos, len)
|
||||
end
|
||||
|
||||
pos = p
|
||||
|
||||
-- print("name: ", name)
|
||||
|
||||
ans.nsdname = name
|
||||
|
||||
elseif typ == TYPE_TXT or typ == TYPE_SPF then
|
||||
|
||||
local key = (typ == TYPE_TXT) and "txt" or "spf"
|
||||
|
||||
local slen = byte(buf, pos)
|
||||
if slen + 1 > len then
|
||||
-- truncate the over-run TXT record data
|
||||
slen = len
|
||||
end
|
||||
|
||||
-- print("slen: ", len)
|
||||
|
||||
local val = sub(buf, pos + 1, pos + slen)
|
||||
local last = pos + len
|
||||
pos = pos + slen + 1
|
||||
|
||||
if pos < last then
|
||||
-- more strings to be processed
|
||||
-- this code path is usually cold, so we do not
|
||||
-- merge the following loop on this code path
|
||||
-- with the processing logic above.
|
||||
|
||||
val = {val}
|
||||
local idx = 2
|
||||
repeat
|
||||
local slen = byte(buf, pos)
|
||||
if pos + slen + 1 > last then
|
||||
-- truncate the over-run TXT record data
|
||||
slen = last - pos - 1
|
||||
end
|
||||
|
||||
val[idx] = sub(buf, pos + 1, pos + slen)
|
||||
idx = idx + 1
|
||||
pos = pos + slen + 1
|
||||
|
||||
until pos >= last
|
||||
end
|
||||
|
||||
ans[key] = val
|
||||
|
||||
elseif typ == TYPE_PTR then
|
||||
|
||||
local name, p = _decode_name(buf, pos)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
if p - pos ~= len then
|
||||
return nil, format("bad cname record length: %d ~= %d",
|
||||
p - pos, len)
|
||||
end
|
||||
|
||||
pos = p
|
||||
|
||||
-- print("name: ", name)
|
||||
|
||||
ans.ptrdname = name
|
||||
|
||||
elseif typ == TYPE_SOA then
|
||||
local name, p = _decode_name(buf, pos)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
ans.mname = name
|
||||
|
||||
pos = p
|
||||
name, p = _decode_name(buf, pos)
|
||||
if not name then
|
||||
return nil, pos
|
||||
end
|
||||
ans.rname = name
|
||||
|
||||
for _, field in ipairs(soa_int32_fields) do
|
||||
local byte_1, byte_2, byte_3, byte_4 = byte(buf, p, p + 3)
|
||||
ans[field] = lshift(byte_1, 24) + lshift(byte_2, 16)
|
||||
+ lshift(byte_3, 8) + byte_4
|
||||
p = p + 4
|
||||
end
|
||||
|
||||
pos = p
|
||||
|
||||
else
|
||||
-- for unknown types, just forward the raw value
|
||||
|
||||
ans.rdata = sub(buf, pos, pos + len - 1)
|
||||
pos = pos + len
|
||||
end
|
||||
end
|
||||
|
||||
return pos
|
||||
end
|
||||
|
||||
|
||||
local function parse_response(buf, id, opts)
|
||||
local n = #buf
|
||||
if n < 12 then
|
||||
return nil, 'truncated';
|
||||
end
|
||||
|
||||
-- header layout: ident flags nqs nan nns nar
|
||||
|
||||
local ident_hi = byte(buf, 1)
|
||||
local ident_lo = byte(buf, 2)
|
||||
local ans_id = lshift(ident_hi, 8) + ident_lo
|
||||
|
||||
-- print("id: ", id, ", ans id: ", ans_id)
|
||||
|
||||
if ans_id ~= id then
|
||||
-- identifier mismatch and throw it away
|
||||
log(DEBUG, "id mismatch in the DNS reply: ", ans_id, " ~= ", id)
|
||||
return nil, "id mismatch"
|
||||
end
|
||||
|
||||
local flags_hi = byte(buf, 3)
|
||||
local flags_lo = byte(buf, 4)
|
||||
local flags = lshift(flags_hi, 8) + flags_lo
|
||||
|
||||
-- print(format("flags: 0x%x", flags))
|
||||
|
||||
if band(flags, 0x8000) == 0 then
|
||||
return nil, format("bad QR flag in the DNS response")
|
||||
end
|
||||
|
||||
if band(flags, 0x200) ~= 0 then
|
||||
return nil, "truncated"
|
||||
end
|
||||
|
||||
local code = band(flags, 0xf)
|
||||
|
||||
-- print(format("code: %d", code))
|
||||
|
||||
local nqs_hi = byte(buf, 5)
|
||||
local nqs_lo = byte(buf, 6)
|
||||
local nqs = lshift(nqs_hi, 8) + nqs_lo
|
||||
|
||||
-- print("nqs: ", nqs)
|
||||
|
||||
if nqs ~= 1 then
|
||||
return nil, format("bad number of questions in DNS response: %d", nqs)
|
||||
end
|
||||
|
||||
local nan_hi = byte(buf, 7)
|
||||
local nan_lo = byte(buf, 8)
|
||||
local nan = lshift(nan_hi, 8) + nan_lo
|
||||
|
||||
-- print("nan: ", nan)
|
||||
|
||||
local nns_hi = byte(buf, 9)
|
||||
local nns_lo = byte(buf, 10)
|
||||
local nns = lshift(nns_hi, 8) + nns_lo
|
||||
|
||||
local nar_hi = byte(buf, 11)
|
||||
local nar_lo = byte(buf, 12)
|
||||
local nar = lshift(nar_hi, 8) + nar_lo
|
||||
|
||||
-- skip the question part
|
||||
|
||||
local ans_qname, pos = _decode_name(buf, 13)
|
||||
if not ans_qname then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
-- print("qname in reply: ", ans_qname)
|
||||
|
||||
-- print("question: ", sub(buf, 13, pos))
|
||||
|
||||
if pos + 3 + nan * 12 > n then
|
||||
-- print(format("%d > %d", pos + 3 + nan * 12, n))
|
||||
return nil, 'truncated';
|
||||
end
|
||||
|
||||
-- question section layout: qname qtype(2) qclass(2)
|
||||
|
||||
--[[
|
||||
local type_hi = byte(buf, pos)
|
||||
local type_lo = byte(buf, pos + 1)
|
||||
local ans_type = lshift(type_hi, 8) + type_lo
|
||||
]]
|
||||
|
||||
-- print("ans qtype: ", ans_type)
|
||||
|
||||
local class_hi = byte(buf, pos + 2)
|
||||
local class_lo = byte(buf, pos + 3)
|
||||
local qclass = lshift(class_hi, 8) + class_lo
|
||||
|
||||
-- print("ans qclass: ", qclass)
|
||||
|
||||
if qclass ~= 1 then
|
||||
return nil, format("unknown query class %d in DNS response", qclass)
|
||||
end
|
||||
|
||||
pos = pos + 4
|
||||
|
||||
local answers = {}
|
||||
|
||||
if code ~= 0 then
|
||||
answers.errcode = code
|
||||
answers.errstr = resolver_errstrs[code] or "unknown"
|
||||
end
|
||||
|
||||
local authority_section, additional_section
|
||||
|
||||
if opts then
|
||||
authority_section = opts.authority_section
|
||||
additional_section = opts.additional_section
|
||||
if opts.qtype == TYPE_SOA then
|
||||
authority_section = true
|
||||
end
|
||||
end
|
||||
|
||||
local err
|
||||
|
||||
pos, err = parse_section(answers, SECTION_AN, buf, pos, nan)
|
||||
|
||||
if not pos then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if not authority_section and not additional_section then
|
||||
return answers
|
||||
end
|
||||
|
||||
pos, err = parse_section(answers, SECTION_NS, buf, pos, nns,
|
||||
not authority_section)
|
||||
|
||||
if not pos then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if not additional_section then
|
||||
return answers
|
||||
end
|
||||
|
||||
pos, err = parse_section(answers, SECTION_AR, buf, pos, nar)
|
||||
|
||||
if not pos then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return answers
|
||||
end
|
||||
|
||||
|
||||
local function _gen_id(self)
|
||||
local id = self._id -- for regression testing
|
||||
if id then
|
||||
return id
|
||||
end
|
||||
return rand(0, 65535) -- two bytes
|
||||
end
|
||||
|
||||
|
||||
local function _tcp_query(self, query, id, opts)
|
||||
local sock = self.tcp_sock
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
log(DEBUG, "query the TCP server due to reply truncation")
|
||||
|
||||
local server = _get_cur_server(self)
|
||||
|
||||
local ok, err = sock:connect(server[1], server[2])
|
||||
if not ok then
|
||||
return nil, "failed to connect to TCP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
end
|
||||
|
||||
query = concat(query, "")
|
||||
local len = #query
|
||||
|
||||
local len_hi = char(rshift(len, 8))
|
||||
local len_lo = char(band(len, 0xff))
|
||||
|
||||
local bytes, err = sock:send({len_hi, len_lo, query})
|
||||
if not bytes then
|
||||
return nil, "failed to send query to TCP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
end
|
||||
|
||||
local buf, err = sock:receive(2)
|
||||
if not buf then
|
||||
return nil, "failed to receive the reply length field from TCP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
end
|
||||
|
||||
len_hi = byte(buf, 1)
|
||||
len_lo = byte(buf, 2)
|
||||
len = lshift(len_hi, 8) + len_lo
|
||||
|
||||
-- print("tcp message len: ", len)
|
||||
|
||||
buf, err = sock:receive(len)
|
||||
if not buf then
|
||||
return nil, "failed to receive the reply message body from TCP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
end
|
||||
|
||||
local answers, err = parse_response(buf, id, opts)
|
||||
if not answers then
|
||||
return nil, "failed to parse the reply from the TCP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
end
|
||||
|
||||
sock:close()
|
||||
|
||||
return answers
|
||||
end
|
||||
|
||||
|
||||
function _M.tcp_query(self, qname, opts)
|
||||
local socks = self.socks
|
||||
if not socks then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
pick_sock(self, socks)
|
||||
|
||||
local id = _gen_id(self)
|
||||
|
||||
local query, err = _build_request(qname, id, self.no_recurse, opts)
|
||||
if not query then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return _tcp_query(self, query, id, opts)
|
||||
end
|
||||
|
||||
|
||||
function _M.query(self, qname, opts, tries)
|
||||
local socks = self.socks
|
||||
if not socks then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
local id = _gen_id(self)
|
||||
|
||||
local query, err = _build_request(qname, id, self.no_recurse, opts)
|
||||
if not query then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
-- local cjson = require "cjson"
|
||||
-- print("query: ", cjson.encode(concat(query, "")))
|
||||
|
||||
local retrans = self.retrans
|
||||
if tries then
|
||||
tries[1] = nil
|
||||
end
|
||||
|
||||
-- print("retrans: ", retrans)
|
||||
|
||||
for i = 1, retrans do
|
||||
local sock = pick_sock(self, socks)
|
||||
|
||||
local ok
|
||||
ok, err = sock:send(query)
|
||||
if not ok then
|
||||
local server = _get_cur_server(self)
|
||||
err = "failed to send request to UDP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
|
||||
else
|
||||
local buf
|
||||
|
||||
for _ = 1, 128 do
|
||||
buf, err = sock:receive(4096)
|
||||
if err then
|
||||
local server = _get_cur_server(self)
|
||||
err = "failed to receive reply from UDP server "
|
||||
.. concat(server, ":") .. ": " .. err
|
||||
break
|
||||
end
|
||||
|
||||
if buf then
|
||||
local answers
|
||||
answers, err = parse_response(buf, id, opts)
|
||||
if err == "truncated" then
|
||||
answers, err = _tcp_query(self, query, id, opts)
|
||||
end
|
||||
|
||||
if err and err ~= "id mismatch" then
|
||||
break
|
||||
end
|
||||
|
||||
if answers then
|
||||
return answers, nil, tries
|
||||
end
|
||||
end
|
||||
-- only here in case of an "id mismatch"
|
||||
end
|
||||
end
|
||||
|
||||
if tries then
|
||||
tries[i] = err
|
||||
tries[i + 1] = nil -- ensure termination for user supplied table
|
||||
end
|
||||
end
|
||||
|
||||
return nil, err, tries
|
||||
end
|
||||
|
||||
|
||||
function _M.compress_ipv6_addr(addr)
|
||||
local addr = re_sub(addr, "^(0:)+|(:0)+$|:(0:)+", "::", "jo")
|
||||
if addr == "::0" then
|
||||
addr = "::"
|
||||
end
|
||||
|
||||
return addr
|
||||
end
|
||||
|
||||
|
||||
local function _expand_ipv6_addr(addr)
|
||||
if find(addr, "::", 1, true) then
|
||||
local ncol, addrlen = 8, #addr
|
||||
|
||||
for i = 1, addrlen do
|
||||
if byte(addr, i) == COLON_CHAR then
|
||||
ncol = ncol - 1
|
||||
end
|
||||
end
|
||||
|
||||
if byte(addr, 1) == COLON_CHAR then
|
||||
addr = "0" .. addr
|
||||
end
|
||||
|
||||
if byte(addr, -1) == COLON_CHAR then
|
||||
addr = addr .. "0"
|
||||
end
|
||||
|
||||
addr = re_sub(addr, "::", ":" .. rep("0:", ncol), "jo")
|
||||
end
|
||||
|
||||
return addr
|
||||
end
|
||||
|
||||
|
||||
_M.expand_ipv6_addr = _expand_ipv6_addr
|
||||
|
||||
|
||||
function _M.arpa_str(addr)
|
||||
if find(addr, ":", 1, true) then
|
||||
addr = _expand_ipv6_addr(addr)
|
||||
local idx, hidx, addrlen = 1, 1, #addr
|
||||
|
||||
for i = addrlen, 0, -1 do
|
||||
local s = byte(addr, i)
|
||||
if s == COLON_CHAR or not s then
|
||||
for _ = hidx, 4 do
|
||||
arpa_tmpl[idx] = ZERO_CHAR
|
||||
idx = idx + 2
|
||||
end
|
||||
hidx = 1
|
||||
else
|
||||
arpa_tmpl[idx] = s
|
||||
idx = idx + 2
|
||||
hidx = hidx + 1
|
||||
end
|
||||
end
|
||||
|
||||
addr = char(unpack(arpa_tmpl))
|
||||
else
|
||||
addr = re_sub(addr, [[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})]],
|
||||
"$4.$3.$2.$1.in-addr.arpa", "ajo")
|
||||
end
|
||||
|
||||
return addr
|
||||
end
|
||||
|
||||
|
||||
function _M.reverse_query(self, addr)
|
||||
return self.query(self, self.arpa_str(addr),
|
||||
{qtype = self.TYPE_PTR})
|
||||
end
|
||||
|
||||
|
||||
return _M
|
|
@ -0,0 +1,60 @@
|
|||
local json = require 'json'
|
||||
local redis = require 'redis'
|
||||
local response = require 'response'
|
||||
|
||||
local module = {
|
||||
['redis'] = {}
|
||||
}
|
||||
|
||||
module.redis.connect = function()
|
||||
local red = redis:new();
|
||||
red:set_timeout(1000);
|
||||
local ok, err = red:connect('redis', 6379)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, err)
|
||||
response.quit(ngx.HTTP_SERVICE_UNAVAILABLE)
|
||||
return
|
||||
end
|
||||
|
||||
return red
|
||||
end
|
||||
|
||||
module.redis.checkDomain = function(red, category, domain)
|
||||
local result, err = red:hmget(category, domain)
|
||||
if err then
|
||||
ngx.log(ngx.ERR, err)
|
||||
response.quit(ngx.HTTP_SERVICE_UNAVAILABLE)
|
||||
return
|
||||
end
|
||||
return type(result) == 'string' and true or false
|
||||
end
|
||||
|
||||
local function split(str, pat)
|
||||
local t = {}
|
||||
local fpat = "(.-)" .. pat
|
||||
local last_end = 1
|
||||
local s, e, cap = str:find(fpat, 1)
|
||||
while s do
|
||||
if s ~= 1 or cap ~= "" then
|
||||
table.insert(t,cap)
|
||||
end
|
||||
last_end = e+1
|
||||
s, e, cap = str:find(fpat, last_end)
|
||||
end
|
||||
if last_end <= #str then
|
||||
cap = str:sub(last_end)
|
||||
table.insert(t, cap)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
module.parseURL = function(uri)
|
||||
local uri = uri or ngx.var.request_uri
|
||||
return split(uri, '[\\/]+')
|
||||
end
|
||||
|
||||
module.getDomain = function(str)
|
||||
return string.match(str, '%w+%.%w+$')
|
||||
end
|
||||
|
||||
return module
|
|
@ -0,0 +1,504 @@
|
|||
--
|
||||
-- IP address manipulation library in Lua
|
||||
--
|
||||
-- @author leite (xico@simbio.se)
|
||||
-- @license MIT
|
||||
-- @copyright Simbiose 2015
|
||||
|
||||
local math, string, table, bit_available, bit =
|
||||
require [[math]], require [[string]], require [[table]], pcall(require, 'bit')
|
||||
|
||||
-- yey! Lua 5.3 bitwise keywords available
|
||||
if not bit_available and _VERSION == 'Lua 5.3' then
|
||||
bit = assert(load([[return {
|
||||
band = function (a, b) return a & b end,
|
||||
bor = function (a, b) return a | b end,
|
||||
rshift = function (a, b) return a >> b end,
|
||||
lshift = function (a, b) return a << b end
|
||||
}]]))()
|
||||
end
|
||||
|
||||
local ip, modf, len, match, find, format, concat, insert, band, bor, rshift, lshift, type,
|
||||
assert, error, tonumber, pcall, setmetatable =
|
||||
{}, math.modf, string.len, string.match, string.find, string.format, table.concat, table.insert,
|
||||
bit.band, bit.bor, bit.rshift, bit.lshift, type, assert, error, tonumber, pcall, setmetatable
|
||||
|
||||
local _octets, _octet, _part, _parts_with_octets, EMPTY, COLON, ZERO =
|
||||
'^((0?[xX]?)[%da-fA-F]+)%.((0?[xX]?)[%da-fA-F]+)%.((0?[xX]?)[%da-fA-F]+)%.((0?[xX]?)[%da-fA-F]+)/?(%d*)$',
|
||||
'^((0?[xX]?)[%da-fA-F]+)((/?)(%d*))$', '(:?)([^:/$]*)(:?)',
|
||||
'^([:%dxXa-fA-F]-::?)(([%dxXa-fA-F]*)[%.%dxXa-fA-F]*)/?(%d*)$', '', ':', '0'
|
||||
|
||||
math, string, bit, table = nil, nil, nil, nil
|
||||
|
||||
-- IP special ranges
|
||||
|
||||
local special_ranges = {
|
||||
ipv4 = {
|
||||
{'unspecified', octets={0, 0, 0, 0}, _cidr=8},
|
||||
{'broadcast', octets={255, 255, 255, 255}, _cidr=32},
|
||||
{'multicast', octets={224, 0, 0, 0}, _cidr=4},
|
||||
{'linkLocal', octets={169, 254, 0, 0}, _cidr=16},
|
||||
{'loopback', octets={127, 0, 0, 0}, _cidr=8},
|
||||
{
|
||||
'private', {octets={10, 0, 0, 0}, _cidr=8}, {octets={172, 16, 0, 0}, _cidr=12},
|
||||
{octets={192, 168, 0, 0}, _cidr=16}
|
||||
}, {
|
||||
'reserved', {octets={192, 0, 0, 0}, _cidr=24}, {octets={192, 0, 2, 0}, _cidr=24},
|
||||
{octets={192, 88, 99, 0}, _cidr=24}, {octets={198, 51, 100, 0}, _cidr=24},
|
||||
{octets={203, 0, 113, 0}, _cidr=24}, {octets={240, 0, 0, 0}, _cidr=4}
|
||||
}
|
||||
}, ipv6 = {
|
||||
{'unspecified', parts={0, 0, 0, 0, 0, 0, 0, 0}, _cidr=128},
|
||||
{'linkLocal', parts={0xfe80, 0, 0, 0, 0, 0, 0, 0}, _cidr=10},
|
||||
{'multicast', parts={0xff00, 0, 0, 0, 0, 0, 0, 0}, _cidr=8},
|
||||
{'loopback', parts={0, 0, 0, 0, 0, 0, 0, 1}, _cidr=128},
|
||||
{'uniqueLocal', parts={0xfc00, 0, 0, 0, 0, 0, 0, 0}, _cidr=7},
|
||||
{'ipv4Mapped', parts={0, 0, 0, 0, 0, 0xffff, 0, 0}, _cidr=96},
|
||||
{'rfc6145', parts={0, 0, 0, 0, 0xffff, 0, 0, 0}, _cidr=96},
|
||||
{'rfc6052', parts={0x64, 0xff9b, 0, 0, 0, 0, 0, 0}, _cidr=96},
|
||||
{'6to4', parts={0x2002, 0, 0, 0, 0, 0, 0, 0}, _cidr=16},
|
||||
{'teredo', parts={0x2001, 0, 0, 0, 0, 0, 0, 0}, _cidr=32},
|
||||
{'reserved', parts={0x2001, 0xdb8, 0, 0, 0, 0, 0, 0}, _cidr=32}
|
||||
}
|
||||
}
|
||||
|
||||
-- assert ipv4 octets
|
||||
--
|
||||
-- @table octets
|
||||
-- @return boolean, [string]
|
||||
|
||||
local function assert_ipv4 (octets)
|
||||
if not(octets and type(octets) == 'table') then
|
||||
return false, 'octets should be a table'
|
||||
end
|
||||
if not(#octets == 4) then
|
||||
return false, 'ipv4 octet count should be 4'
|
||||
end
|
||||
if not((-1 < octets[1] and 256 > octets[1]) and (-1 < octets[2] and 256 > octets[2]) and
|
||||
(-1 < octets[3] and 256 > octets[3]) and (-1 < octets[4] and 256 > octets[4])) then
|
||||
return false, 'ipv4 octet is a byte'
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- assert ipv6 parts
|
||||
--
|
||||
-- @table parts
|
||||
-- @return boolean, [string]
|
||||
|
||||
local function assert_ipv6 (parts)
|
||||
if not(parts and type(parts) == 'table') then
|
||||
return false, 'parts should be a table'
|
||||
end
|
||||
if not(#parts == 8) then
|
||||
return false, 'ipv6 part count should be 8'
|
||||
end
|
||||
if not((-1 < parts[1] and 0x10000 > parts[1]) and (-1 < parts[2] and 0x10000 > parts[2]) and
|
||||
(-1 < parts[3] and 0x10000 > parts[3]) and (-1 < parts[4] and 0x10000 > parts[4]) and
|
||||
(-1 < parts[5] and 0x10000 > parts[5]) and (-1 < parts[6] and 0x10000 > parts[6]) and
|
||||
(-1 < parts[7] and 0x10000 > parts[7]) and (-1 < parts[8] and 0x10000 > parts[8])) then
|
||||
return false, 'ipv6 part should fit to two octets'
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- generic CIDR matcher
|
||||
--
|
||||
-- @table first
|
||||
-- @table second
|
||||
-- @number part_size
|
||||
-- @number cidr_bits
|
||||
-- @return boolean
|
||||
|
||||
local function match_cidr(first, second, part_size, cidr_bits)
|
||||
assert(#first == #second, 'cannot match CIDR for objects with different lengths')
|
||||
local part, shift = 0, 0
|
||||
while cidr_bits > 0 do
|
||||
part = part + 1
|
||||
shift = part_size - cidr_bits
|
||||
shift = shift < 0 and 0 or shift
|
||||
if rshift(first[part], shift) ~= rshift(second[part], shift) then
|
||||
return false
|
||||
end
|
||||
cidr_bits = cidr_bits - part_size
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- funct address named range matching
|
||||
--
|
||||
-- @table address
|
||||
-- @table range_list
|
||||
-- @string default_name
|
||||
-- @return string
|
||||
|
||||
local function subnet_match(address, range_list, default_name)
|
||||
local subnet = {}
|
||||
for i = 1, #range_list do
|
||||
subnet = range_list[i]
|
||||
if #subnet == 1 then
|
||||
if address:match(subnet) then
|
||||
return subnet[1]
|
||||
end
|
||||
else
|
||||
for j = 2, #subnet do
|
||||
if address:match(subnet[j]) then
|
||||
return subnet[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return default_name or 'unicast'
|
||||
end
|
||||
|
||||
-- parse IP version 4
|
||||
--
|
||||
-- @string string
|
||||
-- @table octets
|
||||
-- @number cidr
|
||||
-- @return boolean, [string]
|
||||
|
||||
local function parse_v4(string, octets, cidr)
|
||||
local value, hex, _, __, _cidr = match(string, _octet)
|
||||
|
||||
if value then
|
||||
value = tonumber(value, hex == ZERO and 8 or nil)
|
||||
if value > 0xffffffff or value < 0 then
|
||||
return false, 'address outside defined range'
|
||||
end
|
||||
octets[1], octets[2], octets[3], octets[4] =
|
||||
band(rshift(value, 24), 0xff), band(rshift(value, 16), 0xff),
|
||||
band(rshift(value, 8), 0xff), band(value, 0xff)
|
||||
return tonumber(_cidr == EMPTY and 32 or _cidr)
|
||||
end
|
||||
|
||||
local st, _st, nd, _nd, rd, _rd, th, _th, _cidr = match(string, _octets)
|
||||
|
||||
if not(st) then
|
||||
return false, 'invalid ip address'
|
||||
end
|
||||
|
||||
octets[1], octets[2], octets[3], octets[4] =
|
||||
tonumber(st, _st == ZERO and 8 or nil), tonumber(nd, _nd == ZERO and 8 or nil),
|
||||
tonumber(rd, _rd == ZERO and 8 or nil), tonumber(th, _th == ZERO and 8 or nil)
|
||||
return tonumber(_cidr == EMPTY and (cidr and cidr or 32) or _cidr)
|
||||
end
|
||||
|
||||
-- parse IP version 6
|
||||
--
|
||||
-- @string string
|
||||
-- @table parts
|
||||
-- @table octets
|
||||
-- @number cidr
|
||||
-- @return boolean, [string]
|
||||
|
||||
local function parse_v6(string, parts, octets, cidr)
|
||||
local nd_sep, part, l_sep, count, double, length, index, last, string, octets_st, sep, _cidr =
|
||||
'', '', false, 1, 0, 0, 0, 0, match(string, _parts_with_octets)
|
||||
|
||||
if not string or EMPTY == string then
|
||||
return false, 'invalid ipv6 format'
|
||||
end
|
||||
|
||||
if #octets_st == #sep then
|
||||
string = string .. sep
|
||||
else
|
||||
local err, message = parse_v4(octets_st, octets)
|
||||
if not err then
|
||||
return err, message
|
||||
end
|
||||
end
|
||||
|
||||
_cidr, length, index, last, sep, part, nd_sep =
|
||||
tonumber(_cidr==EMPTY and (cidr and cidr or 128) or _cidr), len(string), find(string, _part)
|
||||
|
||||
while index and index <= length do
|
||||
if sep == COLON and nd_sep == COLON then
|
||||
if part == EMPTY or l_sep then
|
||||
if double > 0 then
|
||||
return false, 'string is not formatted like ip address'
|
||||
end
|
||||
double = count
|
||||
end
|
||||
elseif sep == COLON or nd_sep == COLON then
|
||||
if l_sep and sep == COLON then
|
||||
if double > 0 then
|
||||
return false, 'string is not formatted like ip address'
|
||||
end
|
||||
double = count
|
||||
end
|
||||
end
|
||||
|
||||
insert(parts, tonumber(part == EMPTY and '0' or part, 16))
|
||||
|
||||
l_sep, count, index, last, sep, part, nd_sep =
|
||||
nd_sep == COLON, count + 1, find(string, _part, last + 1)
|
||||
end
|
||||
|
||||
if #octets > 0 then
|
||||
insert(parts, bor(lshift(octets[1], 8), octets[2]))
|
||||
insert(parts, bor(lshift(octets[3], 8), octets[4]))
|
||||
length = 7
|
||||
else
|
||||
length = 9
|
||||
end
|
||||
|
||||
for index = 1, (length - count) do
|
||||
insert(parts, double, 0)
|
||||
end
|
||||
|
||||
return _cidr
|
||||
end
|
||||
|
||||
-- ip metatable
|
||||
|
||||
local ip_metatable = {
|
||||
|
||||
-- set CIDR
|
||||
--
|
||||
-- @number cidr
|
||||
-- @return metatable
|
||||
|
||||
cidr = function(self, cidr)
|
||||
self._cidr = cidr
|
||||
return self
|
||||
end,
|
||||
|
||||
-- get address named range
|
||||
--
|
||||
-- @return string
|
||||
|
||||
range = function(self)
|
||||
return subnet_match(self, special_ranges[self:kind()])
|
||||
end,
|
||||
|
||||
-- get or match address kind
|
||||
--
|
||||
-- @string [kind]
|
||||
-- @return string|boolean
|
||||
|
||||
kind = function(self, kind)
|
||||
local _kind = #self.parts > 0 and 'ipv6' or (#self.octets > 0 and 'ipv4' or EMPTY)
|
||||
if kind then
|
||||
return kind == _kind
|
||||
end
|
||||
return _kind
|
||||
end,
|
||||
|
||||
-- match two addresses
|
||||
--
|
||||
-- @table address
|
||||
-- @number cidr
|
||||
-- @return boolean
|
||||
|
||||
match = function(self, address, cidr)
|
||||
if cidr and address._cidr then
|
||||
address._cidr = cidr
|
||||
end
|
||||
return self.__eq(self, address)
|
||||
end,
|
||||
|
||||
-- converts ipv4 to ipv4-mapped ipv6 address
|
||||
--
|
||||
-- @return string|nil
|
||||
|
||||
ipv4_mapped_address = function (self)
|
||||
return self:kind('ipv4') and ip.parsev6('::ffff:' .. self:__tostring()) or nil
|
||||
end,
|
||||
|
||||
-- check if it's a ipv4 mapped address
|
||||
--
|
||||
-- @return boolean
|
||||
|
||||
is_ipv4_mapped = function (self)
|
||||
return self:range() == 'ipv4Mapped'
|
||||
end,
|
||||
|
||||
-- converts ipv6 ipv4-mapped address to ipv4 address
|
||||
--
|
||||
-- @return metatable
|
||||
|
||||
ipv4_address = function (self)
|
||||
assert(self:is_ipv4_mapped(), 'trying to convert a generic ipv6 address to ipv4')
|
||||
local high, low = self.parts[7], self.parts[8]
|
||||
return ip.v4({rshift(high, 8), band(high, 0xff), rshift(low, 8), band(low, 0xff)})
|
||||
end,
|
||||
|
||||
-- IP table to string
|
||||
--
|
||||
-- @return string
|
||||
|
||||
__tostring = function(self)
|
||||
if self:kind('ipv4') then
|
||||
return concat(self.octets, '.')
|
||||
end
|
||||
|
||||
local part, state, size, output = '', 0, #self.parts, {}
|
||||
|
||||
for i = 1, size do
|
||||
part = format('%x', self.parts[i])
|
||||
if 0 == state then
|
||||
insert(output, (ZERO == part and EMPTY or part))
|
||||
state = 1
|
||||
elseif 1 == state then
|
||||
if ZERO == part then
|
||||
state = 2
|
||||
else
|
||||
insert(output, part)
|
||||
end
|
||||
elseif 2 == state then
|
||||
if ZERO ~= part then
|
||||
insert(output, EMPTY)
|
||||
insert(output, part)
|
||||
state = 3
|
||||
end
|
||||
else
|
||||
insert(output, part)
|
||||
end
|
||||
end
|
||||
|
||||
if 2 == state then
|
||||
insert(output, COLON)
|
||||
end
|
||||
|
||||
return concat(output, COLON)
|
||||
end,
|
||||
|
||||
-- compare two IP addresses
|
||||
--
|
||||
-- @table value
|
||||
-- @return boolean
|
||||
|
||||
__eq = function(self, value)
|
||||
if #self.parts > 0 then
|
||||
assert(value.parts and #value.parts > 0, 'cannot match different address version')
|
||||
return match_cidr(self.parts, value.parts, 16, value._cidr)
|
||||
end
|
||||
assert(value.octets and #value.octets > 0, 'cannot match different address version')
|
||||
return match_cidr(self.octets, value.octets, 8, value._cidr)
|
||||
end
|
||||
}
|
||||
|
||||
ip_metatable.__index = ip_metatable
|
||||
|
||||
-- create new IP metatable
|
||||
--
|
||||
-- @table parts
|
||||
-- @table octets
|
||||
-- @number cidr
|
||||
-- @return metatable
|
||||
|
||||
local function new (parts, octets, cidr)
|
||||
return setmetatable({octets=octets, parts=parts, _cidr=cidr}, ip_metatable)
|
||||
end
|
||||
|
||||
-- assert IP version 4 octets and create it's metatable
|
||||
--
|
||||
-- @table octets
|
||||
-- @number cidr
|
||||
-- @return metatable
|
||||
|
||||
function ip.v4 (octets, cidr)
|
||||
local err, message = assert_ipv4(octets)
|
||||
assert(err, message)
|
||||
return new({}, octets, cidr or 32)
|
||||
end
|
||||
|
||||
-- assert IP version 6 parts and create it's metatable
|
||||
--
|
||||
-- @table parts
|
||||
-- @number cidr
|
||||
-- @table [octets]
|
||||
-- @return metatable
|
||||
|
||||
function ip.v6 (parts, cidr, octets)
|
||||
local err, message = assert_ipv6(parts)
|
||||
assert(err, message)
|
||||
|
||||
if octets and #octets > 0 then
|
||||
err, message = assert_ipv4(octets)
|
||||
assert(err, message)
|
||||
end
|
||||
|
||||
return new(parts, octets or {}, cidr or 128)
|
||||
end
|
||||
|
||||
-- parse string to IP version 4 metatable
|
||||
--
|
||||
-- @string string
|
||||
-- @number [cidr]
|
||||
-- @return metatable
|
||||
|
||||
function ip.parsev4 (string, cidr)
|
||||
local octets, message = {}, ''
|
||||
cidr, message = parse_v4(string, octets, cidr)
|
||||
assert(cidr ~= false, message)
|
||||
return ip.v4(octets, cidr)
|
||||
end
|
||||
|
||||
-- parse string to IP version 6 metatable
|
||||
--
|
||||
-- @string string
|
||||
-- @number [cidr]
|
||||
-- @return metatable
|
||||
|
||||
function ip.parsev6 (string, cidr)
|
||||
local parts, octets, message = {}, {}, ''
|
||||
cidr, message = parse_v6(string, parts, octets, cidr)
|
||||
assert(cidr ~= false, message)
|
||||
return ip.v6(parts, cidr, octets)
|
||||
end
|
||||
|
||||
-- check and parse string to IP metatable
|
||||
--
|
||||
-- @string string
|
||||
-- @return metatable
|
||||
|
||||
function ip.parse (string)
|
||||
if ip.isv6(string) then
|
||||
return ip.parsev6(string)
|
||||
elseif ip.isv4(string) then
|
||||
return ip.parsev4(string)
|
||||
end
|
||||
error('the address has neither IPv6 nor IPv4 format')
|
||||
end
|
||||
|
||||
-- check if string is a IP version 4 address
|
||||
--
|
||||
-- @string string
|
||||
-- @boolean validate
|
||||
-- @return boolean
|
||||
|
||||
function ip.isv4 (string, validate)
|
||||
if validate then
|
||||
local octets = {}
|
||||
return parse_v4(string, octets) ~= false and assert_ipv4(octets)
|
||||
end
|
||||
return find(string, _octet) ~= nil or find(string, _octets) ~= nil
|
||||
end
|
||||
|
||||
-- check if string is a IP version 6 address
|
||||
--
|
||||
-- @string string
|
||||
-- @boolean validate
|
||||
-- @return boolean
|
||||
|
||||
function ip.isv6 (string, validate)
|
||||
if validate then
|
||||
local octets, parts = {}, {}
|
||||
return parse_v6(string, parts, octets) ~= false and assert_ipv6(parts)
|
||||
end
|
||||
return find(string, _parts_with_octets) ~= nil
|
||||
end
|
||||
|
||||
-- check if IP address is valid
|
||||
--
|
||||
-- @string string
|
||||
-- @return boolean
|
||||
|
||||
function ip.valid (string)
|
||||
return pcall(ip.parse, string)
|
||||
end
|
||||
|
||||
return ip
|
|
@ -0,0 +1,385 @@
|
|||
--
|
||||
-- json.lua
|
||||
--
|
||||
-- Copyright (c) 2015 rxi
|
||||
--
|
||||
-- This library is free software; you can redistribute it and/or modify it
|
||||
-- under the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
|
||||
local json = { _version = "0.1.0" }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Encode
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local encode
|
||||
|
||||
local escape_char_map = {
|
||||
[ "\\" ] = "\\\\",
|
||||
[ "\"" ] = "\\\"",
|
||||
[ "\b" ] = "\\b",
|
||||
[ "\f" ] = "\\f",
|
||||
[ "\n" ] = "\\n",
|
||||
[ "\r" ] = "\\r",
|
||||
[ "\t" ] = "\\t",
|
||||
}
|
||||
|
||||
local escape_char_map_inv = { [ "\\/" ] = "/" }
|
||||
for k, v in pairs(escape_char_map) do
|
||||
escape_char_map_inv[v] = k
|
||||
end
|
||||
|
||||
|
||||
local function escape_char(c)
|
||||
return escape_char_map[c] or string.format("\\u%04x", c:byte())
|
||||
end
|
||||
|
||||
|
||||
local function encode_nil(val)
|
||||
return "null"
|
||||
end
|
||||
|
||||
|
||||
local function encode_table(val, stack)
|
||||
local res = {}
|
||||
stack = stack or {}
|
||||
|
||||
-- Circular reference?
|
||||
if stack[val] then error("circular reference") end
|
||||
|
||||
stack[val] = true
|
||||
|
||||
if val[1] ~= nil or next(val) == nil then
|
||||
-- Treat as array -- check keys are valid and it is not sparse
|
||||
local n = 0
|
||||
for k in pairs(val) do
|
||||
if type(k) ~= "number" then
|
||||
error("invalid table: mixed or invalid key types")
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
if n ~= #val then
|
||||
error("invalid table: sparse array")
|
||||
end
|
||||
-- Encode
|
||||
for i, v in ipairs(val) do
|
||||
table.insert(res, encode(v, stack))
|
||||
end
|
||||
stack[val] = nil
|
||||
return "[" .. table.concat(res, ",") .. "]"
|
||||
|
||||
else
|
||||
-- Treat as an object
|
||||
for k, v in pairs(val) do
|
||||
if type(k) ~= "string" then
|
||||
error("invalid table: mixed or invalid key types")
|
||||
end
|
||||
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
|
||||
end
|
||||
stack[val] = nil
|
||||
return "{" .. table.concat(res, ",") .. "}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function encode_string(val)
|
||||
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
||||
end
|
||||
|
||||
|
||||
local function encode_number(val)
|
||||
-- Check for NaN, -inf and inf
|
||||
if val ~= val or val <= -math.huge or val >= math.huge then
|
||||
error("unexpected number value '" .. tostring(val) .. "'")
|
||||
end
|
||||
return string.format("%.14g", val)
|
||||
end
|
||||
|
||||
|
||||
local type_func_map = {
|
||||
[ "nil" ] = encode_nil,
|
||||
[ "table" ] = encode_table,
|
||||
[ "string" ] = encode_string,
|
||||
[ "number" ] = encode_number,
|
||||
[ "boolean" ] = tostring,
|
||||
}
|
||||
|
||||
|
||||
encode = function(val, stack)
|
||||
local t = type(val)
|
||||
local f = type_func_map[t]
|
||||
if f then
|
||||
return f(val, stack)
|
||||
end
|
||||
error("unexpected type '" .. t .. "'")
|
||||
end
|
||||
|
||||
|
||||
function json.encode(val)
|
||||
return ( encode(val) )
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Decode
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local parse
|
||||
|
||||
local function create_set(...)
|
||||
local res = {}
|
||||
for i = 1, select("#", ...) do
|
||||
res[ select(i, ...) ] = true
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local space_chars = create_set(" ", "\t", "\r", "\n")
|
||||
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
||||
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
||||
local literals = create_set("true", "false", "null")
|
||||
|
||||
local literal_map = {
|
||||
[ "true" ] = true,
|
||||
[ "false" ] = false,
|
||||
[ "null" ] = nil,
|
||||
}
|
||||
|
||||
|
||||
local function next_char(str, idx, set, negate)
|
||||
for i = idx, #str do
|
||||
if set[str:sub(i, i)] ~= negate then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return #str + 1
|
||||
end
|
||||
|
||||
|
||||
local function decode_error(str, idx, msg)
|
||||
local line_count = 1
|
||||
local col_count = 1
|
||||
for i = 1, idx - 1 do
|
||||
col_count = col_count + 1
|
||||
if str:sub(i, i) == "\n" then
|
||||
line_count = line_count + 1
|
||||
col_count = 1
|
||||
end
|
||||
end
|
||||
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
|
||||
end
|
||||
|
||||
|
||||
local function codepoint_to_utf8(n)
|
||||
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
|
||||
local f = math.floor
|
||||
if n <= 0x7f then
|
||||
return string.char(n)
|
||||
elseif n <= 0x7ff then
|
||||
return string.char(f(n / 64) + 192, n % 64 + 128)
|
||||
elseif n <= 0xffff then
|
||||
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||
elseif n <= 0x10ffff then
|
||||
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
|
||||
f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||
end
|
||||
error( string.format("invalid unicode codepoint '%x'", n) )
|
||||
end
|
||||
|
||||
|
||||
local function parse_unicode_escape(s)
|
||||
local n1 = tonumber( s:sub(3, 6), 16 )
|
||||
local n2 = tonumber( s:sub(9, 12), 16 )
|
||||
-- Surrogate pair?
|
||||
if n2 then
|
||||
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
|
||||
else
|
||||
return codepoint_to_utf8(n1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function parse_string(str, i)
|
||||
local has_unicode_escape = false
|
||||
local has_surrogate_escape = false
|
||||
local has_escape = false
|
||||
local last
|
||||
for j = i + 1, #str do
|
||||
local x = str:byte(j)
|
||||
|
||||
if x < 32 then
|
||||
decode_error(str, j, "control character in string")
|
||||
end
|
||||
|
||||
if last == 92 then -- "\\" (escape char)
|
||||
if x == 117 then -- "u" (unicode escape sequence)
|
||||
local hex = str:sub(j + 1, j + 5)
|
||||
if not hex:find("%x%x%x%x") then
|
||||
decode_error(str, j, "invalid unicode escape in string")
|
||||
end
|
||||
if hex:find("^[dD][89aAbB]") then
|
||||
has_surrogate_escape = true
|
||||
else
|
||||
has_unicode_escape = true
|
||||
end
|
||||
else
|
||||
local c = string.char(x)
|
||||
if not escape_chars[c] then
|
||||
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
|
||||
end
|
||||
has_escape = true
|
||||
end
|
||||
last = nil
|
||||
|
||||
elseif x == 34 then -- '"' (end of string)
|
||||
local s = str:sub(i + 1, j - 1)
|
||||
if has_surrogate_escape then
|
||||
s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)
|
||||
end
|
||||
if has_unicode_escape then
|
||||
s = s:gsub("\\u....", parse_unicode_escape)
|
||||
end
|
||||
if has_escape then
|
||||
s = s:gsub("\\.", escape_char_map_inv)
|
||||
end
|
||||
return s, j + 1
|
||||
|
||||
else
|
||||
last = x
|
||||
end
|
||||
end
|
||||
decode_error(str, i, "expected closing quote for string")
|
||||
end
|
||||
|
||||
|
||||
local function parse_number(str, i)
|
||||
local x = next_char(str, i, delim_chars)
|
||||
local s = str:sub(i, x - 1)
|
||||
local n = tonumber(s)
|
||||
if not n then
|
||||
decode_error(str, i, "invalid number '" .. s .. "'")
|
||||
end
|
||||
return n, x
|
||||
end
|
||||
|
||||
|
||||
local function parse_literal(str, i)
|
||||
local x = next_char(str, i, delim_chars)
|
||||
local word = str:sub(i, x - 1)
|
||||
if not literals[word] then
|
||||
decode_error(str, i, "invalid literal '" .. word .. "'")
|
||||
end
|
||||
return literal_map[word], x
|
||||
end
|
||||
|
||||
|
||||
local function parse_array(str, i)
|
||||
local res = {}
|
||||
local n = 1
|
||||
i = i + 1
|
||||
while 1 do
|
||||
local x
|
||||
i = next_char(str, i, space_chars, true)
|
||||
-- Empty / end of array?
|
||||
if str:sub(i, i) == "]" then
|
||||
i = i + 1
|
||||
break
|
||||
end
|
||||
-- Read token
|
||||
x, i = parse(str, i)
|
||||
res[n] = x
|
||||
n = n + 1
|
||||
-- Next token
|
||||
i = next_char(str, i, space_chars, true)
|
||||
local chr = str:sub(i, i)
|
||||
i = i + 1
|
||||
if chr == "]" then break end
|
||||
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
|
||||
end
|
||||
return res, i
|
||||
end
|
||||
|
||||
|
||||
local function parse_object(str, i)
|
||||
local res = {}
|
||||
i = i + 1
|
||||
while 1 do
|
||||
local key, val
|
||||
i = next_char(str, i, space_chars, true)
|
||||
-- Empty / end of object?
|
||||
if str:sub(i, i) == "}" then
|
||||
i = i + 1
|
||||
break
|
||||
end
|
||||
-- Read key
|
||||
if str:sub(i, i) ~= '"' then
|
||||
decode_error(str, i, "expected string for key")
|
||||
end
|
||||
key, i = parse(str, i)
|
||||
-- Read ':' delimiter
|
||||
i = next_char(str, i, space_chars, true)
|
||||
if str:sub(i, i) ~= ":" then
|
||||
decode_error(str, i, "expected ':' after key")
|
||||
end
|
||||
i = next_char(str, i + 1, space_chars, true)
|
||||
-- Read value
|
||||
val, i = parse(str, i)
|
||||
-- Set
|
||||
res[key] = val
|
||||
-- Next token
|
||||
i = next_char(str, i, space_chars, true)
|
||||
local chr = str:sub(i, i)
|
||||
i = i + 1
|
||||
if chr == "}" then break end
|
||||
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
|
||||
end
|
||||
return res, i
|
||||
end
|
||||
|
||||
|
||||
local char_func_map = {
|
||||
[ '"' ] = parse_string,
|
||||
[ "0" ] = parse_number,
|
||||
[ "1" ] = parse_number,
|
||||
[ "2" ] = parse_number,
|
||||
[ "3" ] = parse_number,
|
||||
[ "4" ] = parse_number,
|
||||
[ "5" ] = parse_number,
|
||||
[ "6" ] = parse_number,
|
||||
[ "7" ] = parse_number,
|
||||
[ "8" ] = parse_number,
|
||||
[ "9" ] = parse_number,
|
||||
[ "-" ] = parse_number,
|
||||
[ "t" ] = parse_literal,
|
||||
[ "f" ] = parse_literal,
|
||||
[ "n" ] = parse_literal,
|
||||
[ "[" ] = parse_array,
|
||||
[ "{" ] = parse_object,
|
||||
}
|
||||
|
||||
|
||||
parse = function(str, idx)
|
||||
local chr = str:sub(idx, idx)
|
||||
local f = char_func_map[chr]
|
||||
if f then
|
||||
return f(str, idx)
|
||||
end
|
||||
decode_error(str, idx, "unexpected character '" .. chr .. "'")
|
||||
end
|
||||
|
||||
|
||||
function json.decode(str)
|
||||
if type(str) ~= "string" then
|
||||
error("expected argument of type string, got " .. type(str))
|
||||
end
|
||||
local status, result = pcall(
|
||||
function()
|
||||
return parse(str, next_char(str, 1, space_chars, true))
|
||||
end
|
||||
)
|
||||
return result, not status
|
||||
end
|
||||
|
||||
|
||||
return json
|
|
@ -0,0 +1,439 @@
|
|||
-- Copyright (C) Yichun Zhang (agentzh)
|
||||
|
||||
|
||||
local sub = string.sub
|
||||
local byte = string.byte
|
||||
local tcp = ngx.socket.tcp
|
||||
local null = ngx.null
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local unpack = unpack
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local tostring = tostring
|
||||
local rawget = rawget
|
||||
--local error = error
|
||||
|
||||
|
||||
local ok, new_tab = pcall(require, "table.new")
|
||||
if not ok or type(new_tab) ~= "function" then
|
||||
new_tab = function (narr, nrec) return {} end
|
||||
end
|
||||
|
||||
|
||||
local _M = new_tab(0, 54)
|
||||
|
||||
_M._VERSION = '0.26'
|
||||
|
||||
|
||||
local common_cmds = {
|
||||
"get", "set", "mget", "mset",
|
||||
"del", "incr", "decr", -- Strings
|
||||
"llen", "lindex", "lpop", "lpush",
|
||||
"lrange", "linsert", -- Lists
|
||||
"hexists", "hget", "hset", "hmget",
|
||||
--[[ "hmset", ]] "hdel", -- Hashes
|
||||
"smembers", "sismember", "sadd", "srem",
|
||||
"sdiff", "sinter", "sunion", -- Sets
|
||||
"zrange", "zrangebyscore", "zrank", "zadd",
|
||||
"zrem", "zincrby", -- Sorted Sets
|
||||
"auth", "eval", "expire", "script",
|
||||
"sort" -- Others
|
||||
}
|
||||
|
||||
|
||||
local sub_commands = {
|
||||
"subscribe", "psubscribe"
|
||||
}
|
||||
|
||||
|
||||
local unsub_commands = {
|
||||
"unsubscribe", "punsubscribe"
|
||||
}
|
||||
|
||||
|
||||
local mt = { __index = _M }
|
||||
|
||||
|
||||
function _M.new(self)
|
||||
local sock, err = tcp()
|
||||
if not sock then
|
||||
return nil, err
|
||||
end
|
||||
return setmetatable({ _sock = sock, _subscribed = false }, mt)
|
||||
end
|
||||
|
||||
|
||||
function _M.set_timeout(self, timeout)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
return sock:settimeout(timeout)
|
||||
end
|
||||
|
||||
|
||||
function _M.connect(self, ...)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
self._subscribed = false
|
||||
|
||||
return sock:connect(...)
|
||||
end
|
||||
|
||||
|
||||
function _M.set_keepalive(self, ...)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
if rawget(self, "_subscribed") then
|
||||
return nil, "subscribed state"
|
||||
end
|
||||
|
||||
return sock:setkeepalive(...)
|
||||
end
|
||||
|
||||
|
||||
function _M.get_reused_times(self)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
return sock:getreusedtimes()
|
||||
end
|
||||
|
||||
|
||||
local function close(self)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
return sock:close()
|
||||
end
|
||||
_M.close = close
|
||||
|
||||
|
||||
local function _read_reply(self, sock)
|
||||
local line, err = sock:receive()
|
||||
if not line then
|
||||
if err == "timeout" and not rawget(self, "_subscribed") then
|
||||
sock:close()
|
||||
end
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local prefix = byte(line)
|
||||
|
||||
if prefix == 36 then -- char '$'
|
||||
-- print("bulk reply")
|
||||
|
||||
local size = tonumber(sub(line, 2))
|
||||
if size < 0 then
|
||||
return null
|
||||
end
|
||||
|
||||
local data, err = sock:receive(size)
|
||||
if not data then
|
||||
if err == "timeout" then
|
||||
sock:close()
|
||||
end
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local dummy, err = sock:receive(2) -- ignore CRLF
|
||||
if not dummy then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return data
|
||||
|
||||
elseif prefix == 43 then -- char '+'
|
||||
-- print("status reply")
|
||||
|
||||
return sub(line, 2)
|
||||
|
||||
elseif prefix == 42 then -- char '*'
|
||||
local n = tonumber(sub(line, 2))
|
||||
|
||||
-- print("multi-bulk reply: ", n)
|
||||
if n < 0 then
|
||||
return null
|
||||
end
|
||||
|
||||
local vals = new_tab(n, 0)
|
||||
local nvals = 0
|
||||
for i = 1, n do
|
||||
local res, err = _read_reply(self, sock)
|
||||
if res then
|
||||
nvals = nvals + 1
|
||||
vals[nvals] = res
|
||||
|
||||
elseif res == nil then
|
||||
return nil, err
|
||||
|
||||
else
|
||||
-- be a valid redis error value
|
||||
nvals = nvals + 1
|
||||
vals[nvals] = {false, err}
|
||||
end
|
||||
end
|
||||
|
||||
return vals
|
||||
|
||||
elseif prefix == 58 then -- char ':'
|
||||
-- print("integer reply")
|
||||
return tonumber(sub(line, 2))
|
||||
|
||||
elseif prefix == 45 then -- char '-'
|
||||
-- print("error reply: ", n)
|
||||
|
||||
return false, sub(line, 2)
|
||||
|
||||
else
|
||||
-- when `line` is an empty string, `prefix` will be equal to nil.
|
||||
return nil, "unknown prefix: \"" .. tostring(prefix) .. "\""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function _gen_req(args)
|
||||
local nargs = #args
|
||||
|
||||
local req = new_tab(nargs * 5 + 1, 0)
|
||||
req[1] = "*" .. nargs .. "\r\n"
|
||||
local nbits = 2
|
||||
|
||||
for i = 1, nargs do
|
||||
local arg = args[i]
|
||||
if type(arg) ~= "string" then
|
||||
arg = tostring(arg)
|
||||
end
|
||||
|
||||
req[nbits] = "$"
|
||||
req[nbits + 1] = #arg
|
||||
req[nbits + 2] = "\r\n"
|
||||
req[nbits + 3] = arg
|
||||
req[nbits + 4] = "\r\n"
|
||||
|
||||
nbits = nbits + 5
|
||||
end
|
||||
|
||||
-- it is much faster to do string concatenation on the C land
|
||||
-- in real world (large number of strings in the Lua VM)
|
||||
return req
|
||||
end
|
||||
|
||||
|
||||
local function _do_cmd(self, ...)
|
||||
local args = {...}
|
||||
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
local req = _gen_req(args)
|
||||
|
||||
local reqs = rawget(self, "_reqs")
|
||||
if reqs then
|
||||
reqs[#reqs + 1] = req
|
||||
return
|
||||
end
|
||||
|
||||
-- print("request: ", table.concat(req))
|
||||
|
||||
local bytes, err = sock:send(req)
|
||||
if not bytes then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return _read_reply(self, sock)
|
||||
end
|
||||
|
||||
|
||||
local function _check_subscribed(self, res)
|
||||
if type(res) == "table"
|
||||
and (res[1] == "unsubscribe" or res[1] == "punsubscribe")
|
||||
and res[3] == 0
|
||||
then
|
||||
self._subscribed = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _M.read_reply(self)
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
if not rawget(self, "_subscribed") then
|
||||
return nil, "not subscribed"
|
||||
end
|
||||
|
||||
local res, err = _read_reply(self, sock)
|
||||
_check_subscribed(self, res)
|
||||
|
||||
return res, err
|
||||
end
|
||||
|
||||
|
||||
for i = 1, #common_cmds do
|
||||
local cmd = common_cmds[i]
|
||||
|
||||
_M[cmd] =
|
||||
function (self, ...)
|
||||
return _do_cmd(self, cmd, ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
for i = 1, #sub_commands do
|
||||
local cmd = sub_commands[i]
|
||||
|
||||
_M[cmd] =
|
||||
function (self, ...)
|
||||
self._subscribed = true
|
||||
return _do_cmd(self, cmd, ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
for i = 1, #unsub_commands do
|
||||
local cmd = unsub_commands[i]
|
||||
|
||||
_M[cmd] =
|
||||
function (self, ...)
|
||||
local res, err = _do_cmd(self, cmd, ...)
|
||||
_check_subscribed(self, res)
|
||||
return res, err
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _M.hmset(self, hashname, ...)
|
||||
if select('#', ...) == 1 then
|
||||
local t = select(1, ...)
|
||||
|
||||
local n = 0
|
||||
for k, v in pairs(t) do
|
||||
n = n + 2
|
||||
end
|
||||
|
||||
local array = new_tab(n, 0)
|
||||
|
||||
local i = 0
|
||||
for k, v in pairs(t) do
|
||||
array[i + 1] = k
|
||||
array[i + 2] = v
|
||||
i = i + 2
|
||||
end
|
||||
-- print("key", hashname)
|
||||
return _do_cmd(self, "hmset", hashname, unpack(array))
|
||||
end
|
||||
|
||||
-- backwards compatibility
|
||||
return _do_cmd(self, "hmset", hashname, ...)
|
||||
end
|
||||
|
||||
|
||||
function _M.init_pipeline(self, n)
|
||||
self._reqs = new_tab(n or 4, 0)
|
||||
end
|
||||
|
||||
|
||||
function _M.cancel_pipeline(self)
|
||||
self._reqs = nil
|
||||
end
|
||||
|
||||
|
||||
function _M.commit_pipeline(self)
|
||||
local reqs = rawget(self, "_reqs")
|
||||
if not reqs then
|
||||
return nil, "no pipeline"
|
||||
end
|
||||
|
||||
self._reqs = nil
|
||||
|
||||
local sock = rawget(self, "_sock")
|
||||
if not sock then
|
||||
return nil, "not initialized"
|
||||
end
|
||||
|
||||
local bytes, err = sock:send(reqs)
|
||||
if not bytes then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local nvals = 0
|
||||
local nreqs = #reqs
|
||||
local vals = new_tab(nreqs, 0)
|
||||
for i = 1, nreqs do
|
||||
local res, err = _read_reply(self, sock)
|
||||
if res then
|
||||
nvals = nvals + 1
|
||||
vals[nvals] = res
|
||||
|
||||
elseif res == nil then
|
||||
if err == "timeout" then
|
||||
close(self)
|
||||
end
|
||||
return nil, err
|
||||
|
||||
else
|
||||
-- be a valid redis error value
|
||||
nvals = nvals + 1
|
||||
vals[nvals] = {false, err}
|
||||
end
|
||||
end
|
||||
|
||||
return vals
|
||||
end
|
||||
|
||||
|
||||
function _M.array_to_hash(self, t)
|
||||
local n = #t
|
||||
-- print("n = ", n)
|
||||
local h = new_tab(0, n / 2)
|
||||
for i = 1, n, 2 do
|
||||
h[t[i]] = t[i + 1]
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
|
||||
-- this method is deperate since we already do lazy method generation.
|
||||
function _M.add_commands(...)
|
||||
local cmds = {...}
|
||||
for i = 1, #cmds do
|
||||
local cmd = cmds[i]
|
||||
_M[cmd] =
|
||||
function (self, ...)
|
||||
return _do_cmd(self, cmd, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
setmetatable(_M, {__index = function(self, cmd)
|
||||
local method =
|
||||
function (self, ...)
|
||||
return _do_cmd(self, cmd, ...)
|
||||
end
|
||||
|
||||
-- cache the lazily generated method in our
|
||||
-- module table
|
||||
_M[cmd] = method
|
||||
return method
|
||||
end})
|
||||
|
||||
|
||||
return _M
|
|
@ -0,0 +1,22 @@
|
|||
local json = require 'json'
|
||||
|
||||
local module = {}
|
||||
|
||||
module.getPostData = function()
|
||||
local data, err
|
||||
|
||||
ngx.req.read_body()
|
||||
data = ngx.req.get_body_data()
|
||||
if not data then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
data, err = json.decode(data)
|
||||
if err or type(data) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
return module
|
|
@ -0,0 +1,63 @@
|
|||
local json = require 'json'
|
||||
|
||||
local module = {}
|
||||
|
||||
module.raw = function(status, data)
|
||||
ngx.status = status
|
||||
ngx.say(data)
|
||||
end
|
||||
|
||||
module.json = function(status, data)
|
||||
ngx.status = status
|
||||
ngx.header['Content-type'] = 'application/json'
|
||||
ngx.say(json.encode(data))
|
||||
end
|
||||
|
||||
module.status = function(status)
|
||||
ngx.status = status
|
||||
end
|
||||
|
||||
module.exit = function(status)
|
||||
return ngx.exit(status)
|
||||
end
|
||||
|
||||
module.isValidResponseType = function(request_type)
|
||||
return (request_type == 'raw' or request_type == 'json' or request_type == 'xml' or request_type == 'status') and true or false
|
||||
end
|
||||
|
||||
module.quit = module.exit
|
||||
|
||||
module.xml = function(status, data)
|
||||
local response = '<?xml version="1.0" encoding="utf-8"?><response>'
|
||||
for i, v in pairs(data) do
|
||||
response = response .. '<'..i..'>'..tostring(v)..'</'..i..'>'
|
||||
end
|
||||
|
||||
ngx.status = status
|
||||
response = response .. '</response>'
|
||||
ngx.header['Content-type'] = 'text/xml; charset=utf-8'
|
||||
ngx.say(response)
|
||||
end
|
||||
|
||||
module.createResponse = function(response_type, email, domain, isBad)
|
||||
if response_type == 'status' then
|
||||
module.status(isBad and ngx.HTTP_FORBIDDEN or ngx.HTTP_OK)
|
||||
elseif response_type == 'raw' then
|
||||
module.raw(ngx.HTTP_OK, tostring(isBad))
|
||||
elseif response_type == 'json' then
|
||||
module.json(ngx.HTTP_OK, {
|
||||
['email'] = email,
|
||||
['domain'] = domain,
|
||||
['bad'] = isBad
|
||||
})
|
||||
elseif response_type == 'xml' then
|
||||
module.xml(ngx.HTTP_OK, {
|
||||
['email'] = email,
|
||||
['domain'] = domain,
|
||||
['bad'] = isBad
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return module
|
|
@ -0,0 +1,80 @@
|
|||
local request = require 'request'
|
||||
local response = require 'response'
|
||||
local helper = require 'helper'
|
||||
local resolver = require 'dns'
|
||||
local json = require 'json'
|
||||
local ip = require 'ip'
|
||||
|
||||
local red = helper.redis.connect()
|
||||
|
||||
request_uri = helper.parseURL()
|
||||
if type(request_uri) ~= "table" or table.getn(request_uri) < 2 then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
local response_type = request_uri[2]
|
||||
if not response.isValidResponseType(response_type) then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
local data = request.getPostData()
|
||||
if data == nil or data['email'] == nil then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
domain = helper.getDomain(data['email'])
|
||||
if not domain then
|
||||
response.quit(ngx.HTTP_BAD_REQUEST)
|
||||
return
|
||||
end
|
||||
|
||||
local isBad = helper.redis.checkDomain(red, "disposable", domain)
|
||||
if not isBad or postData['no_dns_check'] == true then
|
||||
local r, err = resolver:new{
|
||||
nameservers = {'8.8.8.8', '8.8.4.4'},
|
||||
retrans = 5,
|
||||
timeout = 2000,
|
||||
}
|
||||
|
||||
if not r or err then
|
||||
ngx.log(ngx.ERR, err)
|
||||
response.quit(ngx.HTTP_SERVICE_UNAVAILABLE)
|
||||
end
|
||||
|
||||
local ans, err = r:tcp_query(domain, { qtype = r.TYPE_MX })
|
||||
if not ans or err then
|
||||
ngx.log(ngx.ERR, err)
|
||||
if type(ans) == "table" then
|
||||
for i, v in pairs(ans) do
|
||||
ngx.log(ngx.ERR, json.encode(err))
|
||||
end
|
||||
end
|
||||
response.quit(ngx.HTTP_SERVICE_UNAVAILABLE)
|
||||
return
|
||||
end
|
||||
|
||||
if not (type(ans) ~= "table" or #ans == 0) then
|
||||
for _i, _v in pairs(ans) do
|
||||
local ip_addrs, err = r:tcp_query(_v.exchange)
|
||||
if not ip_addrs or err or type(ip_addrs) ~= 'table' or #ip_addrs == 0 then
|
||||
isBad = true
|
||||
break
|
||||
end
|
||||
local p
|
||||
for i, v in pairs(ip_addrs) do
|
||||
p = ip.parse(v.address)
|
||||
if p.range(p) ~= "unicast" then
|
||||
isBad = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
isBad = true
|
||||
end
|
||||
end
|
||||
|
||||
response.createResponse(response_type, data['email'], domain, isBad)
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
const git = require('simple-git'),
|
||||
commander = require('commander'),
|
||||
request = require('request-promise'),
|
||||
fs = require('fs'),
|
||||
redis = require("redis");
|
||||
|
||||
let pkg = require('./package.json'),
|
||||
repos = require('./repositories.json'),
|
||||
client = redis.createClient({
|
||||
'host': 'redis',
|
||||
'port': 6379
|
||||
}),
|
||||
saveList = [],
|
||||
domainList = [];
|
||||
|
||||
client.on('error', (err) => {
|
||||
console.error(`[x] ${err.toString()}`);
|
||||
});
|
||||
|
||||
console.log(`[*] Gathering from ${repos.length} sources...`);
|
||||
Promise.all(repos.map(d => request(d.url))).then((data) => {
|
||||
repos.forEach((source) => {
|
||||
console.log(` - ${source.url}`);
|
||||
});
|
||||
|
||||
let tempList = data.join('\n').split('\n');
|
||||
let domainList = [];
|
||||
console.log(`[*] Creating domain list...`);
|
||||
tempList.forEach((domain) => {
|
||||
if (domain === '') {
|
||||
return;
|
||||
}
|
||||
if (domainList[domain] === undefined) {
|
||||
domainList[domain] = true;
|
||||
}
|
||||
});
|
||||
domainList = Object.keys(domainList);
|
||||
console.log(`[*] Found ${domainList.length} domains`);
|
||||
console.log(`[*] Sorting by alphabet...`);
|
||||
domainList = domainList.sort((a, b) => a !== b ? a < b ? -1 : 1 : 0);
|
||||
|
||||
console.log(`[*] Adding domains to cache...`)
|
||||
domainList.forEach((domain) => {
|
||||
client.hset('disposable', domain, true);
|
||||
});
|
||||
|
||||
console.log(`[*] Done!`);
|
||||
client.quit();
|
||||
}).catch((err) => {
|
||||
console.error(err.toString());
|
||||
console.error(`URL: ${err.options.uri}`);
|
||||
client.quit();
|
||||
process.exit(1);
|
||||
});
|
|
@ -0,0 +1,468 @@
|
|||
{
|
||||
"name": "trash-bot",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz",
|
||||
"integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=",
|
||||
"requires": {
|
||||
"co": "4.6.0",
|
||||
"fast-deep-equal": "1.0.0",
|
||||
"fast-json-stable-stringify": "2.0.0",
|
||||
"json-schema-traverse": "0.3.1"
|
||||
}
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
|
||||
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
|
||||
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
|
||||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
|
||||
},
|
||||
"boom": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
|
||||
"requires": {
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
|
||||
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
|
||||
"requires": {
|
||||
"delayed-stream": "1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
|
||||
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
|
||||
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
|
||||
"requires": {
|
||||
"boom": "5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
|
||||
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
|
||||
"requires": {
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"double-ended-queue": {
|
||||
"version": "2.1.0-0",
|
||||
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
|
||||
"integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw="
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "0.1.1"
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
|
||||
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
|
||||
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
|
||||
"requires": {
|
||||
"asynckit": "0.4.0",
|
||||
"combined-stream": "1.0.5",
|
||||
"mime-types": "2.1.17"
|
||||
}
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
|
||||
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
||||
"requires": {
|
||||
"ajv": "5.5.1",
|
||||
"har-schema": "2.0.0"
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
|
||||
"requires": {
|
||||
"boom": "4.3.1",
|
||||
"cryptiles": "3.1.2",
|
||||
"hoek": "4.2.0",
|
||||
"sntp": "2.1.0"
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
|
||||
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"jsprim": "1.4.1",
|
||||
"sshpk": "1.13.1"
|
||||
}
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"optional": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
|
||||
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.17",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
|
||||
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
|
||||
"requires": {
|
||||
"mime-db": "1.30.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
|
||||
},
|
||||
"redis": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz",
|
||||
"integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==",
|
||||
"requires": {
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"redis-commands": "1.3.1",
|
||||
"redis-parser": "2.6.0"
|
||||
}
|
||||
},
|
||||
"redis-commands": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz",
|
||||
"integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs="
|
||||
},
|
||||
"redis-parser": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz",
|
||||
"integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.83.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
|
||||
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
|
||||
"requires": {
|
||||
"aws-sign2": "0.7.0",
|
||||
"aws4": "1.6.0",
|
||||
"caseless": "0.12.0",
|
||||
"combined-stream": "1.0.5",
|
||||
"extend": "3.0.1",
|
||||
"forever-agent": "0.6.1",
|
||||
"form-data": "2.3.1",
|
||||
"har-validator": "5.0.3",
|
||||
"hawk": "6.0.2",
|
||||
"http-signature": "1.2.0",
|
||||
"is-typedarray": "1.0.0",
|
||||
"isstream": "0.1.2",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"mime-types": "2.1.17",
|
||||
"oauth-sign": "0.8.2",
|
||||
"performance-now": "2.1.0",
|
||||
"qs": "6.5.1",
|
||||
"safe-buffer": "5.1.1",
|
||||
"stringstream": "0.0.5",
|
||||
"tough-cookie": "2.3.3",
|
||||
"tunnel-agent": "0.6.0",
|
||||
"uuid": "3.1.0"
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
|
||||
"requires": {
|
||||
"bluebird": "3.5.1",
|
||||
"request-promise-core": "1.1.1",
|
||||
"stealthy-require": "1.1.1",
|
||||
"tough-cookie": "2.3.3"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
|
||||
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
|
||||
"requires": {
|
||||
"lodash": "4.17.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
|
||||
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
},
|
||||
"simple-git": {
|
||||
"version": "1.83.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.83.0.tgz",
|
||||
"integrity": "sha1-OiaE32L3W6TnleE2QtArnYV/wJ0=",
|
||||
"requires": {
|
||||
"debug": "3.1.0"
|
||||
}
|
||||
},
|
||||
"sntp": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
|
||||
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
|
||||
"requires": {
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
||||
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
|
||||
"requires": {
|
||||
"asn1": "0.2.3",
|
||||
"assert-plus": "1.0.0",
|
||||
"bcrypt-pbkdf": "1.0.1",
|
||||
"dashdash": "1.14.1",
|
||||
"ecc-jsbn": "0.1.1",
|
||||
"getpass": "0.1.7",
|
||||
"jsbn": "0.1.1",
|
||||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
|
||||
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
|
||||
"requires": {
|
||||
"punycode": "1.4.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"optional": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "1.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "trash-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "./index.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"commander": "^2.12.2",
|
||||
"redis": "^2.8.0",
|
||||
"request": "^2.83.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"simple-git": "^1.83.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"name": "adamloving temporary email address domains",
|
||||
"url": "https://gist.githubusercontent.com/adamloving/4401361/raw/db901ef28d20af8aa91bf5082f5197d27926dea4/temporary-email-address-domains"
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue