Created
March 29, 2021 01:28
-
-
Save kengonakajima/d3bc7b83893aba441f13e841bf3d07ac to your computer and use it in GitHub Desktop.
pcap analyzer for game packets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!ruby -Ku | |
# Author: takeda yoshiki | |
res_hash = { | |
"ret" => false, | |
"error" => "", | |
} | |
begin | |
require 'pp' | |
require 'json' | |
# 取得するデータ | |
# - だいたいの同時接続数 | |
# - 送信頻度 | |
# - サーバーの受信数/sec | |
# - サーバーの送信数/sec | |
# - 受信の平均パケットサイズ | |
# - 送信の平均パケットサイズ | |
# - 増幅率 | |
def get_param(argv:ARGV, delimiter:[], default:"", split:"=") | |
ret = default | |
argv = argv.map{|r|r.split(split)}.flatten.select{|r|r!=split} | |
delimiter = [delimiter] unless delimiter.kind_of?(Array) | |
delimiter.each{|d| | |
unless (inx=argv.index(d)).nil? | |
ret = argv[inx+1] unless argv[inx+1].nil? | |
break | |
end | |
} | |
return ret | |
end | |
#サーバのアドレスを取得する | |
def get_server_addr(datas) | |
# pcapを取得したアドレスを特定する | |
addrs = datas.slice(0,10).map{|r| | |
[r["src"],r["dst"]] | |
}.flatten | |
server_addr = addrs.uniq.map do |a| | |
{ | |
"addr"=>a, | |
"num"=>addrs.count{|x|x==a}, | |
} | |
end.sort_by{|r| | |
-r["num"] | |
}[0]["addr"] | |
return server_addr | |
end | |
#接続しているクライアントを取得する | |
#※今は送信しか見ていない | |
def get_connection_clients(server_addr,datas) | |
return datas.select do |r| | |
r["dst"] == server_addr | |
end.map do|r| | |
r["src"] | |
end.sort.uniq | |
end | |
# - 1秒間あたりの同時接続クライアント数を取得 | |
# TODO:余計なループがあるので後から治す。ぶっちゃけ全秒数の接続数取らなくてもいい。 | |
def get_connection_num(server_addr,datas) | |
first = datas[0]["time"].to_i | |
last = datas.last["time"].to_i | |
return (first..last).map do |sec| | |
{ | |
"time" => sec, | |
"count" => get_connection_clients( | |
server_addr,datas.select do |r| | |
r["time"].to_i == sec | |
end).count, | |
} | |
end | |
end | |
#特定秒のパケットのみ取り出す | |
def extract_data_of_sec(target_sec,datas) | |
return datas.select do |r| | |
r["time"].to_i == target_sec | |
end | |
end | |
def get_average_connection(server_addr,datas) | |
sec_of_connections = get_connection_num(server_addr,datas) | |
total = sec_of_connections.map do|r| | |
next r["count"].to_i | |
end.inject(:+) | |
return (total.to_f / sec_of_connections.length.to_f) | |
end | |
# データの特定の秒数を取得する | |
# 特定の1秒間のデータを取得する際に使用する | |
# 現状では、通信が落ち着くと思われる70%の時間を取得 | |
def get_target_time(datas,target_ratio=0.7) | |
target_rows = datas[datas.length * target_ratio] | |
return target_rows["time"].to_i rescue 0 | |
end | |
def get_server_send_late(datas,clients) | |
return clients.map do |client| | |
{ | |
"client" => client, | |
"num" => datas.select{|r| | |
r["dst"]==client | |
}.length | |
} | |
end | |
end | |
# - 受信の平均パケットサイズ | |
def get_packet_size(server_addr,datas,src_or_dst) | |
length = datas.select{|r|r[src_or_dst]==server_addr}.length | |
return datas.select{|r|r[src_or_dst]==server_addr} | |
.map{|r|r["size"].to_i}.inject(:+) / length | |
end | |
if !(ENV["OS"].nil?) and ENV["OS"].index("Windows") | |
tshark='"C:/Program Files/Wireshark/tshark.exe"' | |
else | |
tshark=`which tshark`.strip | |
end | |
raise "plz spaciled -p [pcap]" if | |
(pcap = get_param(delimiter: ["-p","--pcap"],default:"")).length <= 0 | |
# DIR="/root/d/support/s_スパイク・チュンソフト様/20210315_先方のtcpdump調査/20210312_lily_pcap" | |
lines=`#{tshark} -r "#{File.expand_path(pcap)}"` | |
raise "no pcap data." if lines.length <= 0 | |
#連想配列にデータを変換 | |
datas = lines.split("\n").map do |line| | |
arr = line.split("\s") | |
{ | |
"seq" => arr[0], | |
"time" => arr[1], | |
"src" => arr[2], | |
"dst" => arr[4], | |
"protocol" => arr[5], | |
"size" => arr[6], | |
} | |
end | |
server_addr = get_server_addr(datas) | |
#中間よりちょっと後ろのデータを取る | |
target_sec = get_target_time(datas) | |
datas = extract_data_of_sec(target_sec,datas) | |
# - 同時接続数 | |
connection_average = get_average_connection(server_addr,datas) | |
connection_clients = get_connection_clients(server_addr,datas) | |
# - 1クライアントあたりの送信頻度(最低,最高,平均値) | |
send_ratio_par_client = get_server_send_late( | |
datas,connection_clients).sort_by!{|r|r["num"]} | |
max_send_ratio_par_sec_for_client = send_ratio_par_client.sort_by {|r|r["num"]}.last["num"] | |
minimum_send_ratio_par_sec_for_client = send_ratio_par_client.sort_by {|r|-r["num"]}.last["num"] | |
average_send_ratio_par_sec_for_client = send_ratio_par_client.map{|r|r["num"]}.inject(:+) /send_ratio_par_client.length | |
# - サーバーの受信数/sec | |
server_receive_num_per_sec = datas.select{|r|r["dst"]==server_addr}.length | |
# - サーバーの送信数/sec | |
server_send_num_per_sec = datas.select{|r|r["src"]==server_addr}.length | |
ret = { | |
# - だいたいの同時接続数 | |
"connection_client_average" => connection_average, | |
# - 送信頻度 | |
"max_send_ratio_par_sec_for_client" =>max_send_ratio_par_sec_for_client, | |
"minimum_send_ratio_par_sec_for_client" =>minimum_send_ratio_par_sec_for_client, | |
"average_send_ratio_par_sec_for_client" =>average_send_ratio_par_sec_for_client, | |
# - サーバーの受信数/sec | |
"server_receive_num_per_sec" => server_receive_num_per_sec, | |
# - サーバーの送信数/sec | |
"server_send_num_per_sec" => server_send_num_per_sec, | |
# - 受信の平均パケットサイズ | |
"average_server_receive_packet_size" => get_packet_size(server_addr,datas,"dst"), | |
# - 送信の平均パケットサイズ | |
"average_server_send_packet_size" => get_packet_size(server_addr,datas,"src"), | |
# - 増幅率 | |
"amplification_ratio" => get_packet_size(server_addr,datas,"src")/get_packet_size(server_addr,datas,"dst"), | |
} | |
res_hash["ret"] = ret | |
rescue => e | |
if e.message.length > 0 | |
res_hash["error"] = "#{e.message}\\n#{e.backtrace}" | |
end | |
end | |
puts JSON.generate(res_hash) |
Author
kengonakajima
commented
Mar 29, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment