1 
2 /* Web Polygraph       http://www.web-polygraph.org/
3  * Copyright 2003-2011 The Measurement Factory
4  * Licensed under the Apache License, Version 2.0 */
5 
6 #include "base/polygraph.h"
7 
8 #include <ctype.h>
9 #include "xstd/h/net/if.h"
10 #include "xstd/h/iostream.h"
11 #include "xstd/h/iomanip.h"
12 
13 #include "xstd/NetIface.h"
14 #include "xstd/gadgets.h"
15 #include "base/CmdLine.h"
16 #include "base/opts.h"
17 #include "base/polyOpts.h"
18 #include "pgl/PglNetAddrRange.h"
19 
20 
21 class MyOpts: public OptGrp {
22 	public:
MyOpts()23 		MyOpts():
24 			theHelpOpt(this,     "help",         "list of options"),
25 			theVersOpt(this,     "version",      "package version info"),
26 			theIfName(this,      "if <str>",     "interface name"),
27 			theAliases(this,     "aliases <str>","ip(s) or ip range(s) to set as aliases")
28 			{}
29 
30 		virtual bool validate() const;
31 
32 		virtual ostream &printAnonym(ostream &os) const;
33 		virtual bool parseAnonym(const Array<const char *> &opts);
canParseAnonym() const34 		virtual bool canParseAnonym() const { return true; }
35 
36 	public:
37 		HelpOpt theHelpOpt;
38 		VersionOpt theVersOpt;
39 		StrOpt theIfName;
40 		StrArrOpt theAliases;
41 };
42 
43 
44 static MyOpts TheOpts;
45 static NetIface *TheIface = 0;
46 
47 /* MyOpt */
48 
printAnonym(ostream & os) const49 ostream &MyOpts::printAnonym(ostream &os) const {
50 	return os << "[interface_name] [alias] ...";
51 }
52 
parseAnonym(const Array<const char * > & opts)53 bool MyOpts::parseAnonym(const Array<const char *> &opts) {
54 	if (!opts.count())
55 		return true;
56 
57 	int aliasStart = 0;
58 	if (!isdigit(*opts[0])) {
59 		theIfName.val(opts[0]);
60 		aliasStart = 1;
61 	}
62 
63 	for (int i = aliasStart; i < opts.count(); ++i)
64 		theAliases.addItem(opts[i]);
65 
66 	return true;
67 }
68 
validate() const69 bool MyOpts::validate() const {
70 	if (!theIfName)
71 		cerr << "interface name is not specified" << endl;
72 	else
73 		return true;
74 	return false;
75 }
76 
77 static
configureLogs(int prec)78 void configureLogs(int prec) {
79 	configureStream(cout, prec);
80 	configureStream(cerr, prec);
81 	configureStream(clog, prec);
82 }
83 
84 static
configure()85 void configure() {
86 	Socket::Configure();
87 	configureLogs(2);
88 	TheIface = new NetIface;
89 	TheIface->name(TheOpts.theIfName);
90 }
91 
92 static
getPrimaryAddress()93 void getPrimaryAddress() {
94 	NetIface::Primaries addrs;
95 	if (!TheIface->primaries(addrs)) {
96 		clog << TheIface->name() << ": cannot get primary address(es) of " <<
97 			"the network interface" << endl;
98 		return;
99 	}
100 	if (addrs.vFour) {
101 		clog << TheIface->name() << ": primary IPv4 address is " <<
102 			addrs.vFour << endl;
103 	}
104 	if (addrs.vSix) {
105 		clog << TheIface->name() << ": primary IPv6 address is " <<
106 			addrs.vSix << endl;
107 	}
108 }
109 
110 static
delOldAliases()111 void delOldAliases() {
112 	const int delCount = TheIface->delAliases();
113 	Must(delCount >= 0);
114 	clog << TheIface->name() << ": deleted "	<< delCount << " old aliases" << endl;
115 }
116 
117 static
addNewAliases(const Array<NetAddr * > & addrs,const InAddress & netmask)118 void addNewAliases(const Array<NetAddr*> &addrs, const InAddress &netmask) {
119 	Array<InAddress> aliases(addrs.count());
120 	for (int i = 0; i < addrs.count(); ++i)
121 		aliases.append(addrs[i]->addrN());
122 	Must(TheIface->addAliases(aliases, netmask));
123 
124 	static int newCount = 0;
125 	newCount += aliases.count();
126 	clog << TheIface->name() << ": created "
127 		<< aliases.count() << " new aliases "
128 		<< "( " << newCount << " total )"
129 		<< endl;
130 }
131 
main(int argc,char * argv[])132 int main(int argc, char *argv[]) {
133 
134 	CmdLine cmd;
135 	cmd.configure(Array<OptGrp*>() << &TheOpts);
136 	if (!cmd.parse(argc, argv) || !TheOpts.validate())
137 		return -1;
138 
139 	configure();
140 
141 	clog << TheOpts.theIfName << ": ";
142 	if (TheOpts.theAliases)
143 		TheOpts.theAliases.report(clog << "reseting aliases to ");
144 	else
145 		clog << "no new alias specified; will just delete old ones.";
146 	clog << endl;
147 
148 	getPrimaryAddress();
149 	delOldAliases();
150 
151 	for (int i = 0; i < TheOpts.theAliases.val().count(); ++i) {
152 		const String &alias = *TheOpts.theAliases.val()[i];
153 
154 		PglNetAddrRange aliasParser;
155 		if (!aliasParser.parse(alias)) {
156 			cerr << TheOpts.theIfName << ": malformed alias: `" << alias << "' alias" << endl;
157 			return -2;
158 		}
159 		Array<NetAddr*> aliases;
160 		aliasParser.toAddrs(aliases);
161 		for (int i = 0; i < aliases.count(); ++i) {
162 			if (!aliases[i]->addrN().known()) {
163 				cerr << "error: can't parse alias " << aliases[i]->addrA() << endl;
164 				return -1;
165 			}
166 		}
167 
168 		InAddress netmask;
169 		aliasParser.netmask(netmask);
170 		addNewAliases(aliases, netmask);
171 	}
172 
173 	return 0;
174 }
175