diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..722935b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.swp +eznet diff --git a/ltnp/ltnp_operator.cr b/ltnp/ltnp_operator.cr index c800ab9..228708c 100644 --- a/ltnp/ltnp_operator.cr +++ b/ltnp/ltnp_operator.cr @@ -1,16 +1,18 @@ require "./ltnp_record" class LtnpOperator - def initialize(_cmd_output : String) - @cmd_output = _cmd_output - records = @cmd_output.each_line + def initialize(cmd_output : String) + records = cmd_output.each_line records = records.each.select(/^tcp/) @ltnp_records = Array(LtnpRecord).new records.each { |s| @ltnp_records << LtnpRecord.new s } end def say_hi - puts @cmd_output - puts @ltnp_records.to_s + @ltnp_records.each { |r| puts r.to_s } + end + + def get_port_record(port : String) : LtnpRecord | Nil + @ltnp_records.find { |r| r.port == port } end end diff --git a/ltnp/ltnp_record.cr b/ltnp/ltnp_record.cr index 276d455..1cf4f45 100644 --- a/ltnp/ltnp_record.cr +++ b/ltnp/ltnp_record.cr @@ -1,8 +1,53 @@ require "../modules/record_helpers" class LtnpRecord + getter proto : String + getter state : String + getter address : String + getter port : String + getter f_address : String + getter f_port : String + getter state : String + getter pid : String + getter p_name : String + def initialize(record : String) - @str_arr = RecordHelpers.clean_record(record) - + ser_record = RecordHelpers.clean_record(record) + @proto = ser_record[0] + @address, @port = ser_address_port ser_record[3].split(':') + @f_address, @f_port = ser_address_port ser_record[4].split(':') + @state = ser_record[5] + @pid, @p_name = ser_pid_p_name ser_record[6] + end + + def to_s + puts "%s, " * 8 % [ + @proto, @state, @address, @port, + @f_address, @f_port, @pid, @p_name + ] + end + + def ser_address_port(address_port : Array) : {String, String} + address = String.new + port = String.new + unless address_port.size > 2 + address = address_port[0] + port = address_port[1] + else + port = address_port[-1] + end + {address, port} + end + + def ser_pid_p_name(pid_pro_str : String) : {String, String} + pid = String.new + p_name = String.new + unless pid_pro_str == "-" + pid_pro = pid_pro_str.split('/') + pid = pid_pro[0] + p_name = pid_pro[1] + end + {pid, p_name} end + end diff --git a/main b/main deleted file mode 100755 index aa5e9a0..0000000 Binary files a/main and /dev/null differ diff --git a/main.cr b/main.cr index f0920f5..936ac42 100644 --- a/main.cr +++ b/main.cr @@ -15,10 +15,20 @@ OptionParser.parse do |parser| exit end + parser.on "-c PORT", "--check-port=PORT", "Get the process name and ID of process on port" do |port| + ltnp_operator = NetstatRunner.run_ltnp + record = ltnp_operator.get_port_record port + unless record.nil? + puts "Port: %s, Process: %s" % [record.port, record.p_name] + else + puts "No processes found on port %s" % port + end + exit + end + parser.on "-k", "--kill-port", "Kill process on port" do - output = NetstatRunner.run_ltnp - ltnp_parser = LtnpOperator.new output - ltnp_parser.say_hi + ltnp_operator = NetstatRunner.run_ltnp + ltnp_operator.say_hi exit end end diff --git a/modules/netstat_runner.cr b/modules/netstat_runner.cr index 06a4aaa..ead6a9c 100644 --- a/modules/netstat_runner.cr +++ b/modules/netstat_runner.cr @@ -1,7 +1,7 @@ module NetstatRunner - def self.run_ltnp() + def self.run_ltnp() : LtnpOperator io = IO::Memory.new - Process.run("netstat -ltnp", shell: true, output: io) - io.to_s + Process.run("sudo netstat -ltnp", shell: true, output: io) + LtnpOperator.new io.to_s end end diff --git a/ltnp/ltnp_example.txt b/spec/input/ltnp_example.txt similarity index 100% rename from ltnp/ltnp_example.txt rename to spec/input/ltnp_example.txt diff --git a/spec/ltnp/ltnp_operator_spec.cr b/spec/ltnp/ltnp_operator_spec.cr new file mode 100644 index 0000000..10ceffe --- /dev/null +++ b/spec/ltnp/ltnp_operator_spec.cr @@ -0,0 +1,19 @@ +require "spec" +require "../../ltnp/ltnp_operator.cr" + +describe LtnpOperator do + sut = LtnpOperator.new File.read("./spec/input/ltnp_example.txt") + + describe "#get_port_record" do + existing_port = "8081" + nonsense_port = "1234" + + it "should find record when port exists" do + sut.get_port_record(existing_port).nil?.should be_false + end + + it "should not find record when port doesn't exist" do + sut.get_port_record(nonsense_port).nil?.should be_true + end + end +end diff --git a/spec/ltnp/ltnp_record_spec.cr b/spec/ltnp/ltnp_record_spec.cr new file mode 100644 index 0000000..79f29f3 --- /dev/null +++ b/spec/ltnp/ltnp_record_spec.cr @@ -0,0 +1,29 @@ +require "spec" +require "../../ltnp/ltnp_record.cr" + +describe LtnpRecord do + sut_normal = LtnpRecord.new "tcp 0 0 127.0.0.1:8081 0.0.0.0:* LISTEN 69/myproc" + sut_address = LtnpRecord.new "tcp 0 0 :::8081 0.0.0.0:* LISTEN 69/myproc" + sut_process = LtnpRecord.new "tcp 0 0 :::8081 0.0.0.0:* LISTEN -" + + it "should have expected properties under normal circumstance" do + sut_normal.proto.should eq("tcp") + sut_normal.address.should eq("127.0.0.1") + sut_normal.port.should eq("8081") + sut_normal.f_address.should eq("0.0.0.0") + sut_normal.f_port.should eq("*") + sut_normal.state.should eq("LISTEN") + sut_normal.pid.should eq("69") + sut_normal.p_name.should eq("myproc") + end + + it "should have expected properties when Local Address column is edge case" do + sut_address.address.empty?.should be_true + sut_address.port.should eq("8081") + end + + it "should have expected properties when PID/ProcessName column is edge case" do + sut_process.pid.empty?.should be_true + sut_process.p_name.empty?.should be_true + end +end