##Configuration
###Accessing the neo4j server from outside
Uncomment the following line in conf/neo4j-server.properties
# Let the webserver only listen on the specified IP. Default is localhost (only
# accept local connections). Uncomment to allow any connection. Please see the
# security section in the neo4j manual before modifying this.
org.neo4j.server.webserver.address=0.0.0.0
Set up JVM heap in /etc/neo4j/neo4j-wrapper.conf
when necessary. No, this is pretty much necessary.
wrapper.java.initmemory=8192
wrapper.java.maxmemory=8192
##Start server
$ ./bin/neo4j console
Neo4j start listening the access from outside. Now you go http://<neo4j_ip>:7474/
with your browser
##Shell
./bin/neo4j-shell
##Cypher
create nodes
create (ip_1_1_1_1:host {ip:'1.1.1.1', type:'host'})
create (ip_2_2_2_2:c2 {ip:'2.2.2.2', type:'c&c'})
create relation
create (ip_1_1_1_1) -[:to]-> (ip_2_2_2_2)
query for the relation
match (ip_1_1_1_1) -[rel:to]-> (ip_2_2_2_2) return rel
load csv
$ cat flow.csv
1.1.1.1, 2.2.2.2, TCP, 80
3.3.3.3, 4.4.4.4, UDP, 53
5.5.5.5, 6.6.6.6, TCP, 443
7.7.7.7, 8.8.8.8, TCP, 22
$ LOAD CSV FROM 'file:///neo4j/flow.csv' AS line
> MERGE (:node {name:line[0], proto:line[2], port:line[3]});
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 4
Properties set: 12
Labels added: 4
126 ms
$ match (x) where x.port = '80'
> return x;
+--------------------------------------------------+
| x |
+--------------------------------------------------+
| Node[2226]{name:"1.1.1.1",proto:"TCP",port:"80"} |
+--------------------------------------------------+
1 row
20 ms
$ LOAD CSV FROM 'file:///neo4j/flow.csv' AS line
> MERGE (s:src {name:line[0]})-[:r {proto:line[2], port:line[3]}]->(d:dst {name:line[1]}) ;
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 14
Relationships created: 7
Properties set: 28
Labels added: 14
291 ms
$ match (s:src)-[r]->(d:dst)
> return s, r, d;
+------------------------------------------------------------------------------------------------+
| s | r | d |
+------------------------------------------------------------------------------------------------+
| Node[2230]{name:"1.1.1.1"} | :r[2662]{proto:"TCP",port:"80"} | Node[2231]{name:"2.2.2.2"} |
| Node[2232]{name:"3.3.3.3"} | :r[2663]{proto:"UDP",port:"53"} | Node[2233]{name:"4.4.4.4"} |
| Node[2234]{name:"5.5.5.5"} | :r[2664]{proto:"TCP",port:"443"} | Node[2235]{name:"6.6.6.6"} |
| Node[2236]{name:"7.7.7.7"} | :r[2665]{proto:"TCP",port:"22"} | Node[2237]{name:"8.8.8.8"} |
| Node[2238]{name:"1.1.1.1"} | :r[2666]{proto:"TCP",port:"80"} | Node[2239]{name:"9.9.9.9"} |
| Node[2240]{name:"3.3.3.3"} | :r[2667]{proto:"TCP",port:"80"} | Node[2241]{name:"10.10.10.10"} |
| Node[2242]{name:"5.5.5.5"} | :r[2668]{proto:"ICMP",port:"0"} | Node[2243]{name:"7.7.7.7"} |
+------------------------------------------------------------------------------------------------+
7 rows
34 ms
$ CREATE CONSTRAINT ON (s:src) ASSERT s.name IS UNIQUE;
+-------------------+
| No data returned. |
+-------------------+
Unique constraints added: 1
315 ms
LOAD CSV FROM 'file:///neo4j/flow.csv' AS flow
MERGE (sip:src_ip {name: flow[0]})
MERGE (dip:dst_ip {name: flow[1]})
CREATE UNIQUE (sip)-[:access {proto: flow[2], port: flow[3]}]->(dip)
square_full_mesh.csv
root@neo4j:/neo4j/neo4j# cat /flows/square_full_mesh.csv
1.1.1.1,2.2.2.2,TCP,80
1.1.1.1,3.3.3.3,TCP,80
1.1.1.1,4.4.4.4,TCP,80
2.2.2.2,1.1.1.1,TCP,80
2.2.2.2,3.3.3.3,TCP,80
2.2.2.2,4.4.4.4,TCP,80
3.3.3.3,1.1.1.1,TCP,80
3.3.3.3,2.2.2.2,TCP,80
3.3.3.3,4.4.4.4,TCP,80
4.4.4.4,1.1.1.1,TCP,80
4.4.4.4,2.2.2.2,TCP,80
4.4.4.4,3.3.3.3,TCP,80
this one creates close one but src_ip and dst_ip are dealed as different group(CONSTRAINT works within the each group) - means that you see two node for each ip above.
LOAD CSV FROM 'file:///flows/square_full_mesh.csv' AS flow
MERGE (sip:src_ip {name: flow[0]})
MERGE (dip:dst_ip {name: flow[1]})
CREATE UNIQUE (sip)-[:access {proto: flow[2], port: flow[3]}]->(dip);
delete all nodes and relationship
MATCH (n) DETACH DELETE n
loading from nfdump flow csv file
LOAD CSV FROM 'file:///flows/square_full_mesh.csv' AS flow
MERGE (:ip_addr {name: '1.1.1.1'})
MERGE (:ip_addr {name: '2.2.2.2'})
MATCH (n:ip_addr),(m:ip_addr)
WHERE n.name = '1.1.1.1' and m.name = '2.2.2.2'
CREATE (n)-[r:access]->(m) return r;
quick and dirty and redundunt solution but it works.
# STEP1 - create nodes
LOAD CSV FROM 'file:///flows/square_full_mesh.csv' AS flow
MERGE (:ip {name: flow[0]})
MERGE (:ip {name: flow[1]})
# STEP2 - create relationship
LOAD CSV FROM 'file:///flows/square_full_mesh.csv' AS flow
MATCH (n:ip),(m:ip)
WHERE n.name = flow[0] and m.name = flow[1]
CREATE UNIQUE (n)-[r:access {proto: flow[2], port: flow[3]}]->(m) return r;
loading shell script
#!/bin/bash
# Load nfdump flow.csv
/neo4j/neo4j/bin/neo4j-shell << EOF
LOAD CSV FROM 'file:///flows/i3router_flows_10.csv' AS flow
MERGE (:ip {name: flow[3]})
MERGE (:ip {name: flow[4]});
LOAD CSV FROM 'file:///flows/i3router_flows_10.csv' AS flow
MATCH (n:ip),(m:ip)
WHERE n.name = flow[3] and m.name = flow[4]
CREATE UNIQUE (n)-[r:access {proto: flow[7], port: flow[6]}]->(m);
EOF
csv loading time
neo4j-sh (?)$ LOAD CSV FROM 'file:///flows/i3router_flows_10000.csv' AS flow
> MERGE (:ip {name: flow[3]})
> MERGE (:ip {name: flow[4]});
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 5675
Properties set: 5675
Labels added: 5675
138451 ms
neo4j-sh (?)$
neo4j-sh (?)$ LOAD CSV FROM 'file:///flows/i3router_flows_10000.csv' AS flow
> MATCH (n:ip),(m:ip)
> WHERE n.name = flow[3] and m.name = flow[4]
> CREATE UNIQUE (n)-[r:access {proto: flow[7], port: flow[6]}]->(m);
+-------------------+
| No data returned. |
+-------------------+
Relationships created: 10000
Properties set: 20000
639071 ms