hogeとはワイルドカードのようなものです。日々起こった、さまざまなこと −すなわちワイルドカード− を取り上げて日記を書く、という意味で名付けたのかというとそうでもありません。適当に決めたらこんな理由が浮かんできました。
12/16/2018 ふむ [長年日記]
tDiary 5897日目
■ [Py][小ネタ] NAPT 前のアドレスを知る
例えば下記のようなネットワークがあるとする.Client が Web Server にアクセスした際,NAPT Router によって NAPT される前の Client の情報を Web Server が知りたいとする.
+--------+ +-------------+ +------------+ | Client |----------| NAPT Router |--------| Web Server | +--------+ +-------------+ +------------+ 172.16.0.193 172.16.0.1 10.207.9.88 10.207.9.87
NAPT Router が Linux 箱なら,conntrack エントリがカーネルの中に保持されているので,下記のようなサービスを NAPT Router の上で動かしておくことができるだろう.
import flask
from pyroute2.netlink.exceptions import NetlinkError
from pyroute2.netlink.nfnetlink.nfctsocket import NFCTSocket, NFCTAttrTuple
app = flask.Flask(__name__)
cts = NFCTSocket()
@app.route('/conntrack', methods=['GET'])
def conntrack_get():
saddr = flask.request.args.get('saddr')
daddr = flask.request.args.get('daddr')
proto = int(flask.request.args.get('proto'))
sport = int(flask.request.args.get('sport'))
dport = int(flask.request.args.get('dport'))
tpl = NFCTAttrTuple(saddr=saddr, daddr=daddr,
proto=proto, sport=sport, dport=dport)
try:
entry = cts.entry('get', tuple_reply=tpl)
except NetlinkError:
return flask.Response(status=404)
tuple_orig = entry[0].get_attr('CTA_TUPLE_ORIG')
tuple_ip = tuple_orig.get_attr('CTA_TUPLE_IP')
tuple_proto = tuple_orig.get_attr('CTA_TUPLE_PROTO')
return flask.jsonify(saddr=tuple_ip.get_attr('CTA_IP_V4_SRC'),
daddr=tuple_ip.get_attr('CTA_IP_V4_DST'),
proto=tuple_proto.get_attr('CTA_PROTO_NUM'),
sport=tuple_proto.get_attr('CTA_PROTO_SRC_PORT'),
dport=tuple_proto.get_attr('CTA_PROTO_DST_PORT'))
if __name__ == '__main__':
app.run('10.207.9.88')
その上で Web Server が下記のように,このサービスを叩く.
import flask
import requests
app = flask.Flask(__name__)
@app.route('/', methods=['GET'])
def root():
saddr = flask.request.environ['SERVER_NAME']
daddr = flask.request.environ['REMOTE_ADDR']
sport = flask.request.environ['SERVER_PORT']
dport = flask.request.environ['REMOTE_PORT']
response = requests.get('http://10.207.9.88:5000/conntrack?'
'saddr=%(saddr)s&daddr=%(daddr)s&proto=6&'
'sport=%(sport)s&dport=%(dport)s' % locals())
if not response.ok:
return flask.Response(status=404)
entry = response.json()
return flask.jsonify(saddr=entry['saddr'],
daddr=entry['daddr'],
proto=entry['proto'],
sport=entry['sport'],
dport=entry['dport'])
if __name__ == '__main__':
app.run('10.207.9.87')
Client から Web Server にアクセスしてみると,
$ curl -s http://10.207.9.87:5000/ | jq .
{
"daddr": "10.207.9.87",
"dport": 5000,
"proto": 6,
"saddr": "172.16.0.193",
"sport": 55208
}
Web Server から,NAPT 前のオリジナルの Client のデータが返ってきていることが確認できる.
だからどうしたぼくドラえもん.
[ツッコミを入れる]