0

I have several python classes built to help organize data for my project. I need two independent copies of the class for the final result. However, when I make two copies of the class, they do not seem to be independent and I'm not sure why. The structure is confusing, but I can't seem to recreate my problem with a shorter example, so I'll just include what I have done, I'm sorry it's large, and probably not exactly done correctly.

I'm sure that it is just something simple I'm overlooking. I thought I was decent at python, but I'm self taught, so it could be that I missed something.

from pcapfile import *


"""This should be working fine"""
class Packet:
    # This is just a container class to keep everything organized
    def __init__(self, src, dst):
        self.src = src
        self.dst = dst


"""This works"""
# built on a dictionary with two unordered keys
# use to store ip pairs as one entry
class MultiKeyDict:
    items = {}
    def get_item(self, key1, key2):
        if key1 != key2:
            if (key1, key2) in self.items:
                # return Item, and True flag for correct order
                return self.items[(key1, key2)], True
            else:
                # return item, and false flag for wrong order. cause a key error on purpose if not
                return self.items[key2, key1], False
        else:
            print("Error, Keys cannot be equal")
            err = self.items[(9, 9, 9)]  # cause error on purpose

    # test for existence both ways
    def exists(self, key1, key2):
        if (key1, key2) in self.items or (key2, key1) in self.items:
            return True
        else:
            return False

    def get_if_exists(self, key1, key2):
        if self.exists(key1, key2):
            return self.get_item(key1, key2)
        else:
            return False, False

    def insert_item(self, key1, key2, value):
        if key1 != key2:
            self.items[(key1, key2)] = value
        else:
            print("Error, Keys cannot be equal")
            err = self.items[(9, 9, 9)]  # cause error on purpose

    def update_item(self, key1, key2, value):
        i, f = self.get_item(key1, key2)
        if f:
            self.insert_item(key1, key2, value)
        else:
            self.insert_item(key2, key1, value)

    def get_all_keys(self):
        return self.items.keys()

    def __str__(self):
        rbuilder = "{"
        for _ in self.items:
            rbuilder += str(_) + ":" + str(self.items[_]) + ","
        return rbuilder + "}"

"""I think this works"""
# combination of packets, forming a history list, and running total of counts
# creation initializes first packet
class Flow:
    def __init__(self, pack, max=10):
        self.__max__ = max
        self.src = pack.src  # initial source and destination
        self.dst = pack.dst
        self.total_packets = 1
        self.hist = []
        self.ctr = 1
        self.first_order = True  # flag to tell in original order, true if yes, false if no
        self.sprt = 0  # for training only, will need to update manually

    # to be able to unpack in MultiKeyDict with *(Flow.get_keys())
    def get_keys(self):
        return (self.src, self.dst)

    def update(self):
        if self.ctr < self.__max__:  # update if under max ctr value, otherwise do nothing
            self.ctr += 1
        self.total_packets += 1

    def reverse(self):
        self.hist.append(self.ctr)
        self.first_order = not self.first_order  # flip reversed flag
        self.ctr = 0
        self.update()

    def get_hist(self, order=0):
        if order == 0:
            return self.hist
        else:
            return self.hist[-order:]

    def __str__(self):
        return str((self.get_hist(), self.ctr))

# the goal of this is to make an object that I can throw a packet
# at and it will update the appropriate flow in a MultiKeyDict
# should be able to use this for both training matrix-es, and testing live
class FlowDictionary:
    flows = MultiKeyDict()

    # find or create entry in self.flows for that specific flow
    def update(self, pack):
        f, r = self.flows.get_if_exists(pack.src, pack.dst)
        if f:  # already exists, just need to update
            if f.first_order and pack.src == f.src:  # flow (f) is in original order, and packet src matches
                f.update()
                # print('option1')
            elif f.first_order and pack.src == f.dst:  # flow (f) is in original order, and packer src matches flow dst
                f.reverse()
                # print('option2')
            elif not f.first_order and pack.src == f.dst:  # flow is backwards and so is packet
                f.update()
                # print('option3')
            elif not f.first_order and pack.src == f.src:  # flow is backwards, but packet is forwards
                f.reverse()
                # print('option4')
        else:  # doesn't exist, need to add
            self.flows.insert_item(pack.src, pack.dst, Flow(pack))

    def get_keys_with_histories(self, order=''):  # returns all full length histories if no order, all order length if order
        hist_list = []
        if order == '':
            for _ in self.flows.get_all_keys():
                hist_list.append((_, self.flows.get_item(*_)[0].get_hist(), self.flows.get_item(*_)[0].ctr))
                # print((_, self.flows.get_item(*_)[0].get_hist()))
                # hist_list.append((self.flows.get_item(*(_))))
        else:
            for _ in self.flows.get_all_keys():

                hist_list.append((_, self.flows.get_item(*_)[0].get_hist(order), self.flows.get_item(*_)[0].ctr))
                # print((_, self.flows.get_item(*_)[0].get_hist(order)))
                # hist_list.append((self.flows.get_item(*(_))))
        return hist_list

    def get_history_segments(self, order):
        full_hist_list = self.get_keys_with_histories()
        full_hist_list = [[0]*(order-1)+i[1] for i in full_hist_list]

        return full_hist_list


