#!/usr/bin/env escript main(_) -> case io:get_line("") of eof -> {error, read_error}; {error, Reason} -> {error, read_error, Reason}; Input -> analyze(hd_to_binary(Input)) end. hd_to_binary(HD) -> hd_to_binary(HD, []). hd_to_binary("\n", Acc) -> list_to_binary(lists:reverse(Acc)); hd_to_binary([X,Y|HD], Acc) -> {ok, [V], []} = io_lib:fread("~16u", [X,Y]), hd_to_binary(HD, [V | Acc]). binary_to_hd(Bin) -> lists:flatten([io_lib:format("~2.16.0B", [X]) || X <- binary_to_list(Bin)]). icmp(Payload) -> case Payload of << ToM: 8, Code: 8, Checksum: 16, Quench: 32, Data/binary>> -> Sum = chksum(<< ToM:8, Code:8, 0:16, Quench: 32, Data/binary>>), io:format("\nICMP:\n\nType of message:\t0x~.16B (~s)\nCode:\t\t\t0x~.16B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nQuench:\t\t\t~.16B\nData:\t\t\t~s\n", [ToM, icmp_type(ToM), Code, Checksum, Sum, Quench, binary_to_hd(Data)]); _ -> {error} end. udp(DGram, IP) -> case DGram of << SPort: 16, DPort: 16, Len: 16, Checksum:16, Data/binary>> -> Sum = chksum(<< IP/binary, SPort:16, DPort:16, Len:16, 0:16, Data/binary>>), io:format("\nUDP:\n\nSource port:\t\t0x~.16B (~B)\nDestination port:\t0x~.16B (~B)\nLen:\t\t\t~B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nData:\t\t\t~s\n", [SPort, SPort, DPort, DPort, Len, Checksum, Sum, binary_to_hd(Data)]); _ -> {error} end. tcp(Segment, SAddr, DAddr) -> case Segment of << SPort: 16, DPort: 16, Seq: 32, Ack: 32, DataOff: 4, Reserved: 4, CWR:1, ECE:1, URG:1, ACK:1, PSH:1, RST:1, SYN:1, FIN:1, WindowSize: 16, Checksum: 16, UrgentPointer: 16, Data/binary>> -> SegSize = byte_size(Segment), Sum = chksum(<< SAddr:32, DAddr:32, 0:8, 6:8, SegSize:16, SPort: 16, DPort: 16, Seq: 32, Ack: 32, DataOff: 4, Reserved: 4, CWR:1, ECE:1, URG:1, ACK:1, PSH:1, RST:1, SYN:1, FIN:1, WindowSize: 16, 0:16, UrgentPointer:16, Data/binary>>), io:format("\nTCP:\n\nSource port:\t\t0x~.16B (~B)\nDestination port:\t0x~.16B (~B)\nSequence number:\t~B\nAck number:\t\t~B\nData offset:\t\t0x~.16B\nFlags:\t\t\tCWR: ~B ECE: ~B URG: ~B ACK: ~B PSH: ~B RST: ~B SYN: ~B FIN: ~B\nWindow size:\t\t0x~.16B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nUrgent pointer:\t\t~.16B\nData:\t\t\t~s\n", [SPort, SPort, DPort, DPort, Seq, Ack, DataOff, CWR, ECE, URG, ACK, PSH, RST, SYN, FIN, WindowSize, Checksum, Sum, UrgentPointer, binary_to_hd(Data)]); _ -> {error} end. analyze(Dgram) -> DgramSize = byte_size(Dgram), case Dgram of << 4:4, HLen:4, SrvcType:8, TotLen:16, ID:16, Flgs:3, FragOff:13, TTL:8, Proto:8, HdrChkSum:16, SrcIP:32, DestIP:32, RestDgram/binary>> % when HLen >= 5, 4*HLen=<DgramSize -> OptsLen = 4*(HLen - 5), <<Opts:OptsLen/binary, Data/binary>> = RestDgram, CRC = chksum(<< 4:4, HLen:4, SrvcType:8, TotLen:16, ID:16, Flgs:3, FragOff:13, TTL:8, Proto:8, 0:16, SrcIP:32, DestIP:32, Opts:OptsLen>>), io:format("IP version:\t\t4\nHeader length:\t\t~B\nService type:\t\t~B\nTotal length:\t\t~B (calculated: ~B)\nID:\t\t\t0x~.16B\nFlags:\t\t\t0x~.16B\nFragment offset:\t~B\nTTL:\t\t\t~B\nProtocol:\t\t0x~.16B (~s)\nHeader checksum:\t0x~.16B (calculated: 0x~.16B)\nSource address:\t\t0x~.16B (~s)\nDestination address:\t0x~.16B (~s)\nData:\t\t\t~s\n", [HLen, SrvcType, TotLen, DgramSize, ID, Flgs, FragOff, TTL, Proto, proto(Proto), HdrChkSum, CRC, SrcIP, hex_to_ip(SrcIP), DestIP, hex_to_ip(DestIP), binary_to_hd(Data)]), if Proto == 1 -> icmp(Data); Proto == 6 -> tcp(Data, SrcIP, DestIP); Proto == 17 -> DSize = byte_size(Data), udp(Data, <<SrcIP:32, DestIP:32, 0:8, 17:8, DSize:16>>); true -> io:format("") end; _ -> io:format("Not an IP packet\n") end. hex_to_ip(H) -> X = << H:32 >>, << A:8, B:8, C:8, D:8 >> = X, io_lib:format("~B.~B.~B.~B", [A,B,C,D]). proto(P) -> Protos = [ {1, "ICMP"}, {3, "GGP"}, {6, "TCP"}, {17, "UDP"} ], case lists:keyfind(P, 1, Protos) of false -> "Unknown"; {_, Proto} -> Proto end. icmp_type(P) -> Types = [ {0, "Echo reply"}, {1, "Reserved"}, {3, "Destination unreachable"}, {8, "Echo request"} ], case lists:keyfind(P, 1, Types) of false -> "Unknown"; {_, Proto} -> Proto end. chksum(H) -> chksum(H, 0). chksum(<<>>, Acc) -> (bnot (Acc + (Acc bsr 16)) band 65535); chksum(<<A:8>>, Acc) -> chksum(<<A:8, 0:8>>, Acc); chksum(<<A:8, B:8, C/binary>>, Acc) -> chksum(C, Acc+B+(A bsl 8)).
-module(zad3). -export([create/1, insert/2, select/2, select/3, delete/2, update/3, update/4]). -record(db, {recordname, fields, auto_id, data}). % test: % rd(x, {y,z}). %{db,a, [y,z], 4, [{1,#x{y = 1,z = 2}}, {2,#x{y = undefined,z = undefined}}, {3,#x{y = 5,z = 5}}]} create({RecordName, Fields}) -> {ok, #db{recordname=RecordName, fields=Fields, auto_id=1, data=[]}}. insert(Db, Record) -> Id = Db#db.auto_id, NewData = [{Id,Record}|Db#db.data], {ok, Id, Db#db{auto_id=Id+1, data=NewData}}. select(Db, Pred) -> try Result = lists:filter(fun ({_,Record}) -> Pred(Record) end, Db#db.data), {ok, Result} catch _:_ -> {error, bad_query} end. select(Db, Pred, Field) -> try N = field(Field, Db#db.fields), Result = lists:filter(fun ({_,Record}) -> Pred(element(N,Record)) end, Db#db.data), {ok, Result} catch _:_ -> {error, bad_query} end. field(Field, Fields) -> field(Field, Fields, 2). field(_, [], _) -> {error, not_found}; field(Field, [H|L], N) -> if Field == H -> N; true -> field(Field, L, N+1) end. delete(Db, Pred) -> try {Sat, NSat} = lists:partition(fun ({_,Record}) -> Pred(Record) end, Db#db.data), {ok, Db#db{data=NSat}, Sat} catch _:_ -> {error, bad_query} end. update(Db, Pred, F) -> try {Sat, NSat} = lists:partition(fun ({_,Record}) -> Pred(Record) end, Db#db.data), try ModSat = lists:map(fun ({Id, Record}) -> {Id, F(Record)} end, Sat), {ok, Db#db{data=ModSat++NSat}, ModSat} catch _:_ -> {error, bad_updater} end catch _:_ -> {error, bad_query} end. update(Db, Pred, F, Field) -> N = field(Field, Db#db.fields), update(Db, fun(P) -> Pred(element(N, P)) end, fun(P) -> setelement(N, P, F(element(N, P))) end ).