3 require "$Bin/json_pp.pm";
16 print STDERR "command: $cmd\n";
20 sub fetch_active_data_linux($$) {
24 open DATA, "(ip -4 r s dev $ifname; ip -6 r s dev $ifname) |";
28 my @data = split /\s+/, $_;
29 next if $data[0] =~ /^fe80:/;
30 next if $data[0] =~ /^ff..:/;
31 $data[0] =~ /(:|\/)/ or do {
34 $data->{route}->{$data[0]} = 'delete';
38 open DATA, "ip a s dev $ifname |";
42 my @data = split /\s+/, $_;
43 next unless $data[0] =~ /inet/;
44 next if $data[1] =~ /^fe80:/;
45 $data->{ipaddr}->{$data[1]} = 'delete';
50 sub fetch_active_data_darwin($$) {
54 open DATA, "netstat -rn |";
58 my @data = split /\s+/, $_;
59 next unless $data[3] eq $ifname;
60 next if $data[0] =~ /^fe80:/;
61 next if $data[0] =~ /^ff..:/;
62 $data[0] =~ /(:|\/)/ or do {
64 my @addr = split /\./, $data[0];
69 $data[0] = join(".", @addr)."/$mask";
71 $data->{route}->{$data[0]} = 'delete';
75 open DATA, "ifconfig $ifname |";
79 my @data = split /\s+/, $_;
80 next unless $data[0] =~ /inet/;
81 next if $data[1] =~ /^fe80:/;
82 $data->{ipaddr}->{$data[1]} = 'delete';
87 sub update_data($$$) {
92 return unless $data->{"link-up"} eq 1;
93 foreach my $val (@{$data->{ipaddr}}, @{$data->{ip6addr}}) {
94 my $ip = $val->{ipaddr};
95 my $mask = $val->{mask};
99 if (not($ip =~ /::/) and $mask eq 64) {
100 $route =~ s/((\w+):(\w+):(\w+):(\w+)):.*/$1::/;
104 push @{$data->{routes6}}, { target => "$route", "netmask" => $mask };
106 push @{$data->{routes}}, { target => "$ip", "netmask" => 32 };
108 if ($delete->{ipaddr}->{$ip}) {
109 delete $delete->{ipaddr}->{$ip};
110 } elsif ($delete->{ipaddr}->{"$ip/$mask"}) {
111 delete $delete->{ipaddr}->{"$ip/$mask"};
113 $add->{ipaddr}->{"$ip/$mask"} = 'add';
116 foreach my $val (@{$data->{routes}}, @{$data->{routes6}}) {
117 my $ip = $val->{target}.'/'.$val->{netmask};
119 if ($delete->{route}->{$ip}) {
120 delete $delete->{route}->{$ip};
122 $add->{route}->{$ip} = 'add';
127 sub set_active_data_linux($$$) {
132 foreach my $ip (keys %{$delete->{ipaddr}}) {
133 cmd("ip a d $ip dev $ifname");
135 foreach my $ip (keys %{$add->{ipaddr}}) {
136 cmd("ip a a $ip dev $ifname");
139 foreach my $route (keys %{$delete->{route}}) {
140 cmd("ip r d $route dev $ifname");
142 foreach my $route (keys %{$add->{route}}) {
143 cmd("ip r a $route dev $ifname");
147 sub set_active_data_darwin($$$) {
152 foreach my $ip (keys %{$delete->{ipaddr}}) {
155 cmd("ifconfig $ifname inet6 delete $ip");
157 cmd("ifconfig $ifname delete $ip");
160 foreach my $ip (keys %{$add->{ipaddr}}) {
161 my @ip = split /\//, $ip;
164 cmd("ifconfig $ifname inet6 add $ip[0] prefixlen $ip[1]");
166 cmd("ifconfig $ifname add $ip[0]/$ip[1] $ip[0]");
169 foreach my $route (keys %{$delete->{route}}) {
171 cmd("route delete -inet6 $route -iface $ifname");
173 cmd("route delete -inet $route -iface $ifname");
176 foreach my $route (keys %{$add->{route}}) {
178 cmd("route add -inet6 $route -iface $ifname");
180 cmd("route add -inet $route -iface $ifname");
186 my $platform = `uname`;
187 my $data = JSON::PP::decode_json($json) or die "Failed to decode JSON data\n";
189 my $delete = create_state();
190 my $add = create_state();
192 if ($platform =~ /Darwin/) {
193 fetch_active_data_darwin($data->{ifname}, $delete);
194 } elsif ($platform =~ /Linux/) {
195 fetch_active_data_linux($data->{ifname}, $delete);
197 die "Unsupported platform $platform\n";
200 update_data($data, $delete, $add);
202 if ($platform =~ /Darwin/) {
203 set_active_data_darwin($data->{ifname}, $delete, $add);
204 } elsif ($platform =~ /Linux/) {
205 set_active_data_linux($data->{ifname}, $delete, $add);
208 # print Data::Dumper->Dump([$add, $delete], ["add", "delete"])."\n";