# built to read in a file with a specific order into a flowDictionary, and store the
# matrix trained on it
"""Still needs fixed"""
class TrainingMatrix:
    def __init__(self, order, file):
        self.order = order
        self.train_on_file(file)

    # look for, and add any additional packets to the flow dict,
    # updating and flows already in there
    def train_on_file(self, file):
        pass

    def build_matrix(self, order):
        pass


p = Packet('1', '2')
p2 = Packet('2', '1')
p3 = Packet('3', '4')
p4 = Packet('4', '3')
test1 = FlowDictionary()
test1.update(p)
test1.update(p3)
test1.update(p)
test1.update(p)
test1.update(p2)
test1.update(p3)
test1.update(p3)
test1.update(p)
test1.update(p2)
test1.update(p2)
test1.update(p)
test1.update(p4)
test1.update(p)
test1.update(p2)
test1.update(p)
test1.update(p4)
test1.update(p4)
test1.update(p4)
test1.update(p2)
test1.update(p)
test1.update(p)
test1.update(p3)
test1.update(p2)
test1.update(p2)
test1.update(p4)
test1.update(p)
test1.update(p)
test1.update(p2)
test1.update(p2)
print(test1.flows)

print(test1.get_keys_with_histories())
print(test1.get_keys_with_histories(2))
print(test1.get_history_segments(2))


print()

p5 = Packet('12', '21')
p6 = Packet('12', '11')
p7 = Packet('13', '14')
p8 = Packet('14', '13')
test2 = FlowDictionary()
test2.update(p5)
test2.update(p7)
test2.update(p5)
test2.update(p5)
test2.update(p6)
test2.update(p7)
test2.update(p7)
test2.update(p5)
test2.update(p6)
test2.update(p6)
test2.update(p5)
test2.update(p8)
test2.update(p5)
test2.update(p6)
test2.update(p5)
test2.update(p8)
test2.update(p8)
test2.update(p8)
test2.update(p6)
test2.update(p5)
test2.update(p5)
test2.update(p7)
test2.update(p6)
test2.update(p6)
test2.update(p8)
test2.update(p5)
test2.update(p5)
test2.update(p6)
test2.update(p6)
print(test2.flows)

print(test2.get_keys_with_histories())
print(test2.get_keys_with_histories(2))
print(test2.get_history_segments(2))

And the output:

{('3', '4'):([3, 4, 1], 1),('1', '2'):([3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2], 2),}
[(('3', '4'), [3, 4, 1], 1), (('1', '2'), [3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2], 2)]
[(('3', '4'), [4, 1], 1), (('1', '2'), [2, 2], 2)]
[[0, 3, 4, 1], [0, 3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2]]

{('3', '4'):([3, 4, 1], 1),('1', '2'):([3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2], 2),('12', '11'):([], 9),('12', '21'):([], 10),('13', '14'):([3, 4, 1], 1),}
[(('3', '4'), [3, 4, 1], 1), (('1', '2'), [3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2], 2), (('12', '11'), [], 9), (('12', '21'), [], 10), (('13', '14'), [3, 4, 1], 1)]
[(('3', '4'), [4, 1], 1), (('1', '2'), [2, 2], 2), (('12', '11'), [], 9),     (('12', '21'), [], 10), (('13', '14'), [4, 1], 1)]
[[0, 3, 4, 1], [0, 3, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2], [0], [0], [0, 3, 4, 1]]

as you can see it appears that the second class some of the same data, or that it didn't start with an empty dictionary like I thought it should have. Let me know if you have any suggestions. Thanks!

Chad Bockholt
  • 51
  • 1
  • 5

0 Answers0