#!/usr/bin/perl -w -I/www/cgi-bin use perlfunc; $| = 1; $auto = 0; $do_basic = 1; sub usage { die " usage: node-setup [-a] [-p] -a: automatic mode - don't ask any questions -p: only process port forwarding and dhcp settings\n\n" } ########################## # main program starts here # validate args while(defined $ARGV[0] and $ARGV[0] =~ /^-/) { $arg = shift; if ($arg eq "-a") { $auto = 1 } elsif($arg eq "-p") { $do_basic = 0 } else { usage() } } $config = shift; usage() unless defined $config; die "'$config' is not a valid configuration\n" unless -f "/etc/config.$config/_setup"; #chomp ($node = `nvram get node`); #chomp ($mac2 = `nvram get mac2`); #chomp ($tactical = `nvram get tactical`); $node = nvram_get("node"); $tactical = nvram_get("tactical"); $mac2 = mac2ip(get_mac("wlan0"), 0); $dtdmac = mac2ip(get_mac("eth0"), 0); unless($auto) { print "\ncurrent node name is '$node'\n"; print "type a new name or just to keep the current name\n\n"; do { print "enter node name: "; $node2 = ; die "node-setup aborted\n" if not defined $node2; chomp $node2; } while($node2 =~ /[^\w\-]/ or $node2 =~ /_/); print "\ncurrent tactical name is "; if($tactical) { print "'$tactical'\n" } else { print "not set\n" } print "type a new name, to keep the current name,\n"; print "or @ to remove the tactical name\n\n"; do { print "enter tactical name: "; $tac2 = ; die "node-setup aborted\n" if not defined $tac2; chomp $tac2; } while($tac2 ne "@" and ($tac2 =~ /[^\w\-]/ or $tac2 =~ /_/)); $node = $node2 if $node2; $tactical = $tac2 if $tac2; $tactical = "" if $tac2 eq "@"; } # # load and verify the selected configuration # foreach $line (`cat /etc/config.$config/_setup`) { next if $line =~ /^\s*#/; next if $line =~ /^\s*$/; $line =~ s//$node/; $line =~ s//$mac2/; $line =~ s//$dtdmac/; $line =~ /^(\w+)\s*=\s*(.*)$/; $cfg{$1} = $2; } die "configuration load failed\n" unless keys %cfg; # delete some config lines if necessary if($cfg{wan_proto} eq "dhcp") { $deleteme{wan_ip} = 1; $deleteme{wan_gw} = 1; $deleteme{wan_mask} = 1; } $deleteme{lan_gw} = 1 if $cfg{dmz_mode} or $cfg{wan_proto} ne "disabled"; # lan_dhcp sense is inverted in the dhcp config file # and it is a checkbox so it may not be defined - this fixes that if($cfg{lan_dhcp}) { $cfg{lan_dhcp} = 0 } else { $cfg{lan_dhcp} = 1 } # verify that we have all the variables we need chdir "/etc/config.$config" or die; foreach(`grep "^[^#].*<" *`) { ($file, $parm) = /^(\S+):.*<(\w+)>/; if($parm eq uc $parm) # nvram variable { $lcparm = lc $parm; die "parameter '$parm' in file '$file' does not exist\n" unless nvram_get($lcparm) ne ""; } elsif(not $deleteme{$parm}) { die "parameter '$parm' in file '$file' does not exist\n" unless exists $cfg{$parm}; } } # switch to dmz values if needed if($cfg{dmz_mode}) { foreach(qw(lan_ip lan_mask dhcp_start dhcp_end dhcp_limit)) { $cfg{$_} = $cfg{"dmz_$_"}; } } # select ports and dhcp files based on mode $portfile = "/etc/config.$config/_setup.ports"; $dhcpfile = "/etc/config.$config/_setup.dhcp"; $portfile .= ($cfg{dmz_mode} ? ".dmz" : ".nat") if $config eq "mesh"; $dhcpfile .= ($cfg{dmz_mode} ? ".dmz" : ".nat") if $config eq "mesh"; # basic configuration if($do_basic) { # setup the staging area system "rm -rf /tmp/new_config; mkdir /tmp/new_config"; # copy and process the new configuration chdir "/etc/config.$config" or die; foreach $file (glob "*") { chomp $file; next if $file =~ /^_setup/; next if $file =~ /^firewall.user/; next if $file =~ /^olsrd/; open(IN, $file) or die; open(OUT, "> /tmp/new_config/$file") or die; while(defined ($line = )) { if($line =~ /^include\s+(\S+)/) { foreach $inc (`cat $1`) { print OUT $inc; } next; } $line =~ s//$node/; $line =~ s//$mac2/; $line =~ s//$dtdmac/; $delparm = 0; while(($parm) = $line =~ /^[^\#].*<(\S+)>/) { if($deleteme{$parm}) { $delparm = 1; last; } $line =~ s/<$parm>/$cfg{$parm}/; } print OUT $line unless $delparm; } close(OUT); close(IN); } # make it official system "rm -f /etc/config/*"; system "mv /tmp/new_config/* /etc/config"; unlink "/tmp/new_config"; system "cp -f /etc/config.$config/firewall.user /etc/"; #system "nvram set config=$config"; #system "nvram set node=$node"; #system "nvram set tactical=$tactical"; #system "nvram commit"; nvram_set("config", $config); nvram_set("node", $node); nvram_set("tactical", $tactical); } # # generate the system files # open(HOSTS, ">/etc/hosts") or die; print HOSTS "# automatically generated file - do not edit\n"; print HOSTS "# use /etc/hosts.user for custom entries\n"; print HOSTS "127.0.0.1\tlocalhost\n"; print HOSTS "$cfg{lan_ip}\tlocalnode "; print HOSTS "\n$cfg{wifi_ip}\t" if $cfg{wifi_ip}; print HOSTS "$node $tactical\n"; print HOSTS "$cfg{dtdlink_ip}\tdtdlink.$node.local.mesh dtdlink.$node" if $cfg{dtdlink_ip}; print HOSTS add_ip_address($cfg{lan_ip}, 1), "\tlocalap\n" unless $cfg{dmz_mode}; open(ETHER, ">/etc/ethers") or die; print ETHER "# automatically generated file - do not edit\n"; print ETHER "# use /etc/ethers.user for custom entries\n"; $netaddr = ip2decimal($cfg{lan_ip}) & ip2decimal($cfg{lan_mask}); foreach(`cat $dhcpfile`) { next if /^\s*#/; next if /^\s*$/; ($mac, $ip, $host) = split /\s+/, $_; $ip = decimal2ip($netaddr + $ip); # filter out addresses that are illegal for the lan subnet next unless validate_same_subnet($ip, $cfg{lan_ip}, $cfg{lan_mask}); next unless validate_ip_netmask($ip, $cfg{lan_mask}); printf ETHER "$mac\t$ip\n"; printf HOSTS "$ip\t$host\n"; } print HOSTS "\n"; close(HOSTS); close(ETHER); system "cat /etc/hosts.user >> /etc/hosts" if -e "/etc/hosts.user"; system "cat /etc/ethers.user >> /etc/ethers" if -e "/etc/ethers.user"; unless($do_basic) { system "cp -f /etc/config.$config/firewall /etc/config"; system "cp -f /etc/config.$config/firewall.user /etc/"; } open(FILE, ">>/etc/config/firewall") or die; if($cfg{dmz_mode}) { print FILE "\nconfig forwarding\n"; print FILE " option src wifi\n"; print FILE " option dest lan\n"; print FILE "\n"; print FILE "\nconfig forwarding\n"; print FILE " option src dtdlink\n"; print FILE " option dest lan\n"; system "uci set firewall.\@zone\[2\].masq=0"; system "uci commit"; } else { print FILE "\n"; print FILE "config 'include'\n"; print FILE " option 'path' '/etc/firewall.dtdlink'\n"; print FILE " option 'reload' '1'\n"; } if ($cfg{olsrd_gw}) { print FILE "\nconfig forwarding\n"; print FILE " option src wifi\n"; print FILE " option dest wan\n"; print FILE "\n"; print FILE "\nconfig forwarding\n"; print FILE " option src dtdlink\n"; print FILE " option dest wan\n"; } foreach(`cat $portfile`) { next if /^\s*#/; next if /^\s*$/; chomp; # set dmz server if(/dmz_ip = (\S+)/ and not $cfg{dmz_mode}) { print FILE "\nconfig redirect\n\toption src wifi\n\toption proto tcp\n\toption src_dip $cfg{wifi_ip}\n\toption dest_ip $1\n\n"; print FILE "config redirect\n\toption src wifi\n\toption proto udp\n\toption src_dip $cfg{wifi_ip}\n\toption dest_ip $1\n\n"; next; } # set port forwarding rule ($intf, $type, $oport, $host, $iport, $enable) = split /[:]/, $_; next unless $enable; if($cfg{dmz_mode}) { next if $intf eq "wifi"; $intf = "wan" if $intf eq "both"; } $match = "option src_dport $oport\n"; if ($type eq "tcp") { $match .= "option proto tcp\n" } elsif($type eq "udp") { $match .= "option proto udp\n" } # uci the host and than # set the inside port unless the rule uses an outside port range $host = "option dest_ip $host\n"; $host .="\toption dest_port $iport\n" unless $oport =~ /-/; if($intf eq "both") { print FILE "\nconfig redirect\n\toption src wifi\n\t$match\toption src_dip $cfg{wifi_ip}\n\t$host\n"; print FILE "config redirect\n\toption src wan\n\t$match\t$host\n"; } elsif($intf eq "wifi") { print FILE "config redirect\n\toption src wifi\n\t$match\toption src_dip $cfg{wifi_ip}\n\t$host\n"; } elsif($intf eq "wan") { print FILE "config redirect\n\toption src wan\n\t$match\t$host\n"; } else { print STDERR "ERROR: unknown interface '$intf'\n"; close(FILE); exit 1; } } close(FILE); # generate the services file if($config eq "mesh") { $servfile = "/etc/config.$config/_setup.services." . ($cfg{dmz_mode} ? "dmz" : "nat"); open(SERV, ">/etc/config/services") or die; foreach(`cat $servfile 2>/dev/null`) { next if /^\s*#/; next if /^\s*$/; chomp; ($name, $link, $proto, $host, $port, $suffix) = split /\|/, $_; $proto = "http" unless $proto; $port = 0 unless $link; $suffix = "" unless $suffix; next unless defined $name and $name ne "" and defined $host and $host ne ""; printf SERV "%s://%s:%s/%s|%s|%s\n", $proto, $host, $port, $suffix, "tcp", $name; } close(SERV); } # generate the local config script open(FILE, ">/etc/local/services") or die; print FILE "#!/bin/sh\n"; unless($cfg{wifi_proto} eq "disabled") { $cfg{wifi_txpower} = wifi_maxpower() if not defined $cfg{wifi_txpower} or $cfg{wifi_txpower} > wifi_maxpower(); $cfg{wifi_txpower} = 1 if $cfg{wifi_txpower} < 1; if(wifi_useschains()){ print FILE "/usr/local/bin/wifi-onbootchains\n"; } print FILE "/usr/sbin/iw dev wlan0 set txpower fixed $cfg{wifi_txpower}00\n"; if(defined $cfg{aprs_lat} and defined $cfg{aprs_lon}) { printf FILE "echo %s,%s > /tmp/latlon.txt\n", $cfg{aprs_lat}, $cfg{aprs_lon}; } if($config eq "mesh") { print FILE "/usr/local/bin/olsrd-watchdog &\n"; print FILE "/usr/local/bin/olsrd-namechange-loop &\n"; } } close(FILE); system "chmod +x /etc/local/services"; # generate olsrd.conf if(-f "/etc/config.$config/olsrd") { open(IN, "/etc/config.$config/olsrd") or die; open(OUT, ">/etc/config/olsrd") or die; while(defined ($line = )) { if($line =~ //) { if($cfg{olsrd_bridge}) { $line =~ s//"wifi" "lan"/ } else { $line =~ s//"lan"/ } } elsif(($parm) = $line =~ /^[^\#].*<(\S+)>/) { $line =~ s/<$parm>/$cfg{$parm}/; } print OUT $line; } if($cfg{dmz_mode}) { print OUT "\n"; print OUT "config Hna4\n"; @parts = split /[.]/, $cfg{dmz_lan_ip}; --$parts[3]; # assume network = lan_ip - 1 print OUT "\toption netaddr ", join(".", @parts),"\n"; print OUT "\toption netmask 255.255.255.", ((0xff << $cfg{dmz_mode}) & 0xff), "\n"; print OUT "\n\n"; } if($cfg{olsrd_gw}) { print OUT "config LoadPlugin\n"; print OUT " option library 'olsrd_dyn_gw.so.0.5'\n"; print OUT " option Interval '60'\n"; print OUT " list Ping '71.42.236.91'\n"; # hsmm-mesh.org\n"; print OUT " list Ping '71.42.236.90'\n"; # hsmm-mesh.org\n"; print OUT " list Ping '8.8.8.8'\n"; # google dns\n"; print OUT " list Ping '8.8.4.4'\n"; # google dns\n"; print OUT "\n\n"; } close(OUT); close(IN); } # indicate whether lan is running in dmz mode system "echo $cfg{dmz_mode} > /etc/config/dmz-mode" if $cfg{dmz_mode}; # Set chains/antenna config elements as they are no longer in the template files if(wifi_useschains()){ $cmd .= "uci set wireless.\@wifi-device[0].rxchain=$cfg{wifi_rxant} >/dev/null 2>&1;"; $cmd .= "uci set wireless.\@wifi-device[0].txchain=$cfg{wifi_txant} >/dev/null 2>&1;"; } else { $cmd .= "uci set wireless.\@wifi-device[0].rxantenna=$cfg{wifi_rxant} >/dev/null 2>&1;"; $cmd .= "uci set wireless.\@wifi-device[0].txantenna=$cfg{wifi_txant} >/dev/null 2>&1;"; } $cmd .= "uci -q commit;"; system $cmd; # finish up unless($auto) { print "configuration complete.\n"; print "you should now reboot the router.\n"; if($config eq "client") { print "\nCurrent ssid setting in /etc/config/wireless:\n"; system "grep ssid /etc/config/wireless"; print "\n"; } } exit 0;