The First Step of Rapid Tool Smithing
So I have not been to productive in a traditional sense over the last few months. I have been excercising my C++ development skills and spending a few weeks prototyping tools, based on interest and needs. Only knowledge has been the real product of my work. I have been focusing and learning a about how to perform rapid prototyping along with learning to augment functionality from other open sources of code.
Research is a slippery slope and it is hard to quantify a rate of return. This goes for any type of research in any industry. The idea is that to be novel, you must invest time and effort, so identifying as many shortcuts as possible is a valuable skill. For instance, if I want to implement a DNS scanner, I don’t want to rewrite the entire DNS protocol, nor do I want write the network code, threading, etc. I want to leverage existing sources and frameworks for those elements. Additionally, programming languages should be seriously considered. In this case, I am looking at C++, however, higher level programming languages such Python or Ruby could serve most beneficial in a very rapid PoC environment. This post will detail some of the preliminary decisions that a researcher may encounter and then give an overview into how to work through various vague compilation and linker errors, showing the time savings from short cuts.
First, what I generally do determine which language will be most convenient. Higher level languages are very easy to prototype in, and there are a number of libraries, modules, and frameworks. However, the level of control and platform speed will dictate whether these languages can be used. For example if I am looking for functionality versus performance, I would use Python over C/C++, and this decision may even be tied to the available resources such as source code.
In this case I chose C++, because I want to achieve performance gains, so now I need to track down sources or projects. After a quick search for DNS projects, Bind appeared to dominate a majority of the results. So, I decided to start by reviewing the Bind projects capabilities. After I downloaded the latest branch, I reviewed the code looked at what I knew would be important to me. As it turns out the code base was fairly complete, however, the branch was not made to compile in Visual Studio, yet.
This is one of those forks in the road. Do I stick with what I have, derive something, or build something from scratch? This question should always be first and foremost in your mind, and with experience it gets easier to answer. There are a number of complexities that may arise ranging from programming language eccentrities, platform capabilities, functional needs, development time, along with a myriad of other variables, and with each project, the experience and knowledge accumulates, which allows someone to follow that path of least resistance to meet the next milestone.
Before I continue on, I want to stress why I chose the Bind 10 development branch. Ready, it was the path of least resistance. If you review development and compilation docs for Bind 9, it requires alot of dependencies which means lots more effort. Bind 10 requires Boost Libraries for cpp, which is relatively easy to download and install, or at the very least compile. Note: If you are using Visual Studio 2010 Beta, you need to compile from source, and this is actually very easy if you follow the instructions on the tutorial. Once I found Bind 10, I developed a sort of tunnel vision, so I did not seek out any other candidate projects, and in this process, time is precious and a resource you can not waste.
Continuing on to the next battle in rapid tool smithing. The desired functionality was in the DNS and Exception source directories, so I copied the libs directory, added the required VS filters, and then the source files in those filters. Now, I write my main file, include the message.h, compile, and fail.
The first reason I failed was because there are some missing source code files that needed to be generated from a script and inclusions for “config.h” which is an artifact of the auto configuration process. To address the missing source files, I used intuition. I am not quite sure how, but I ended up looking at one file in particular, “gen-rdatacode.py”. Basically, I peeked at the file, renamed it to a python script, tried to run it, and failed again. No problem, I read over the file and realized it was relying on the auto configuration process, so I just went through and updated all auto generation tags (e.g. “@src@” with “.\”). Then I ran the script, encountered some minor fails, but persisted and got the “real” missing source files generated. I also commented out all the ‘#include “config.h”‘ requirements in other source files, followed by updating the project’s source files.
Ok, time to compile again, now I found some inconsistencies in the inet_pton and the inet_ntop, which are declared in *nix headers, which are not present on Windows (without cygwin). So, I just added the WinTcpIp.h include and added some preprocessor logic, to jump over the *nix includes. I also got errors that the inet_ntop and inet_pton are not defined, which was an indicator that I needed to turn off the Unicode compilation for the project, after which I attempted another compile. Note that inet_ntop and inet_pton are part of the ANSI specification, thus if Unicode is enabled, the two functions are not defined.
After this I compiled and got one of the most obscure errors ever:
cannot convert from 'std::_Tree_const_iterator<_Mytree>' to 'std::_Tree_const_iterator<_Mytree>' c:\code\fiercplusplus\fiercplusplus\src\lib\dns\messagerenderer.cc 262
Then I looked at the issue much more closely:
1> while trying to match the argument list '(std::_Tree_const_iterator<_Mytree>, std::_Tree_const_iterator<_Mytree>)'
1> with
1> [
1> _Mytree=std::_Tree_val<std::_Tset_traits<isc::dns::`anonymous-namespace'::NameCompressNode,isc::dns::`anonymous-namespace'::NameCompare,std::allocator<isc::dns::`anonymous-namespace'::NameCompressNode>,false>>
1> ]
1> and
1> [
1> _Mytree=std::_Tree_val<std::_Tset_traits<isc::dns::`anonymous-namespace'::NameCompressNode,std::less<isc::dns::`anonymous-namespace'::NameCompressNode>,std::allocator<isc::dns::`anonymous-namespace'::NameCompressNode>,false>>
1> ]
Someone with a sharp eye will notice that the top description includes “std::less<isc::dns::`anonymous-namespace’” and the bottom type description does not look like the top one. As it turns out, the default template declaration uses the std::less<T> to make the comparison, rather than the struct NameCompare which what should be used to make the comparison, thus the ambiguity of ‘std::_Tree_const_iterator<_Mytree>’ to ‘std::_Tree_const_iterator<_Mytree>’ melts away. The error is simply fixed by changing the definition/declaration in the following manner:
from: std::set<NameCompressNode>::const_iterator notfound = impl_->nodeset_.end();
to: std::set<NameCompressNode, NameCompare>::const_iterator notfound = impl_->nodeset_.end();
This issue alone took me about 1-2 hours to resolve. Googling was less than helpful, and this is the reason the resolution took so long. Contrary to popular belief Topeka, does not have all the answers. So, stepping back from the problem is sometimes the best way to step closer to the problem.
Much closer to compiling now. Now we are getting linker errors, which means we are very close. The errors I encountered are linker ones, where symbols cannot be identified. The issue was initially perplexing, because the code is part of the project sources and not an external lib. So, I go back and review yet another vague linker warning, “warning LNK4042: object specified more than once; extras ignored Debug\objs\exceptions.obj”. The warning is very explicit and tells me what happened, meaning two files will compile to the same object filename. What does not make sense, the filename collision (e.g. exceptions.cc) happens with two files in different directories. The warning and MSDN description does not give me no direction about how to resolve this issue. I actually used a life line, and asked a friend, who helped me identify the solution. Essentially, I had to update the intermediate output directory for the source files. The solution was found on stack overflow, and my Topekaing skills did not come up with any results that detailed this process. Special Thanks to Rudolph Araujo for helping out on that one.
After working through all that in about 5-6 hours, there is an immediate realization of time savings versus if I had had been ambitious and tried to develop and test my own stuff from scratch.
Posted in Development, Hacking, Research having 1 comment »
August 10th, 2010 at 4:31 pm
great stream-of-consciousness description of what you’re working on. can you do this for the other ~894 (hey, everybody works 14 hour days, right?) hours that you’ve been doing this type research?