diff --git a/ipscan/.classpath b/ipscan/.classpath new file mode 100755 index 00000000..834385d8 --- /dev/null +++ b/ipscan/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipscan/.project b/ipscan/.project new file mode 100755 index 00000000..bd3c4dd4 --- /dev/null +++ b/ipscan/.project @@ -0,0 +1,20 @@ + + + ipscan + + + swt + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.jem.beaninfo.BeanInfoNature + + diff --git a/ipscan/.settings/org.eclipse.jdt.core.prefs b/ipscan/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 00000000..45a8784d --- /dev/null +++ b/ipscan/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,256 @@ +#Thu Dec 14 22:09:10 EET 2006 +eclipse.preferences.version=1 +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes= +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=1 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false +org.eclipse.jdt.core.formatter.comment.format_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false diff --git a/ipscan/.settings/org.eclipse.jdt.ui.prefs b/ipscan/.settings/org.eclipse.jdt.ui.prefs new file mode 100755 index 00000000..d5cbab0b --- /dev/null +++ b/ipscan/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,11 @@ +#Thu Dec 14 22:09:10 EET 2006 +eclipse.preferences.version=1 +formatter_profile=_Angry IP Scanner +formatter_settings_version=10 +internal.default.compliance=user +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.javadoc=true +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/ipscan/.settings/org.eclipse.ltk.core.refactoring.prefs b/ipscan/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100755 index 00000000..cbf5c911 --- /dev/null +++ b/ipscan/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,3 @@ +#Thu Jul 27 00:09:24 EEST 2006 +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/ipscan/.settings/org.eclipse.wst.validation.prefs b/ipscan/.settings/org.eclipse.wst.validation.prefs new file mode 100755 index 00000000..db788f22 --- /dev/null +++ b/ipscan/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,6 @@ +#Thu Jul 27 00:09:24 EEST 2006 +DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator; +USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.jst.jsp.core.internal.validation.JSPDirectiveValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsp.core.internal.validation.JSPELValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.jst.jsp.core.internal.validation.JSPJavaValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.html.internal.validation.HTMLValidator; +USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.jst.jsp.core.internal.validation.JSPDirectiveValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsp.core.internal.validation.JSPELValidator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.jst.jsp.core.internal.validation.JSPJavaValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.wst.html.internal.validation.HTMLValidator; +USER_PREFERENCE=overrideGlobalPreferencesfalse +eclipse.preferences.version=1 diff --git a/ipscan/build.xml b/ipscan/build.xml new file mode 100755 index 00000000..b28e9fb3 --- /dev/null +++ b/ipscan/build.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipscan/ext/emma/emma.jar b/ipscan/ext/emma/emma.jar new file mode 100755 index 00000000..534143b6 Binary files /dev/null and b/ipscan/ext/emma/emma.jar differ diff --git a/ipscan/ext/emma/emma_ant.jar b/ipscan/ext/emma/emma_ant.jar new file mode 100755 index 00000000..cadb5723 Binary files /dev/null and b/ipscan/ext/emma/emma_ant.jar differ diff --git a/ipscan/ext/picocontainer/LICENSE.txt b/ipscan/ext/picocontainer/LICENSE.txt new file mode 100755 index 00000000..638e89a6 --- /dev/null +++ b/ipscan/ext/picocontainer/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright (c) 2003, PicoContainer Organization +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + Neither the name of the PicoContainer Organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/ipscan/ext/picocontainer/picocontainer-1.0.jar b/ipscan/ext/picocontainer/picocontainer-1.0.jar new file mode 100755 index 00000000..4b452806 Binary files /dev/null and b/ipscan/ext/picocontainer/picocontainer-1.0.jar differ diff --git a/ipscan/ext/retroguard/GPL.txt b/ipscan/ext/retroguard/GPL.txt new file mode 100755 index 00000000..13a56b1d --- /dev/null +++ b/ipscan/ext/retroguard/GPL.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ipscan/ext/retroguard/Readme.txt b/ipscan/ext/retroguard/Readme.txt new file mode 100755 index 00000000..106ec403 --- /dev/null +++ b/ipscan/ext/retroguard/Readme.txt @@ -0,0 +1,58 @@ + + ** RETROGUARD(tm) BYTECODE OBFUSCATOR ** + +-- RetroGuard v2.0.5, released 25th August 2005 -- + +Thank you for downloading this release of the RetroGuard +bytecode obfuscator. If you have questions about using RetroGuard, +or wish to report a bug to be fixed for the next release, +please contact web@retrologic.com + + +This software is distributed under a "dual license" model: + + - GNU GPL for non-commercial projects and for commercial trial integration; + + - a subscription-based commercial license for commercial projects. + +In summary, if your project is commercial then RetroGuard is commercial; +if your project is free software then RetroGuard is free software. + +To obtain a license agreement for commercial use of this software, +please visit http://www.retrologic.com/retroguard-main.html or contact +Retrologic Systems at web@retrologic.com + + +Included in this release are the following files and directories: + +Readme.txt : This file. + +GPL.txt : For non-commercial projects, RetroGuard is distributed + under the GNU General Public License. +-OR- +License.txt : For commercial projects, RetroGuard is distributed under + a subscription-based commercial license. + +retroguard.jar : A JAR (Java ARchive) file containing the classes that + make up the RetroGuard Bytecode Obfuscator. + +src-dist.tar.gz: RetroGuard source files (GPL, non-commercial release only). + + +The latest documentation for RetroGuard can be found online at: + + http://www.retrologic.com/retroguard-docs.html + +The change history of the software can be found at: + + http://www.retrologic.com/retroguard-changes.html + +Answers to common questions about obfuscation and RetroGuard can be found at: + + http://www.retrologic.com/retroguard-faq.html + + +If you have any questions please contact: + + web@retrologic.com + diff --git a/ipscan/ext/retroguard/retroguard.conf b/ipscan/ext/retroguard/retroguard.conf new file mode 100755 index 00000000..e112fd68 --- /dev/null +++ b/ipscan/ext/retroguard/retroguard.conf @@ -0,0 +1,13 @@ +.option Application +.option MapClassString + +.method;native ** * and_class + +.class net/azib/ipscan/feeders/*Feeder public +.class net/azib/ipscan/fetchers/*Fetcher public +.class net/azib/ipscan/exporters/*Exporter public +.class net/azib/ipscan/**/*Exception +.class net/azib/ipscan/config/GlobalConfig public +.class net/azib/ipscan/resources/* + +#.class org/eclipse/swt/**/OS diff --git a/ipscan/ext/retroguard/retroguard.jar b/ipscan/ext/retroguard/retroguard.jar new file mode 100755 index 00000000..98f79f74 Binary files /dev/null and b/ipscan/ext/retroguard/retroguard.jar differ diff --git a/ipscan/ext/rocksaw/LICENSE b/ipscan/ext/rocksaw/LICENSE new file mode 100755 index 00000000..d6456956 --- /dev/null +++ b/ipscan/ext/rocksaw/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ipscan/ext/rocksaw/NOTICE b/ipscan/ext/rocksaw/NOTICE new file mode 100755 index 00000000..3ee836b9 --- /dev/null +++ b/ipscan/ext/rocksaw/NOTICE @@ -0,0 +1,2 @@ +This product includes software developed by +Daniel F. Savarese (http://www.savarese.org/). diff --git a/ipscan/ext/rocksaw/README b/ipscan/ext/rocksaw/README new file mode 100755 index 00000000..74666927 --- /dev/null +++ b/ipscan/ext/rocksaw/README @@ -0,0 +1,161 @@ +$Id: README 6877 2006-04-14 00:56:38Z dfs $ + +===== +ABOUT +===== + +RockSaw is a simple API for performing network I/O with raw +sockets in Java. + + +============ +REQUIREMENTS +============ + +The 0.4.5 version of RockSaw has been compiled and tested on Linux, +Win32 with Cygwin/MinGW/Winsock or Visual C++, and Solaris 8/9/10. It +should compile on other POSIX systems using the GNU tool chain. + +The Ping.java example program requires VServ TCP/IP version 0.7.x +(http://www.savarese.org/software/vserv-tcpip.html) or later to +compile because it uses the ICMPEchoPacket class. + +librocksaw.so in the binary distribution is pre-compiled for Linux +i386 and rocksaw.dll is pre-compiled for Win32 using Visual C++. + +J2SE 1.3 or greater is required to compile because of the use of +Runtime.addShutdownHook on Win32. If you have a need to support +J2SE 1.2, we can find another solution for calling WSACleanup on +Win32 platforms. + +Winsock2 (ws2_32.dll) is required on Win32 platforms. + +========= +COMPILING +========= + +You must have the JDK_HOME environment variable set and pointing to +the directory where the Java Development Kit is installed. Otherwise, +the JNI headers will not be found. RockSaw has been tested primarily +with J2SE 5 JDK 1.5, but it compiles with the J2SE 2 1.3, and 1.4 +SDKs. Only the Ping.java example program requires J2SE 5. + +The source code requires Apache Ant (http://ant.apache.org/), GNU +make, and GCC to compile. On Windows, you must either have Visual C++ +installed or have Cygwin and MinGW installed with support for the +Cygwin GCC -mno-cygwin option (http://www.cygwin.com/). Autoconf +support may be added somewhere down the line if warranted. + +The command + + ant -projecthelp + +will list all build targets in build.xml. There are very few files +in the source tree: + + src/java Java source code + src/jni The C JNI source and Makefile + +When you compile the source with + + ant jar + +the C source will also be built by execing a call to gmake in src/jni. +A jar file and shared library will be created and placed in the lib/ +directory. They will be called: + + rocksaw-version.jar + librocksaw.so + +Currently there is no version number for the shared library. On +Win32 systems, the shared library will be called: + + rocksaw.dll + +The version of Winsock linked to on Windows can be changed with +the jni.winsock property. By default, it is set to ws2_32, +which is Winsock2. + +J2SE 1.4/1.3/1.2 +------------------ + +You may have to override the javac.args, javac.source, and +javac.target properties because the -Xlint:unchecked parameter +is only valid for J2SE 5. For example, to compile for +J2SE 1.3: + + ant -Djavac.args="" -Djavac.source=1.3 -Djavac.target=1.3 jar + +Win32: CYGWIN +------------- + +When compiling with cygwin, you may need to redefine the jni.make +property because it is set to "gmake" by default. Cygwin doesn't +include a gmake executable for GNU Make. It is named only make. +Therefore, you may have to use the following command line: + + ant -Djni.make=make jar + +Alternatively, you can edit the build.properties file. + +Win32: Visual C++ +----------------- + +To compile using Visual C++, you have to override the default +compiler command, make command, and makefile properties: + + jni.cc + jni.make + jni.makefile + +You can override these on the command line or in build.properties. +For example, to compile using Visual C++, you would use the +following command: + + ant -Djni.cc=cl -Djni.make=nmake -Djni.makefile=Makefile.win32 jar + +Make sure your JDK_HOME environment variable is set and that +you've run either the vcvars.bat or vsvars32.bat command +(depending on the version of Visual C++ you're using) to set +your paths for the command line tools. + +Ping Example +------------ + +The example Ping program can be compiled separately with the +example.compile target, but requires VServ TCP/IP to compile. The +classpath.vserv-tcpip property in build.properties must point to the +VServ TCP/IP jar, which by default is expected to be present in the +lib/ directory. Then you can compile the program with: + + ant example.compile + + +========= +LICENSING +========= + +RockSaw is Copyright 2004-2005 by Daniel F. Savarese and licensed +under the Apache License 2.0 as described in the files: + + LICENSE + NOTICE + + +===== +NOTES +===== + +On most operating systems, you must have root access or administrative +privileges to use raw sockets. + +The API is at a fairly crude stage of development (i.e., the minimum +required to do the job it needed to do), but is functional. Don't +hesitate to submit patches that enhance the functionality. + + +======= +CONTACT +======= + +To contact me see http://www.savarese.org/contact.html diff --git a/ipscan/ext/rocksaw/lib/librocksaw.so b/ipscan/ext/rocksaw/lib/librocksaw.so new file mode 100755 index 00000000..e8c0fc04 Binary files /dev/null and b/ipscan/ext/rocksaw/lib/librocksaw.so differ diff --git a/ipscan/ext/rocksaw/lib/rocksaw.dll b/ipscan/ext/rocksaw/lib/rocksaw.dll new file mode 100755 index 00000000..d023bf68 Binary files /dev/null and b/ipscan/ext/rocksaw/lib/rocksaw.dll differ diff --git a/ipscan/ext/rocksaw/lib/tmp.jar b/ipscan/ext/rocksaw/lib/tmp.jar new file mode 100755 index 00000000..a2187642 Binary files /dev/null and b/ipscan/ext/rocksaw/lib/tmp.jar differ diff --git a/ipscan/ext/rocksaw/src/java/org/savarese/rocksaw/net/RawSocket.java b/ipscan/ext/rocksaw/src/java/org/savarese/rocksaw/net/RawSocket.java new file mode 100755 index 00000000..b90d40a1 --- /dev/null +++ b/ipscan/ext/rocksaw/src/java/org/savarese/rocksaw/net/RawSocket.java @@ -0,0 +1,615 @@ +/* + * $Id: RawSocket.java 5979 2005-11-09 18:11:02Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.rocksaw.net; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.SocketException; + +/** + *

The RawSocket class provides a strictly utilitarian API for + * performing I/O with raw sockets. The API is currently crude, but + * functional. It should evolve into something more feature-complete + * and flexible.

+ * + *

We throw java.io.InterruptedIOException when read/write + * operations time out because java.net.SocketTimeoutException is + * present only in J2SE 1.4 and up. By using InterruptedIOException, + * we allow programmers to use the software with J2SE 1.2 and 1.3.

+ * + *

Socket options should not be set until the socket has been + * opened.

+ * + *

Important! On most operating systems, you must have root + * access or administrative privileges to use raw sockets.

+ * + * @author Daniel F. Savarese + */ + +public class RawSocket { + + /** + * A protocol family constant for {@link #open} indicating IPv4. + * This should be moved to another class. + */ + public static final int PF_INET = 2; + + /** + * A protocol family constant for {@link #open} indicating IPv6. + * This should be moved to another class. + */ + public static final int PF_INET6 = 10 ; + + /** + * Initializes any system resources used by the RockSaw library. + * Really, all it does is call WSAStartup on Win32. It may be + * called multiple times (only the first call has any effect), but + * each call must be matched with a corresponding call to + * RockSawShutdown(). + * + * @return zero if successful, otherwise some non-zero value. + */ + private native static int __RockSawStartup(); + + /** + * Deallocates any system resources used by the RockSaw library. + * Really, all it does is call WSACleanup on Win32. + */ + private native static void __RockSawShutdown(); + + static { + System.loadLibrary("rocksaw"); + if(__RockSawStartup() != 0) + throw new UnsatisfiedLinkError(__getErrorMessage()); + + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + __RockSawShutdown(); + } + }); + } + + private static final int __UNDEFINED = -1; + + /** + * TimeVal is a convenience class for tracking select timeouts. + * Should we implement select outside of this class, we can make + * this a public top-level class with proper getters and setters. + */ + private static final class TimeVal { + int seconds; + int microseconds; + + TimeVal() { + seconds = microseconds = 0; + } + + void setInMilliseconds(int milliseconds) { + seconds = milliseconds / 1000; + + if(seconds > 0) + milliseconds-=(seconds*1000); + + microseconds = milliseconds * 1000; + } + + int getInMilliseconds() { + return (seconds * 1000 + microseconds / 1000); + } + + boolean isZero() { + return (seconds == 0 && microseconds == 0); + } + } + + private int __socket; + private int __family; + private TimeVal __stimeout, __rtimeout; + private boolean __useSelectTimeout; + + /** + * Creates an uninitialized socket. If the {@code os.name} system + * property starts with the string "SunOS", + * {@link #setUseSelectTimeout} is set to true (because Solaris does not + * support socket send and receive timeouts), otherwise it is false + * by default. + */ + public RawSocket() { + __socket = __UNDEFINED; + __family = __UNDEFINED; + __stimeout = new TimeVal(); + __rtimeout = new TimeVal(); + + String os = System.getProperty("os.name"); + + if(os != null && os.startsWith("SunOS")) + setUseSelectTimeout(true); + else + setUseSelectTimeout(false); + } + + + /** + * Tests if the socket has been opened. + * + * @return True if the socket is open. + */ + public boolean isOpen() { + return (__socket > 0); + } + + + /** + * Writes a system error message into a StringBuffer. + * The message is appended to the supplied StringBuffer argument. + * This is not a thread safe call because it relies on the value + * of errno, which may be altered at any time by another thread. + * + * @param buffer The buffer in which to store the error message. + */ + private native static void __getErrorMessage(StringBuffer buffer); + + private static String __getErrorMessage() { + StringBuffer buf = new StringBuffer(); + __getErrorMessage(buf); + return buf.toString(); + } + + private static void __throwIOException() throws IOException { + throw new IOException(__getErrorMessage()); + } + + private static void __throwSocketException() throws SocketException { + throw new SocketException(__getErrorMessage()); + } + + private static void __throwInterruptedIOException() + throws InterruptedIOException + { + throw new InterruptedIOException(__getErrorMessage()); + } + + private native static int __socket(int protocolFamily, int protocol); + + + /** + *

Returns the protocol number corresponding to the given protocol name. + * For example, {@code getProtocolByName("icmp");} should return 1 and + * {@code getProtocolByName("udp");} should return 17. The native system + * protocol database is used to look up the protocol numbers.

+ * + *

This method really belongs in another class, probably in + * vserv-tcpip, but is currently included here as a convenience. It + * may be moved elsewhere in the 1.0 release API.

+ * + * @return The protocol number corresponding to the given protocol name. + * If the protocol name cannot be found, returns a negative value. + */ + public native static final int getProtocolByName(String name); + + + /** + * Opens a raw socket. + * + * @param protocolFamily The protocol family of the socket (e.g., + * {@link #PF_INET} or {@link #PF_INET6}). + * @param protocol The protocol within the protocol family. {@link + * #getProtocolByName} should be used to obtain protocol numbers. + * @exception IllegalStateException If the object instance is + * already open. + * @exception IOException If an error occurs while opening the socket. + */ + public void open(int protocolFamily, int protocol) + throws IllegalStateException, IOException + { + if(isOpen()) + throw new IllegalStateException(); + __socket = __socket(protocolFamily, protocol); + + if(__socket < 0) { + __socket = __UNDEFINED; + __throwIOException(); + } + + __family = protocolFamily; + } + + private native static int __close(int socket); + + /** + * Closes the socket. + * + * @exception IOException If an I/O error occurs. + */ + public void close() throws IOException { + int result = __close(__socket); + __socket = __UNDEFINED; + __family = __UNDEFINED; + + if(result != 0) + __throwIOException(); + } + + /** + * @return True if errno equals EAGAIN or EWOULDBLOCK. + */ + private native boolean __isErrorEAGAIN(); + + private native static int __setIPHeaderInclude(int socket, boolean on); + + /** + * @return A negative value if an error occurs, else zero for false and + * a positive value for true. + */ + private native static int __getIPHeaderInclude(int socket); + + + /** + * Sets or unsets the IP_HDRINCL socket option. Setting this option + * causes IPv4 packet writes to expect the entire IP packet, + * starting from the header. The default behavior is to only expect + * the data payload. This option is valid only for IPv4 sockets. + * + * @param on True if headers should be included, false if not. + * @exception SocketException If the option setting could not be altered. + */ + public void setIPHeaderInclude(boolean on) throws SocketException { + int result = __setIPHeaderInclude(__socket, on); + + if(result < 0) + __throwSocketException(); + } + + + /** + * Retrieves the current setting of the IP_HDRINCL option. + * + * @return True if the IP_HDRINCL option is set, false if not. + * @exception SocketException If the option value could not be retrieved. + */ + public boolean getIPHeaderInclude() throws SocketException { + int result = __getIPHeaderInclude(__socket); + + if(result < 0) + __throwSocketException(); + + return (result > 0); + } + + + private native static int __setSendBufferSize(int socket, int size); + + /** + * Sets the send buffer size (SO_SNDBUF). + * + * @param size The size of the send buffer. + * @exception SocketException If the option value could not be set. + */ + public void setSendBufferSize(int size) throws SocketException { + int result = __setSendBufferSize(__socket, size); + + if(result < 0) + __throwSocketException(); + } + + + private native static int __getSendBufferSize(int __socket); + + /** + * Retrieves the send buffer size (SO_SNDBUF). + * + * @return The size of the send buffer. + * @exception SocketException If the option value could not be retrieved. + */ + public int getSendBufferSize() throws SocketException { + int result = __getSendBufferSize(__socket); + + if(result < 0) + __throwSocketException(); + + return result; + } + + + private native static int __setReceiveBufferSize(int socket, int size); + + /** + * Sets the receive buffer size (SO_RCVBUF). + * + * @param size The size of the receive buffer. + * @exception SocketException If the option value could not be set. + */ + public void setReceiveBufferSize(int size) throws SocketException { + int result = __setReceiveBufferSize(__socket, size); + + if(result < 0) + __throwSocketException(); + } + + + private native static int __getReceiveBufferSize(int socket); + + /** + * Retrieves the receive buffer size (SO_RCVBUF). + * + * @return The size of the receive buffer. + * @exception SocketException If the option value could not be retrieved. + */ + public int getReceiveBufferSize() throws SocketException { + int result = __getReceiveBufferSize(__socket); + + if(result < 0) + __throwSocketException(); + + return result; + } + + /** + * @return Zero if the socket is ready for I/O, negative value if + * timed out or error occurred. + */ + private native static + int __select(int socket, boolean read, int seconds, int microseconds); + + + /** + *

Sets whether or not socket send/receive timeouts should be + * emulated by using the POSIX {@code select} function. Not all + * platforms support socket send/receive timeouts and this method + * provides a means to reproduce the same effect.

+ * + *

This method is not guaranteed to be retained in the 1.0 API. We + * may find a better way to provide support for read/write timeouts + * on all platforms. Technically, it's better to simply use + * non-blocking I/O rather than rely on socket timeouts, but we have + * yet to add a non-blocking I/O interface.

+ * + * @param useSelect true if {@code select} should be used to + * implement timeouts, false if not. + */ + public void setUseSelectTimeout(boolean useSelect) { + __useSelectTimeout = useSelect; + } + + + /** + *

Determines whether or not socket send/receive timeouts are + * emulated by using the POSIX {@code select} system function. + * Not all platforms support socket send/receive timeouts. The + * default value is false except for platforms where the {@code + * os.name} property starts with the string "SunOS".

+ * + * @return True if send/receive timeouts are emulated with select, + * false if not. + */ + public boolean getUseSelectTimeout() { + return __useSelectTimeout; + } + + + private native static int __setSendTimeout(int socket, int timeout); + + /** + * Sets the send timeout (SO_SNDTIMEO). A timeout of zero indicates + * an infinite timeout. A negative timeout is undefined. + * + * @param timeout The send timeout in milliseconds. + * @exception SocketException If the option value could not be set. + */ + public void setSendTimeout(int timeout) throws SocketException { + __stimeout.setInMilliseconds(timeout); + + if(!getUseSelectTimeout()) { + int result = + __setSendTimeout(__socket, timeout); + + if(result < 0) + __throwSocketException(); + } + } + + + private native static int __getSendTimeout(int socket); + + /** + * Retrieves the send timeout (SO_SNDTIMEO). + * + * @return The send timeout in milliseconds. + * @exception SocketException If the option value could not be set. + */ + public int getSendTimeout() throws SocketException { + int result; + + if(getUseSelectTimeout()) + result = __stimeout.getInMilliseconds(); + else { + result = __getSendTimeout(__socket); + + if(result < 0) + __throwSocketException(); + } + + return result; + } + + + private native static int __setReceiveTimeout(int socket, int timeout); + + /** + * Sets the receive timeout (SO_RCVTIMEO). A timeout of zero indicates + * an infinite timeout. A negative timeout is undefined. + * + * @param timeout The receive timeout in milliseconds. + * @exception SocketException If the option value could not be set. + */ + public void setReceiveTimeout(int timeout) throws SocketException { + __rtimeout.setInMilliseconds(timeout); + + if(!getUseSelectTimeout()) { + int result = + __setReceiveTimeout(__socket, timeout); + + if(result < 0) + __throwSocketException(); + } + } + + + private native static int __getReceiveTimeout(int socket); + + /** + * Retrieves the receive timeout (SO_RCVTIMEO). + * + * @return The receive timeout in milliseconds. + * @exception SocketException If the option value could not be set. + */ + public int getReceiveTimeout() throws SocketException { + int result; + + if(getUseSelectTimeout()) + result = __rtimeout.getInMilliseconds(); + else { + result = __getReceiveTimeout(__socket); + + if(result < 0) + __throwSocketException(); + } + + return result; + } + + + private native static int __recvfrom(int socket, byte[] data, int offset, + int length, int family, byte[] address); + + /** + * Reads packet data from the socket. IPv4 ({@link #PF_INET}) + * packets will be delivered in their entirety, including the IP + * header. IPv6 ({@link #PF_INET6}) packet data will not include + * the IPV6 header. + * + * @param address The source to read from. + * @param data The buffer in which to store the packet data. + * @param offset The offset into the buffer where the data should + * be stored. + * @param length The number of bytes to read. + * @exception IllegalArgumentException If the offset or lengths are invalid. + * @exception IOException If an I/O error occurs. + * @exception InterruptedIOException If the read operation times out. + * @return The number of bytes read. + */ + public int read(InetAddress address, byte[] data, int offset, + int length) + throws IllegalArgumentException, IOException, InterruptedIOException + { + if(offset < 0 || length < 0 || length > data.length - offset) + throw new IllegalArgumentException("Invalid offset or length."); + + int result = 0; + + if(getUseSelectTimeout() && !__rtimeout.isZero()) + result = + __select(__socket, true, __rtimeout.seconds, __rtimeout.microseconds); + //System.out.println("s" + System.currentTimeMillis()); + + // ??? setsockopt(ssock, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt)); + + if(result == 0) + result = + __recvfrom(__socket, data, offset, length, __family, + address.getAddress()); + //System.out.println("e" + System.currentTimeMillis()); + + if(result < 0) { + if(__isErrorEAGAIN()) + __throwInterruptedIOException(); + else + __throwIOException(); + } + + return result; + } + + + /** Same as {@code read(address, data, 0, data.length);} */ + public int read(InetAddress address, byte[] data) + throws IOException, InterruptedIOException + { + return read(address, data, 0, data.length); + } + + + private native static int __sendto(int socket, byte[] data, int offset, + int length, int family, byte[] address); + + + + /** + * Writes packet data to the socket. The data should not include + * the IP header. IPv4 ({@link #PF_INET}) sockets may set the + * IP_HDRINCL option with {@link #setIPHeaderInclude}, in which case the + * packet data should include the IP header. + * + * @param address The destination to write to. + * @param data The buffer from which to copy the packet data. + * @param offset The offset into the buffer where the data starts. + * @param length The number of bytes to write. + * @exception IllegalArgumentException If the offset or lengths are invalid. + * @exception IOException If an I/O error occurs. + * @exception InterruptedIOException If the write operation times out. + * @return The number of bytes written. + */ + public int write(InetAddress address, byte[] data, int offset, int length) + throws IllegalArgumentException, IOException, InterruptedIOException + { + if(offset < 0 || length < 0 || length > data.length - offset) + throw new IllegalArgumentException("Invalid offset or length."); + + int result = 0; + + if(getUseSelectTimeout() && !__stimeout.isZero()) + result = + __select(__socket, false, __stimeout.seconds, __stimeout.microseconds); + + if(result == 0) + result = + __sendto(__socket, data, offset, length, __family, + address.getAddress()); + + if(result < 0) { + if(__isErrorEAGAIN()) + __throwInterruptedIOException(); + else + __throwIOException(); + } + + return result; + } + + + /** Same as {@code write(address, data, 0, data.length);} */ + public int write(InetAddress address, byte[] data) + throws IOException, InterruptedIOException + { + return write(address, data, 0, data.length); + } + +} diff --git a/ipscan/ext/rocksaw/src/jni/Makefile b/ipscan/ext/rocksaw/src/jni/Makefile new file mode 100755 index 00000000..ff14538d --- /dev/null +++ b/ipscan/ext/rocksaw/src/jni/Makefile @@ -0,0 +1,74 @@ +# +# $Id: Makefile 6875 2006-04-14 00:29:33Z dfs $ +# +# Copyright 2004-2005 Daniel F. Savarese +# Contact Information: http://www.savarese.org/contact.html +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.savarese.org/software/ApacheLicense-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +UNAME := $(shell uname) +CYGWIN := $(findstring CYGWIN,$(UNAME)) +DARWIN := $(findstring Darwin,$(UNAME)) + +ifeq ($(CYGWIN),CYGWIN) + JDK_HOME := $(shell cygpath $(JDK_HOME)) +endif + +JAVA_INCDIR = $(JDK_HOME)/include +JAVA_INCDIR_PLAF = $(dir $(wildcard $(JAVA_INCDIR)/*/jni_md.h)) + +CC = gcc +CFLAGS = -ansi -Wall -O2 -pipe +CPPFLAGS = -I$(JAVA_INCDIR) -I$(JAVA_INCDIR_PLAF) +WINSOCK = ws2_32 +LDFLAGS = + +ifeq ($(CYGWIN),CYGWIN) + override CC += -mno-cygwin + CPPFLAGS += -D__int64="long long" + LIBNAME = rocksaw + LIBEXTENSION = dll + LDFLAGS += -Wl,--kill-at -l$(WINSOCK) +else + LIBNAME = librocksaw + + ifeq ($(DARWIN),Darwin) + LIBEXTENSION = jnilib + LDFLAGS += -dynamiclib -noprebind -single_module + else + CFLAGS += -fpic + LIBEXTENSION = so + endif +endif + +SRC := $(shell find . -name "*.c" -print) +OBJ := $(SRC:%.c=%.o) + +CLEAN_EXTENSIONS = o $(LIBEXTENSION) + +LIBROCKSAW = $(LIBNAME).$(LIBEXTENSION) + +all: $(LIBROCKSAW) + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(LIBROCKSAW): $(OBJ) + $(CC) -shared -o $@ $^ $(LDFLAGS) + +clean: + for extension in $(CLEAN_EXTENSIONS); do \ + find . -name "*.$$extension" | xargs rm -f ; \ + done + find . -name "*~" | xargs rm -f diff --git a/ipscan/ext/rocksaw/src/jni/Makefile.win32 b/ipscan/ext/rocksaw/src/jni/Makefile.win32 new file mode 100755 index 00000000..d7273453 --- /dev/null +++ b/ipscan/ext/rocksaw/src/jni/Makefile.win32 @@ -0,0 +1,46 @@ +# +# $Id: Makefile.win32 5253 2005-05-06 04:24:20Z dfs $ +# +# Copyright 2004-2005 Daniel F. Savarese +# Contact Information: http://www.savarese.org/contact.html +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.savarese.org/software/ApacheLicense-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +JAVA_INCDIR = $(JDK_HOME)\include +JAVA_INCDIR_PLAF = $(JAVA_INCDIR)\win32 + +CC = cl +CFLAGS = -TC +CPPFLAGS = -I$(JAVA_INCDIR) -I$(JAVA_INCDIR_PLAF) +WINSOCK = ws2_32 +LDFLAGS = $(WINSOCK).lib + +SRC = RawSocket.c +OBJ = $(SRC:.c=.obj) + +LIBNAME = rocksaw +LIBEXTENSION = dll +LIBROCKSAW = $(LIBNAME).$(LIBEXTENSION) +CLEAN_EXTENSIONS = *.obj *.$(LIBEXTENSION) *.lib *.exp + +all: $(LIBROCKSAW) + +.c.obj: + $(CC) -nologo $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(LIBROCKSAW): $(OBJ) + $(CC) -nologo -MD -LD -o $@ $** $(LDFLAGS) + +clean: + del $(CLEAN_EXTENSIONS) diff --git a/ipscan/ext/rocksaw/src/jni/RawSocket.c b/ipscan/ext/rocksaw/src/jni/RawSocket.c new file mode 100755 index 00000000..05a7fa00 --- /dev/null +++ b/ipscan/ext/rocksaw/src/jni/RawSocket.c @@ -0,0 +1,516 @@ +/* + * $Id: RawSocket.c 5982 2005-11-09 18:20:21Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if defined(_WIN32) + +# include +# include + +# if !defined(close) +# define close(fd) closesocket(fd) +# endif + +#else + +# include +# include +# include +# include +# include + +#endif + +#include "RawSocket.h" + +/* + * Utility functions. + */ + +static int setintsockopt(int socket, int level, int option, int value); +static int getintsockopt(int socket, int level, int option); +static int settimeout(int socket, int option, int timeout); +static int gettimeout(int socket, int option); + +static int setintsockopt(int socket, int level, int option, int value) { + return setsockopt(socket, level, option, (void*)&value, sizeof(value)); +} + + +static int getintsockopt(int socket, int level, int option) { + int value = -1; + socklen_t size = sizeof(value); + int result = getsockopt(socket, level, option, (void*)&value, &size); + + if(result < 0) + return result; + + return value; +} + + +static int settimeout(int socket, int option, int timeout) { +#if defined(_WIN32) + return setintsockopt(socket, SOL_SOCKET, option, timeout); +#else + int seconds; + struct timeval value; + + seconds = timeout / 1000; + + if(seconds > 0) + timeout-=(seconds*1000); + + value.tv_sec = seconds; + value.tv_usec = timeout * 1000; + + return setsockopt(socket, SOL_SOCKET, option, (void*)&value, sizeof(value)); +#endif +} + + +static int gettimeout(int socket, int option) { + int result; + struct timeval value; + socklen_t size = sizeof(value); + + result = getsockopt(socket, SOL_SOCKET, option, (void*)&value, &size); + + if(result < 0) + return result; + + return (value.tv_sec * 1000 + value.tv_usec / 1000); +} + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __RockSawInit(); + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1RockSawStartup +(JNIEnv *env, jclass cls) +{ +#if defined(_WIN32) + WORD version = MAKEWORD(2, 0); + WSADATA data; + return (errno = WSAStartup(version, &data)); +#else + return 0; +#endif +} + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __RockSawShutdown(); + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1RockSawShutdown +(JNIEnv *env, jclass cls) +{ +#if defined(_WIN32) + WSACleanup(); +#endif +} + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getErrorMessage + * Signature: (Ljava/lang/StringBuffer;)V + */ +JNIEXPORT void JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getErrorMessage +(JNIEnv *env, jclass cls, jobject buffer) +{ + jclass sbc; + jstring str; + jmethodID mid; + + if(errno) { + char *message = NULL; + +#if defined(_WIN32) + int formatted = + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errno, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &message, 0, NULL ); + if(!formatted) + message = strerror(errno); +#else + message = strerror(errno); +#endif + + str = (*env)->NewStringUTF(env, message); + +#if defined(_WIN32) + if(formatted) + LocalFree(message); +#endif + + sbc = (*env)->GetObjectClass(env, buffer); + mid = + (*env)->GetMethodID(env, sbc, "append", + "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); + (*env)->CallObjectMethod(env, buffer, mid, str); + } +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __select + * Signature: (IZII)I + * + * Returns zero if the socket is ready for I/O. + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1select +(JNIEnv *env, jclass cls, + jint socket, jboolean read, jint seconds, jint microseconds) +{ + int result; + struct timeval timeout; + fd_set *rset = NULL, *wset = NULL, errset, fdset; + + FD_ZERO(&fdset); + FD_ZERO(&errset); + FD_SET(socket, &fdset); + FD_SET(socket, &errset); + + timeout.tv_sec = seconds; + timeout.tv_usec = microseconds; + + if(read) + rset = &fdset; + else + wset = &fdset; + + result = select(socket + 1, rset, wset, &errset, &timeout); + + if(result >= 0) { + if(FD_ISSET(socket, &errset)) + result = -1; + else if(FD_ISSET(socket, &fdset)) + result = 0; + else { +#if defined(_WIN32) + errno = WSAETIMEDOUT; +#else + errno = EAGAIN; +#endif + result = -1; + } + } + + return result; +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __socket + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1socket +(JNIEnv *env, jclass cls, jint family, jint protocol) +{ + return socket(family, SOCK_RAW, protocol); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: getProtocolByName + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket_getProtocolByName +(JNIEnv *env, jclass cls, jstring name) +{ + const char *utf = (*env)->GetStringUTFChars(env, name, NULL); + struct protoent *proto = getprotobyname(utf); + + (*env)->ReleaseStringUTFChars(env, name, utf); + + return proto->p_proto; +} + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __close + * Signature: (I)V + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1close +(JNIEnv *env, jclass cls, jint socket) +{ + return close(socket); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __recvfrom + * Signature: (I[BIII[B)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1recvfrom +(JNIEnv *env, jclass cls, jint socket, + jbyteArray data, jint offset, jint len, jint family, jbyteArray address) +{ + int result; + jbyte *buf; + struct sockaddr *saddr; + struct sockaddr_in sin; + socklen_t socklen; + + /* We support only IPv4 for now. There's a better way to handle + * this, using getaddrinfo if we only allow receives from a preset + * host, obviating the need to check the protocol family and recreate + * the required sockaddr. + */ + if(family == PF_INET) { + socklen = sizeof(sin); + memset(&sin, 0, sizeof(sin)); + sin.sin_family = PF_INET; + buf = (*env)->GetByteArrayElements(env, address, NULL); + memcpy(&sin.sin_addr, buf, sizeof(sin.sin_addr)); + (*env)->ReleaseByteArrayElements(env, address, buf, JNI_ABORT); + saddr = (struct sockaddr *)&sin; + } else { + errno = EINVAL; + return errno; + } + + buf = (*env)->GetByteArrayElements(env, data, NULL); + + result = recvfrom(socket, buf+offset, len, 0, saddr, &socklen); + + (*env)->ReleaseByteArrayElements(env, data, buf, 0); + +#if defined(_WIN32) + if(result < 0) + errno = WSAGetLastError(); +#endif + + return result; +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __sendto + * Signature: (I[BIII[B)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1sendto +(JNIEnv *env, jclass cls, jint socket, + jbyteArray data, jint offset, jint len, jint family, jbyteArray address) +{ + int result; + jbyte *buf; + struct sockaddr *saddr; + struct sockaddr_in sin; + socklen_t socklen; + + /* We only support IPv4 for now. There's a better way to handle + * this, using getaddrinfo if we only allow receives from a preset + * host, obviating the need to check the protocol family and recreate + * the required sockaddr. + */ + if(family == PF_INET) { + socklen = sizeof(sin); + memset(&sin, 0, sizeof(sin)); + sin.sin_family = PF_INET; + buf = (*env)->GetByteArrayElements(env, address, NULL); + memcpy(&sin.sin_addr, buf, sizeof(sin.sin_addr)); + (*env)->ReleaseByteArrayElements(env, address, buf, JNI_ABORT); + saddr = (struct sockaddr *)&sin; + } else { + errno = EINVAL; + return errno; + } + + buf = (*env)->GetByteArrayElements(env, data, NULL); + + result = sendto(socket, buf+offset, len, 0, saddr, socklen); + + (*env)->ReleaseByteArrayElements(env, data, buf, JNI_ABORT); + +#if defined(_WIN32) + if(result < 0) + errno = WSAGetLastError(); +#endif + + return result; +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __isErrorEAGAIN + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1isErrorEAGAIN +(JNIEnv *env, jclass cls) +{ +#if defined(_WIN32) + return (errno == WSAETIMEDOUT); +#else + return (errno == EAGAIN || errno == EWOULDBLOCK); +#endif +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __setIPHeaderInclude + * Signature: (IZ)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setIPHeaderInclude +(JNIEnv *env, jclass cls, jint socket, jboolean on) +{ + return setintsockopt(socket, IPPROTO_IP, IP_HDRINCL, on); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getIPHeaderInclude + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getIPHeaderInclude +(JNIEnv *env, jclass cls, jint socket) +{ + return getintsockopt(socket, IPPROTO_IP, IP_HDRINCL); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __setSendBufferSize + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setSendBufferSize +(JNIEnv *env, jclass cls, jint socket, jint size) +{ + return setintsockopt(socket, SOL_SOCKET, SO_SNDBUF, size); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getSendBufferSize + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getSendBufferSize +(JNIEnv *env, jclass cls, jint socket) +{ + return getintsockopt(socket, SOL_SOCKET, SO_SNDBUF); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __setReceiveBufferSize + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setReceiveBufferSize +(JNIEnv *env, jclass cls, jint socket, jint size) +{ + return setintsockopt(socket, SOL_SOCKET, SO_RCVBUF, size); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getReceiveBufferSize + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getReceiveBufferSize +(JNIEnv *env, jclass cls, jint socket) +{ + return getintsockopt(socket, SOL_SOCKET, SO_RCVBUF); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __setSendTimeout + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setSendTimeout +(JNIEnv *env, jclass cls, jint socket, jint timeout) +{ + return settimeout(socket, SO_SNDTIMEO, timeout); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getSendTimeout + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getSendTimeout +(JNIEnv *env, jclass cls, jint socket) +{ + return gettimeout(socket, SO_SNDTIMEO); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __setReceiveTimeout + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setReceiveTimeout +(JNIEnv *env, jclass cls, jint socket, jint timeout) +{ + return settimeout(socket, SO_RCVTIMEO, timeout); +} + + +/* + * Class: org_savarese_rocksaw_net_RawSocket + * Method: __getReceiveTimeout + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getReceiveTimeout +(JNIEnv *env, jclass cls, jint socket) +{ + return gettimeout(socket, SO_RCVTIMEO); +} diff --git a/ipscan/ext/rocksaw/src/jni/RawSocket.h b/ipscan/ext/rocksaw/src/jni/RawSocket.h new file mode 100755 index 00000000..aab4ec57 --- /dev/null +++ b/ipscan/ext/rocksaw/src/jni/RawSocket.h @@ -0,0 +1,112 @@ +/* + * $Id: RawSocket.h 5979 2005-11-09 18:11:02Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ROCKSAW_RAW_SOCKET_H +#define __ROCKSAW_RAW_SOCKET_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getErrorMessage +(JNIEnv *, jclass, jobject); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1RockSawStartup +(JNIEnv *, jclass); + +JNIEXPORT void JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1RockSawShutdown +(JNIEnv *, jclass); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1select +(JNIEnv *env, jclass cls, jint, jboolean, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1socket +(JNIEnv *, jclass, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket_getProtocolByName +(JNIEnv *, jclass, jstring); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1close +(JNIEnv *, jclass, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1recvfrom +(JNIEnv *, jclass, jint, jbyteArray, jint, jint, jint, jbyteArray); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1sendto +(JNIEnv *, jclass, jint, jbyteArray, jint, jint, jint, jbyteArray); + +JNIEXPORT jboolean JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1isErrorEAGAIN +(JNIEnv *, jclass); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setIPHeaderInclude +(JNIEnv *, jclass, jint, jboolean); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getIPHeaderInclude +(JNIEnv *env, jclass cls, jint socket); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setSendBufferSize +(JNIEnv *, jclass, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getSendBufferSize +(JNIEnv *, jclass, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setReceiveBufferSize +(JNIEnv *, jclass, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getReceiveBufferSize +(JNIEnv *, jclass, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setSendTimeout +(JNIEnv *, jclass, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getSendTimeout +(JNIEnv *, jclass, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1setReceiveTimeout +(JNIEnv *, jclass, jint, jint); + +JNIEXPORT jint JNICALL +Java_org_savarese_rocksaw_net_RawSocket__1_1getReceiveTimeout +(JNIEnv *, jclass, jint); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ipscan/ext/vserv-tcpip/LICENSE b/ipscan/ext/vserv-tcpip/LICENSE new file mode 100755 index 00000000..d6456956 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ipscan/ext/vserv-tcpip/NOTICE b/ipscan/ext/vserv-tcpip/NOTICE new file mode 100755 index 00000000..3ee836b9 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/NOTICE @@ -0,0 +1,2 @@ +This product includes software developed by +Daniel F. Savarese (http://www.savarese.org/). diff --git a/ipscan/ext/vserv-tcpip/README b/ipscan/ext/vserv-tcpip/README new file mode 100755 index 00000000..20f38ac8 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/README @@ -0,0 +1,57 @@ +$Id: README 6024 2005-12-10 23:04:56Z dfs $ + +ABOUT +----- + +Virtual Services TCP/IP, or VServ TCP/IP for short, is a Java library that +enables you to easily manipulate IP and TCP packets. It is intended for +use in conjunction with a library which generates packets, such as +VServ IPQ, as byte arrays. At the moment it supports only IPv4 packet +manipulation. + +The API is still in flux; some methods are missing and some existing +methods will likely be renamed. If you would like something added, +please submit a patch in unified diff format. + + +REQUIREMENTS +------------ + +VServ TCP/IP requires J2SE 1.4 or greater to compile and run. + + +COMPILING +--------- + +The source code requires Apache Ant (http://ant.apache.org/) to compile. + + ant -projecthelp + +will list all build targets in build.xml. There are very few files +in the source tree: + + src/java Java source code + +When you compile the source with + + ant jar + +the following jar file will be created and placed in the lib/ directory: + + vserv-tcpip-version.jar + + +LICENSING +--------- + +VServ TCP/IP is Copyright 2004-2005 by Daniel F. Savarese and licensed +under the Apache License 2.0 as described in the files: + + LICENSE + NOTICE + + +CONTACT +------- + +To contact me see http://www.savarese.org/contact.html diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPEchoPacket.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPEchoPacket.java new file mode 100755 index 00000000..343a9755 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPEchoPacket.java @@ -0,0 +1,102 @@ +/* + * $Id: ICMPEchoPacket.java 5260 2005-05-10 21:01:16Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +/** + * ICMPEchoPacket extends {@link ICMPPacket} to implement ICMP echo request + * and reply packets. + * + * @author Daniel F. Savarese + */ + +public class ICMPEchoPacket extends ICMPPacket { + + /** Offset into the ICMP packet of the identifier header value. */ + public static final int OFFSET_IDENTIFIER = 4; + + /** Offset into the ICMP packet of the sequence number header value. */ + public static final int OFFSET_SEQUENCE = 6; + + + /** + * Creates a new ICMP echo packet of a given size. + * + * @param size The number of bytes in the packet. + */ + public ICMPEchoPacket(int size) { + super(size); + } + + + /** + * Creates a new ICMP echo packet that is a copy of a given packet. + * + * @param packet The packet to replicate. + */ + public ICMPEchoPacket(ICMPEchoPacket packet) { + super(packet); + } + + + public int getICMPHeaderByteLength() { + return 8; + } + + + /** + * Sets the identifier header field. + * + * @param id The new identifier. + */ + public final void setIdentifier(int id) { + _data_[_offset + OFFSET_IDENTIFIER] = (byte)((id >> 8) & 0xff); + _data_[_offset + OFFSET_IDENTIFIER + 1] = (byte)(id & 0xff); + } + + + /** + * @return The identifier header field. + */ + public final int getIdentifier() { + return (((_data_[_offset + OFFSET_IDENTIFIER] & 0xff) << 8) | + (_data_[_offset + OFFSET_IDENTIFIER + 1] & 0xff)); + } + + + /** + * Sets the sequence number. + * + * @param seq The new sequence number. + */ + public final void setSequenceNumber(int seq) { + _data_[_offset + OFFSET_SEQUENCE] = (byte)((seq >> 8) & 0xff); + _data_[_offset + OFFSET_SEQUENCE + 1] = (byte)(seq & 0xff); + } + + + /** + * @return The sequence number. + */ + public final int getSequenceNumber() { + return (((_data_[_offset + OFFSET_SEQUENCE] & 0xff) << 8) | + (_data_[_offset + OFFSET_SEQUENCE + 1] & 0xff)); + } + +} diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPPacket.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPPacket.java new file mode 100755 index 00000000..affd0162 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/ICMPPacket.java @@ -0,0 +1,227 @@ +/* + * $Id: ICMPPacket.java 5347 2005-05-25 22:45:54Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +/** + * ICMPPacket extends {@link IPPacket} to handle ICMP packets. The ICMP + * packet structure is described in + * RFC 792. + * + * @author Daniel F. Savarese + */ + +public abstract class ICMPPacket extends IPPacket { + + /** Offset into the ICMP packet of the type header value. */ + public static final int OFFSET_TYPE = 0; + + /** Offset into the ICMP packet of the code header value. */ + public static final int OFFSET_CODE = 1; + + /** Offset into the ICMP packet of the ICMP checksum. */ + public static final int OFFSET_ICMP_CHECKSUM = 2; + + /** Offset into the ICMP packet of the identifier header value. */ + public static final int OFFSET_IDENTIFIER = 4; + + /** Offset into the ICMP packet of the sequence number header value. */ + public static final int OFFSET_SEQUENCE = 6; + + /** The ICMP type number for an echo request. */ + public static final int TYPE_ECHO_REQUEST = 8; + + /** The ICMP type number for an echo reply. */ + public static final int TYPE_ECHO_REPLY = 0; + + /** The ICMP type number for an "host unreachable" message. */ + public static final int TYPE_HOST_UNREACHABLE = 3; + + /** The byte offset into the IP packet where the ICMP packet begins. */ + int _offset; + + + /** + * Creates a new ICMP packet of a given size. + * + * @param size The number of bytes in the packet. + */ + public ICMPPacket(int size) { + super(size); + _offset = 0; + } + + + /** + * Creates a new ICMP packet that is a copy of a given packet. + * + * @param packet The packet to replicate. + */ + public ICMPPacket(ICMPPacket packet) { + super(packet.size()); + copy(packet); + _offset = packet._offset; + } + + + /** @return The number of bytes in the ICMP packet header. */ + public abstract int getICMPHeaderByteLength(); + + + public void setIPHeaderLength(int length) { + super.setIPHeaderLength(length); + _offset = getIPHeaderByteLength(); + } + + + /** + * @return The total number of bytes in the IP and ICMP headers. + */ + public final int getCombinedHeaderByteLength() { + return _offset + getICMPHeaderByteLength(); + } + + + /** + * Sets the length of the ICMP data payload. + * + * @param length The length of the ICMP data payload in bytes. + */ + public final void setICMPDataByteLength(int length) { + if(length < 0) + length = 0; + + setIPPacketLength(getCombinedHeaderByteLength() + length); + } + + + /** + * @return The number of bytes in the ICMP data payload. + */ + public final int getICMPDataByteLength() { + return getIPPacketLength() - getCombinedHeaderByteLength(); + } + + + /** + * @return The ICMP packet length. This is the size of the IP packet + * minus the size of the IP header. + */ + public final int getICMPPacketByteLength() { + return getIPPacketLength() - _offset; + } + + + /** + * Copies the contents of an ICMPPacket. If the current data array is + * of insufficient length to store the contents, a new array is + * allocated. + * + * @param packet The TCPPacket to copy. + */ + public final void copyData(ICMPPacket packet) { + if(_data_.length < packet._data_.length) { + byte[] data = new byte[packet._data_.length]; + System.arraycopy(_data_, 0, data, 0, getCombinedHeaderByteLength()); + _data_ = data; + } + int length = packet.getICMPDataByteLength(); + System.arraycopy(packet._data_, packet.getCombinedHeaderByteLength(), + _data_, getCombinedHeaderByteLength(), length); + setICMPDataByteLength(length); + } + + + public void setData(byte[] data) { + super.setData(data); + _offset = getIPHeaderByteLength(); + } + + + /** + * Sets the ICMP type header field. + * + * @param type The new type. + */ + public final void setType(int type) { + _data_[_offset + OFFSET_TYPE] = (byte)(type & 0xff); + } + + + /** + * @return The ICMP type header field. + */ + public final int getType() { + return (_data_[_offset + OFFSET_TYPE] & 0xff); + } + + + /** + * Sets the ICMP code header field. + * + * @param code The new type. + */ + public final void setCode(int code) { + _data_[_offset + OFFSET_CODE] = (byte)(code & 0xff); + } + + + /** + * @return The ICMP code header field. + */ + public final int getCode() { + return (_data_[_offset + OFFSET_CODE] & 0xff); + } + + + /** + * @return The ICMP checksum. + */ + public final int getICMPChecksum() { + return (((_data_[_offset + OFFSET_ICMP_CHECKSUM] & 0xff) << 8) | + (_data_[_offset + OFFSET_ICMP_CHECKSUM + 1] & 0xff)); + } + + + /** + * Computes the ICMP checksum, optionally updating the ICMP checksum header. + * + * @param update Specifies whether or not to update the ICMP checksum + * header after computing the checksum. A value of true indicates + * the header should be updated, a value of false indicates it + * should not be updated. + * @return The computed ICMP checksum. + */ + public final int computeICMPChecksum(boolean update) { + return _computeChecksum_(_offset, _offset + OFFSET_ICMP_CHECKSUM, + getIPPacketLength(), 0, update); + } + + + /** + * Same as computeICMPChecksum(true); + * + * @return The computed ICMP checksum value. + */ + public final int computeICMPChecksum() { + return computeICMPChecksum(true); + } + +} + diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/IPPacket.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/IPPacket.java new file mode 100755 index 00000000..99d1cc23 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/IPPacket.java @@ -0,0 +1,527 @@ +/* + * $Id: IPPacket.java 6025 2005-12-10 23:21:25Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +import java.net.*; + +/** + * IPPacket wraps the raw bytes comprising an IPv4 packet and exposes + * its content via setter and getter methods. After you alter the + * header of an IP packet you have to recompute the checksum with + * {@link #computeIPChecksum computeIPChecksum()}. The structure of + * IP packets is described in + * RFC 760. + * + * @author Daniel F. Savarese + */ + +public class IPPacket { + + /** Offset into byte array of the type of service header value. */ + public static final int OFFSET_TYPE_OF_SERVICE = 1; + + /** Offset into byte array of total packet length header value. */ + public static final int OFFSET_TOTAL_LENGTH = 2; + + /** Offset into byte array of the identification header value. */ + public static final int OFFSET_IDENTIFICATION = 4; + + /** Offset into byte array of the flags header value. */ + public static final int OFFSET_FLAGS = 6; + + /** Offset into byte array of source address header value. */ + public static final int OFFSET_SOURCE_ADDRESS = 12; + + /** Number of bytes in source address. */ + public static final int LENGTH_SOURCE_ADDRESS = 4; + + /** Offset into byte array of destination address header value. */ + public static final int OFFSET_DESTINATION_ADDRESS = 16; + + /** Number of bytes in destination address. */ + public static final int LENGTH_DESTINATION_ADDRESS = 4; + + /** Offset into byte array of time to live header value. */ + public static final int OFFSET_TTL = 8; + + /** Offset into byte array of protocol number header value. */ + public static final int OFFSET_PROTOCOL = 9; + + /** Offset into byte array of header checksum header value. */ + public static final int OFFSET_IP_CHECKSUM = 10; + + /** Protocol constant for IPv4. */ + public static final int PROTOCOL_IP = 0; + + /** Protocol constant for ICMP. */ + public static final int PROTOCOL_ICMP = 1; + + /** Protocol constant for TCP. */ + public static final int PROTOCOL_TCP = 6; + + /** Protocol constant for UDP. */ + public static final int PROTOCOL_UDP = 17; + + /** Raw packet data. */ + protected byte[] _data_; + + + /** + * Creates a new IPPacket of a given size. + * + * @param size The number of bytes in the packet. + */ + public IPPacket(int size) { + setData(new byte[size]); + } + + + /** + * @return The size of the packet. + */ + public int size() { + return _data_.length; + } + + + /** + * Sets the raw packet byte array. Although this method would + * appear to violate object-oriented principles, it is necessary to + * implement efficient packet processing. You don't necessarily + * want to allocate a new IPPacket and data buffer every time a + * packet arrives and you need to be able to wrap packets from + * APIs that supply them as byte arrays. + * + * @param data The raw packet byte array to wrap. + */ + public void setData(byte[] data) { + _data_ = data; + } + + + /** + * Copies the raw packet data into a byte array. If the array + * is too small to hold the data, the data is truncated. + * + * @param data The raw packet byte array to wrap. + */ + public void getData(byte[] data) { + System.arraycopy(_data_, 0, data, 0, data.length); + } + + + /** + * Copies the contents of an IPPacket to the calling instance. If + * the two packets are of different lengths, a new byte array is + * allocated equal to the length of the packet parameter. + * + * @param packet The packet to copy from. + */ + public final void copy(IPPacket packet) { + if(_data_.length != packet.size()) + setData(new byte[packet.size()]); + System.arraycopy(packet._data_, 0, _data_, 0, _data_.length); + } + + + /** + * Sets the IP version header value. + * + * @param version A 4-bit unsigned integer. + */ + public final void setIPVersion(int version) { + _data_[0] &= 0x0f; + _data_[0] |= ((version << 4) & 0xf0); + } + + + /** + * Returns the IP version header value. + * + * @return The IP version header value. + */ + public final int getIPVersion() { + return ((_data_[0] & 0xf0) >> 4); + } + + + /** + * Sets the IP header length field. At most, this can be a + * four-bit value. The high order bits beyond the fourth bit + * will be ignored. + * + * @param length The length of the IP header in 32-bit words. + */ + public void setIPHeaderLength(int length) { + // Clear low order bits and then set + _data_[0] &= 0xf0; + _data_[0] |= (length & 0x0f); + } + + + /** + * @return The length of the IP header in 32-bit words. + */ + public final int getIPHeaderLength() { + return (_data_[0] & 0x0f); + } + + + /** + * @return The length of the IP header in bytes. + */ + public final int getIPHeaderByteLength() { + return getIPHeaderLength() << 2; + } + + + /** + * Sets the IP type of service header value. You have to set the individual + * service bits yourself. Convenience methods for setting the service + * bit fields directly may be added in a future version. + * + * @param service An 8-bit unsigned integer. + */ + public final void setTypeOfService(int service) { + _data_[OFFSET_TYPE_OF_SERVICE] = (byte)(service & 0xff); + } + + + /** + * Returns the IP type of service header value. + * + * @return The IP type of service header value. + */ + public final int getTypeOfService() { + return (_data_[OFFSET_TYPE_OF_SERVICE] & 0xff); + } + + + /** + * Sets the IP packet total length header value. + * + * @param length The total IP packet length in bytes. + */ + public final void setIPPacketLength(int length) { + _data_[OFFSET_TOTAL_LENGTH] = (byte)((length >> 8) & 0xff); + _data_[OFFSET_TOTAL_LENGTH + 1] = (byte)(length & 0xff); + } + + + /** + * @return The IP packet total length header value. + */ + public final int getIPPacketLength() { + return (((_data_[OFFSET_TOTAL_LENGTH] & 0xff) << 8) | + (_data_[OFFSET_TOTAL_LENGTH + 1] & 0xff)); + } + + + /** + * Sets the IP identification header value. + * + * @param id A 16-bit unsigned integer. + */ + public void setIdentification(int id) { + _data_[OFFSET_IDENTIFICATION] = (byte)((id >> 8) & 0xff); + _data_[OFFSET_IDENTIFICATION + 1] = (byte)(id & 0xff); + } + + + /** + * Returns the IP identification header value. + * + * @return The IP identification header value. + */ + public final int getIdentification() { + return (((_data_[OFFSET_IDENTIFICATION] & 0xff) << 8) | + (_data_[OFFSET_IDENTIFICATION + 1] & 0xff)); + } + + + /** + * Sets the IP flags header value. You have to set the individual + * flag bits yourself. Convenience methods for setting the flag + * bit fields directly may be added in a future version. + * + * @param flags A 3-bit unsigned integer. + */ + public final void setIPFlags(int flags) { + _data_[OFFSET_FLAGS] &= 0x1f; + _data_[OFFSET_FLAGS] |= ((flags << 5) & 0xe0); + } + + + /** + * Returns the IP flags header value. + * + * @return The IP flags header value. + */ + public final int getIPFlags() { + return ((_data_[OFFSET_FLAGS] & 0xe0) >> 5); + } + + + /** + * Sets the fragment offset header value. The offset specifies a + * number of octets (i.e., bytes). + * + * @param offset A 13-bit unsigned integer. + */ + public void setFragmentOffset(int offset) { + _data_[OFFSET_FLAGS] &= 0xe0; + _data_[OFFSET_FLAGS] |= ((offset >> 8) & 0x1f); + _data_[OFFSET_FLAGS + 1] = (byte)(offset & 0xff); + } + + + /** + * Returns the fragment offset header value. + * + * @return The fragment offset header value. + */ + public final int getFragmentOffset() { + return (((_data_[OFFSET_FLAGS] & 0x1f) << 8) | + (_data_[OFFSET_FLAGS + 1] & 0xff)); + } + + + /** + * Sets the protocol number. + * + * @param protocol The protocol number. + */ + public final void setProtocol(int protocol) { + _data_[OFFSET_PROTOCOL] = (byte)protocol; + } + + + /** + * @return The protocol number. + */ + public final int getProtocol() { + return _data_[OFFSET_PROTOCOL]; + } + + + /** + * Sets the time to live value in seconds. + * + * @param ttl The time to live value in seconds. + */ + public final void setTTL(int ttl) { + _data_[OFFSET_TTL] = (byte)ttl; + } + + + /** + * @return The time to live value in seconds. + */ + public final int getTTL() { + return _data_[OFFSET_TTL]; + } + + + /** + * Calculates checksums assuming the checksum is a 16-bit header field. + * This method is generalized to work for IP, ICMP, UDP, and TCP packets + * given the proper parameters. + */ + protected int _computeChecksum_(int startOffset, + int checksumOffset, + int length, + int virtualHeaderTotal, + boolean update) + { + int total = 0; + int i = startOffset; + int imax = checksumOffset; + + while(i < imax) + total+=(((_data_[i++] & 0xff) << 8) | (_data_[i++] & 0xff)); + + // Skip existing checksum. + i = checksumOffset + 2; + + imax = length - (length % 2); + + while(i < imax) + total+=(((_data_[i++] & 0xff) << 8) | (_data_[i++] & 0xff)); + + if(i < length) + total+=((_data_[i] & 0xff) << 8); + + total+=virtualHeaderTotal; + + // Fold to 16 bits + while((total & 0xffff0000) != 0) + total = (total & 0xffff) + (total >>> 16); + + total = (~total & 0xffff); + + if(update) { + _data_[checksumOffset] = (byte)(total >> 8); + _data_[checksumOffset + 1] = (byte)(total & 0xff); + } + + return total; + } + + + /** + * Computes the IP checksum, optionally updating the IP checksum header. + * + * @param update Specifies whether or not to update the IP checksum + * header after computing the checksum. A value of true indicates + * the header should be updated, a value of false indicates it + * should not be updated. + * @return The computed IP checksum. + */ + public final int computeIPChecksum(boolean update) { + return _computeChecksum_(0, OFFSET_IP_CHECKSUM, getIPHeaderByteLength(), + 0, update); + } + + + /** + * Same as computeIPChecksum(true); + * + * @return The computed IP checksum value. + */ + public final int computeIPChecksum() { + return computeIPChecksum(true); + } + + + /** + * @return The IP checksum header value. + */ + public final int getIPChecksum() { + return (((_data_[OFFSET_IP_CHECKSUM] & 0xff) << 8) | + (_data_[OFFSET_IP_CHECKSUM + 1] & 0xff)); + } + + + /** + * Retrieves the source IP address into a byte array. The array + * should be {@link #LENGTH_SOURCE_ADDRESS} bytes long. + * + * @param address The array in which to store the address. + */ + public final void getSource(byte[] address) { + System.arraycopy(_data_, OFFSET_SOURCE_ADDRESS, address, + 0, (address.length < LENGTH_SOURCE_ADDRESS ? + address.length : LENGTH_SOURCE_ADDRESS)); + } + + + /** + * Retrieves the destionation IP address into a byte array. The array + * should be {@link #LENGTH_DESTINATION_ADDRESS} bytes long. + * + * @param address The array in which to store the address. + */ + public final void getDestination(byte[] address) { + System.arraycopy(_data_, OFFSET_DESTINATION_ADDRESS, address, + 0, (address.length < LENGTH_DESTINATION_ADDRESS ? + address.length : LENGTH_DESTINATION_ADDRESS)); + } + + + /** + * Retrieves the source IP address as a string into a StringBuffer. + * + * @param buffer The StringBuffer in which to store the address. + */ + public final void getSource(StringBuffer buffer) { + OctetConverter.octetsToString(buffer, _data_, OFFSET_SOURCE_ADDRESS); + } + + + /** + * Retrieves the destination IP address as a string into a StringBuffer. + * + * @param buffer The StringBuffer in which to store the address. + */ + public final void getDestination(StringBuffer buffer) { + OctetConverter.octetsToString(buffer, _data_, OFFSET_DESTINATION_ADDRESS); + } + + + /** + * Sets the source IP address using a word representation. + * + * @param src The source IP address as a 32-bit word. + */ + public final void setSourceAsWord(int src) { + OctetConverter.intToOctets(src, _data_, OFFSET_SOURCE_ADDRESS); + } + + + /** + * Sets the destination IP address using a word representation. + * + * @param dest The source IP address as a 32-bit word. + */ + public final void setDestinationAsWord(int dest) { + OctetConverter.intToOctets(dest, _data_, OFFSET_DESTINATION_ADDRESS); + } + + + /** + * @return The source IP address as a 32-bit word. + */ + public final int getSourceAsWord() { + return OctetConverter.octetsToInt(_data_, OFFSET_SOURCE_ADDRESS); + } + + + /** + * @return The destination IP address as a 32-bit word. + */ + public final int getDestinationAsWord() { + return OctetConverter.octetsToInt(_data_, OFFSET_DESTINATION_ADDRESS); + } + + + /** + * @return The source IP address as a java.net.InetAddress instance. + */ + public final InetAddress getSourceAsInetAddress() + throws UnknownHostException + { + byte[] octets = new byte[4]; + getSource(octets); + return InetAddress.getByAddress(octets); + } + + + + /** + * @return The destination IP address as a java.net.InetAddress instance. + */ + public final InetAddress getDestinationAsInetAddress() + throws UnknownHostException + { + byte[] octets = new byte[4]; + getDestination(octets); + return InetAddress.getByAddress(octets); + } +} diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/OctetConverter.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/OctetConverter.java new file mode 100755 index 00000000..bcfb459d --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/OctetConverter.java @@ -0,0 +1,183 @@ +/* + * $Id: OctetConverter.java 5067 2005-03-24 06:10:10Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +/** + * OctetConverter is a utility singleton class for converting IP + * octets to and from other representations. + * + * @author Daniel F. Savarese + */ + +public final class OctetConverter { + + private OctetConverter() { } + + /** + * Converts a set of IPv4 octets to a 32-bit word. + * + * @param octets A byte array containing the IPv4 octets. + * @param offset The offset into the array where the octets start. + * @return The 32-bit word representation of the IPv4 address. + */ + public static final int octetsToInt(byte[] octets, int offset) { + return (((octets[offset] & 0xff) << 24) | + ((octets[offset + 1] & 0xff) << 16) | + ((octets[offset + 2] & 0xff) << 8) | + (octets[offset + 3] & 0xff)); + } + + + /** + * Same as octetsToInt(octets, 0); + */ + public static final int octetsToInt(byte[] octets) { + return octetsToInt(octets, 0); + } + + + /** + * Converts a set of octets to a 64-bit word. + * + * @param octets A byte array containing the octets. + * @param offset The offset into the array where the octets start. + * @return The 64-bit word representation of the octets. + */ + public static final long octetsToLong(byte[] octets, int offset) { + return (((octets[offset] & 0xffffL) << 56) | + ((octets[offset + 1] & 0xffL) << 48) | + ((octets[offset + 2] & 0xffL) << 40) | + ((octets[offset + 3] & 0xffL) << 32) | + ((octets[offset + 4] & 0xffL) << 24) | + ((octets[offset + 5] & 0xffL) << 16) | + ((octets[offset + 6] & 0xffL) << 8) | + (octets[offset + 7] & 0xffL)); + } + + + /** + * Same as octetsToLong(octets, 0); + */ + public static final long octetsToLong(byte[] octets) { + return octetsToLong(octets, 0); + } + + + /** + * Converts a set of IPv4 octets to a string representation. + * + * @param buffer The StringBuffer to which to append the string. + * @param octets A byte array containing the IPv4 octets. + * @param offset The offset into the array where the octets start. + */ + public static final void octetsToString(StringBuffer buffer, byte[] octets, + int offset) + { + buffer.append(octets[offset++] & 0xff); + buffer.append("."); + buffer.append(octets[offset++] & 0xff); + buffer.append("."); + buffer.append(octets[offset++] & 0xff); + buffer.append("."); + buffer.append(octets[offset++] & 0xff); + } + + + /** + * Same as octetsToString(buffer, octets, 0); + */ + public static final void octetsToString(StringBuffer buffer, byte[] octets) { + octetsToString(buffer, octets, 0); + } + + + /** + * Converts a 32-bit word representation of an IPv4 address to a + * string representation. + * + * @param buffer The StringBuffer to which to append the string. + * @param address The 32-bit word representation of the address. + */ + public static final void intToString(StringBuffer buffer, int address) { + buffer.append(0xff & (address >>> 24)); + buffer.append("."); + buffer.append(0xff & (address >>> 16)); + buffer.append("."); + buffer.append(0xff & (address >>> 8)); + buffer.append("."); + buffer.append(0xff & address); + } + + + /** + * Converts a 32-bit word representation of an IPv4 address to a + * byte array of octets. + * + * @param address The 32-bit word representation of the IPv4 address. + * @param octets The byte array in which to store the IPv4 octets. + * @param offset The offset into the array where the octets start. + */ + public static final void intToOctets(int address, byte[] octets, + int offset) + { + octets[offset] = (byte)(0xff & (address >>> 24)); + octets[offset + 1] = (byte)(0xff & (address >>> 16)); + octets[offset + 2] = (byte)(0xff & (address >>> 8)); + octets[offset + 3] = (byte)(0xff & address); + } + + + /** + * Same as intToOctets(address, octets, 0); + */ + public static final void intToOctets(int address, byte[] octets) { + intToOctets(address, octets, 0); + } + + + /** + * Converts a 64-bit word to a byte array of octets. + * + * @param address The 64-bit word. + * @param octets The byte array in which to store octets. + * @param offset The offset into the array where the octets start. + */ + public static final void longToOctets(long address, byte[] octets, + int offset) + { + octets[offset] = (byte)(0xffL & (address >>> 56)); + octets[offset + 1] = (byte)(0xffL & (address >>> 48)); + octets[offset + 2] = (byte)(0xffL & (address >>> 40)); + octets[offset + 3] = (byte)(0xffL & (address >>> 32)); + octets[offset + 4] = (byte)(0xffL & (address >>> 24)); + octets[offset + 5] = (byte)(0xffL & (address >>> 16)); + octets[offset + 6] = (byte)(0xffL & (address >>> 8)); + octets[offset + 7] = (byte)(0xffL & address); + } + + + /** + * Same as longToOctets(address, octets, 0); + */ + public static final void longToOctets(long address, byte[] octets) { + longToOctets(address, octets, 0); + } + +} diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/TCPPacket.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/TCPPacket.java new file mode 100755 index 00000000..1a9ee380 --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/TCPPacket.java @@ -0,0 +1,492 @@ +/* + * $Id: TCPPacket.java 6023 2005-12-10 20:42:15Z dfs $ + * + * Copyright 2004-2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +/** + * TCPPacket extends {@link IPPacket} to handle TCP packets. The TCP + * packet structure is described in + * RFC 761. + * + * @author Daniel F. Savarese + */ + +public class TCPPacket extends IPPacket { + + /** Offset into the TCP packet of the source port header value. */ + public static final int OFFSET_SOURCE_PORT = 0; + + /** Offset into the TCP packet of the destination port header value. */ + public static final int OFFSET_DESTINATION_PORT = 2; + + /** Offset into the TCP packet of the sequence number header value. */ + public static final int OFFSET_SEQUENCE = 4; + + /** Offset into the TCP packet of the acknowledgement number header value. */ + public static final int OFFSET_ACK = 8; + + /** Offset into the TCP packet of the TCP header length. */ + public static final int OFFSET_HEADER_LENGTH = 12; + + /** Offset into the TCP packet of the control header. */ + public static final int OFFSET_CONTROL = 13; + + /** Offset into the TCP packet of the window size. */ + public static final int OFFSET_WINDOW_SIZE = 14; + + /** Offset into the TCP packet of the TCP checksum. */ + public static final int OFFSET_TCP_CHECKSUM = 16; + + /** Offset into the TCP packet of the URG pointer. */ + public static final int OFFSET_URG_POINTER = 18; + + /** A mask for extracting the FIN bit from the control header. */ + public static final int MASK_FIN = 0x01; + + /** A mask for extracting the SYN bit from the control header. */ + public static final int MASK_SYN = 0x02; + + /** A mask for extracting the reset bit from the control header. */ + public static final int MASK_RST = 0x04; + + /** A mask for extracting the push bit from the control header. */ + public static final int MASK_PSH = 0x08; + + /** A mask for extracting the ACK bit from the control header. */ + public static final int MASK_ACK = 0x10; + + /** A mask for extracting the urgent bit from the control header. */ + public static final int MASK_URG = 0x20; + + /** A byte value for TCP options indicating end of option list. */ + public static final byte KIND_EOL = 0; + + /** A byte value for TCP options indicating no operation. */ + public static final byte KIND_NOP = 1; + + /** + * A byte value for TCP options identifying a selective + * acknowledgement option. + */ + public static final byte KIND_SACK = 4; + + /** The byte offset into the IP packet where the TCP packet begins. */ + private int __offset; + + /** + * Creates a new TCP packet of a given size. + * + * @param size The number of bytes in the packet. + */ + public TCPPacket(int size) { + super(size); + __offset = 0; + } + + + /** + * Creates a new TCP packet that is a copy of a given packet. + * + * @param packet The packet to replicate. + */ + public TCPPacket(TCPPacket packet) { + super(packet.size()); + copy(packet); + __offset = packet.__offset; + } + + + /** + * Clears all selective acknowledgement options. This is a + * temporary kluge and will be removed from the final API. Do not + * use it. The final API will have proper methods for adjusting + * selective acknowledgement options. + */ + public void clearSACK() { + int headerLength = getTCPHeaderByteLength(); + int offset = OFFSET_URG_POINTER + 2; + + if(headerLength > offset) { + offset+=__offset; + headerLength+=__offset; + + loop: + do { + byte kind = _data_[offset]; + + switch(kind) { + case KIND_NOP: + ++offset; + break; + case KIND_EOL: + break loop; + case KIND_SACK: + _data_[offset] = KIND_NOP; + _data_[offset + 1] = KIND_NOP; + break loop; + //break; + default: + offset+=_data_[offset + 1]; + /* + int length = _data_[offset + 1]; + while(length-- > 0) + _data_[offset++] = KIND_NOP; + */ + break; + } + + } while(offset < headerLength); + + } + } + + + /** + * Copies the contents of a TCPPacket. If the current data array is + * of insufficient length to store the contents, a new array is + * allocated. + * + * @param packet The TCPPacket to copy. + */ + public final void copyData(TCPPacket packet) { + if(_data_.length < packet._data_.length) { + byte[] data = new byte[packet._data_.length]; + System.arraycopy(_data_, 0, data, 0, getCombinedHeaderByteLength()); + _data_ = data; + } + int length = packet.getTCPDataByteLength(); + System.arraycopy(packet._data_, packet.getCombinedHeaderByteLength(), + _data_, getCombinedHeaderByteLength(), length); + setTCPDataByteLength(length); + } + + /** + * @param mask The bit mask to check. + * @return True only if all of the bits in the mask are set. + */ + public boolean isSet(int mask) { + return ((_data_[__offset + OFFSET_CONTROL] & mask) == mask); + } + + + /** + * @param mask The bit mask to check. + * @return True if any of the bits in the mask are set. + */ + public boolean isSetAny(int mask) { + return ((_data_[__offset + OFFSET_CONTROL] & mask) != 0); + } + + + /** + * @param mask The bit mask to check. + * @return True only if all of the bits in the mask are set + * and ONLY the bits in the mask are set. + */ + public boolean isSetOnly(int mask) { + int flags = _data_[__offset + OFFSET_CONTROL] & 0xff; + return ((flags & mask) == flags); + } + + + /** + * Sets the specified control bits without altering any other bits + * in the control header. + * + * @param mask The bits to set. + */ + public void addControlFlags(int mask) { + int flags = _data_[__offset + OFFSET_CONTROL] & 0xff; + flags |= mask; + _data_[__offset + OFFSET_CONTROL] = (byte)(flags & 0xff); + } + + + /** + * Unsets the specified control bits. + * + * @param mask The bits to unset. + */ + public void removeControlFlags(int mask) { + int flags = _data_[__offset + OFFSET_CONTROL] & 0xff; + flags |= mask; + flags ^= mask; + _data_[__offset + OFFSET_CONTROL] = (byte)(flags & 0xff); + } + + + /** + * Sets the control header to the sepecified value. + * + * @param mask The new control header bit mask. + */ + public void setControlFlags(int mask) { + _data_[__offset + OFFSET_CONTROL] = (byte)(mask & 0xff); + } + + + public void setData(byte[] data) { + super.setData(data); + __offset = getIPHeaderByteLength(); + } + + + /** + * Sets the source port. + * + * @param port The new source port. + */ + public final void setSourcePort(int port) { + _data_[__offset + OFFSET_SOURCE_PORT] = (byte)((port >> 8) & 0xff); + _data_[__offset + OFFSET_SOURCE_PORT + 1] = (byte)(port & 0xff); + } + + + /** + * Sets the destination port. + * + * @param port The new destination port. + */ + public final void setDestinationPort(int port) { + _data_[__offset + OFFSET_DESTINATION_PORT] = (byte)((port >> 8) & 0xff); + _data_[__offset + OFFSET_DESTINATION_PORT + 1] = (byte)(port & 0xff); + } + + + /** + * @return The source port. + */ + public final int getSourcePort() { + return (((_data_[__offset + OFFSET_SOURCE_PORT] & 0xff) << 8) | + (_data_[__offset + OFFSET_SOURCE_PORT + 1] & 0xff)); + } + + + /** + * @return The destination port. + */ + public final int getDestinationPort() { + return (((_data_[__offset + OFFSET_DESTINATION_PORT] & 0xff) << 8) | + (_data_[__offset + OFFSET_DESTINATION_PORT + 1] & 0xff)); + } + + + /** + * Sets the sequence number. + * + * @param seq The new sequence number. + */ + public final void setSequenceNumber(long seq) { + OctetConverter.intToOctets((int)(seq & 0xffffffff), _data_, + __offset + OFFSET_SEQUENCE); + } + + + /** + * @return The sequence number. + */ + public final long getSequenceNumber() { + return (((_data_[__offset + OFFSET_SEQUENCE] & 0xffL) << 24) | + ((_data_[__offset + OFFSET_SEQUENCE + 1] & 0xffL) << 16) | + ((_data_[__offset + OFFSET_SEQUENCE + 2] & 0xffL) << 8) | + (_data_[__offset + OFFSET_SEQUENCE + 3] & 0xffL)); + } + + + /** + * Sets the acknowledgement number. + * + * @param seq The new acknowledgement number. + */ + public final void setAckNumber(long seq) { + OctetConverter.intToOctets((int)(seq & 0xffffffff), _data_, + __offset + OFFSET_ACK); + } + + + /** + * @return The acknowledgement number. + */ + public final long getAckNumber() { + return (((_data_[__offset + OFFSET_ACK] & 0xffL) << 24) | + ((_data_[__offset + OFFSET_ACK + 1] & 0xffL) << 16) | + ((_data_[__offset + OFFSET_ACK + 2] & 0xffL) << 8) | + (_data_[__offset + OFFSET_ACK + 3] & 0xffL)); + } + + + public void setIPHeaderLength(int length) { + super.setIPHeaderLength(length); + __offset = getIPHeaderByteLength(); + } + + + /** + * Sets te TCP header length (i.e., the data offset field) in 32-bit words. + * + * @param length The TCP header length in 32-bit words. + */ + public final void setTCPHeaderLength(int length) { + _data_[__offset + OFFSET_HEADER_LENGTH] &= 0x0f; + _data_[__offset + OFFSET_HEADER_LENGTH] |= ((length << 4) & 0xf0); + } + + + /** + * @return The TCP header length in 32-bit words. + */ + public final int getTCPHeaderLength() { + return (_data_[__offset + OFFSET_HEADER_LENGTH] & 0xf0) >> 4; + } + + + /** + * @return The TCP header length in bytes. + */ + public final int getTCPHeaderByteLength() { + return getTCPHeaderLength() << 2; + } + + + /** + * Sets the TCP window size. + * + * @param window The TCP window size. + */ + public final void setWindowSize(int window) { + _data_[__offset + OFFSET_WINDOW_SIZE] = (byte)((window >> 8) & 0xff); + _data_[__offset + OFFSET_WINDOW_SIZE + 1] = (byte)(window & 0xff); + } + + + /** + * @return The TCP window size. + */ + public final int getWindowSize() { + return (((_data_[__offset + OFFSET_WINDOW_SIZE] & 0xff) << 8) | + (_data_[__offset + OFFSET_WINDOW_SIZE + 1] & 0xff)); + } + + + /** + * Sets the urgent pointer. + * + * @param pointer The urgent pointer value. + */ + public final void setUrgentPointer(int pointer) { + _data_[__offset + OFFSET_URG_POINTER] = (byte)((pointer >> 8) & 0xff); + _data_[__offset + OFFSET_URG_POINTER + 1] = (byte)(pointer & 0xff); + } + + + /** + * @return The urgent pointer value. + */ + public final int getUrgentPointer() { + return (((_data_[__offset + OFFSET_URG_POINTER] & 0xff) << 8) | + (_data_[__offset + OFFSET_URG_POINTER + 1] & 0xff)); + } + + + /** + * @return The TCP checksum. + */ + public final int getTCPChecksum() { + return (((_data_[__offset + OFFSET_TCP_CHECKSUM] & 0xff) << 8) | + (_data_[__offset + OFFSET_TCP_CHECKSUM + 1] & 0xff)); + } + + + /** + * @return The TCP packet length in bytes. This is the size of the + * IP packet minus the size of the IP header. + */ + public final int getTCPPacketByteLength() { + return getIPPacketLength() - __offset; + } + + + /** + * @return The IP header length plus the TCP header length in bytes. + */ + public final int getCombinedHeaderByteLength() { + return __offset + getTCPHeaderByteLength(); + } + + + /** + * Sets the length of the TCP data payload. + * + * @param length The length of the TCP data payload in bytes. + */ + public final void setTCPDataByteLength(int length) { + if(length < 0) + length = 0; + + setIPPacketLength(getCombinedHeaderByteLength() + length); + } + + + public final int getTCPDataByteLength() { + return getIPPacketLength() - getCombinedHeaderByteLength(); + } + + + private final int __getVirtualHeaderTotal() { + int s1 = + ((_data_[OFFSET_SOURCE_ADDRESS] & 0xff) << 8) | + (_data_[OFFSET_SOURCE_ADDRESS + 1] & 0xff); + int s2 = + ((_data_[OFFSET_SOURCE_ADDRESS + 2] & 0xff) << 8) | + (_data_[OFFSET_SOURCE_ADDRESS + 3] & 0xff); + int d1 = + ((_data_[OFFSET_DESTINATION_ADDRESS] & 0xff) << 8) | + (_data_[OFFSET_DESTINATION_ADDRESS + 1] & 0xff); + int d2 = + ((_data_[OFFSET_DESTINATION_ADDRESS + 2] & 0xff) << 8) | + (_data_[OFFSET_DESTINATION_ADDRESS + 3] & 0xff); + return s1 + s2 + d1 + d2 + getProtocol() + getTCPPacketByteLength(); + } + + + /** + * Computes the TCP checksum, optionally updating the TCP checksum header. + * + * @param update Specifies whether or not to update the TCP checksum + * header after computing the checksum. A value of true indicates + * the header should be updated, a value of false indicates it + * should not be updated. + * @return The computed TCP checksum. + */ + public final int computeTCPChecksum(boolean update) { + return _computeChecksum_(__offset, __offset + OFFSET_TCP_CHECKSUM, + getIPPacketLength(), __getVirtualHeaderTotal(), + update); + } + + + /** + * Same as computeTCPChecksum(true); + * + * @return The computed TCP checksum value. + */ + public final int computeTCPChecksum() { + return computeTCPChecksum(true); + } +} diff --git a/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/UDPPacket.java b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/UDPPacket.java new file mode 100755 index 00000000..360e5f3c --- /dev/null +++ b/ipscan/ext/vserv-tcpip/src/java/org/savarese/vserv/tcpip/UDPPacket.java @@ -0,0 +1,252 @@ +/* + * $Id: UDPPacket.java 5347 2005-05-25 22:45:54Z dfs $ + * + * Copyright 2005 Daniel F. Savarese + * Contact Information: http://www.savarese.org/contact.html + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.savarese.org/software/ApacheLicense-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.savarese.vserv.tcpip; + +/** + * UDPPacket extends {@link IPPacket} to handle UDP packets. The UDP + * packet structure is described in + * RFC 768. + * + * @author Daniel F. Savarese + */ + +public class UDPPacket extends IPPacket { + + /** Offset into the UDP packet of the source port header value. */ + public static final int OFFSET_SOURCE_PORT = 0; + + /** Offset into the UDP packet of the destination port header value. */ + public static final int OFFSET_DESTINATION_PORT = 2; + + /** Offset into the UDP packet of UDP total packet length header value. */ + public static final int OFFSET_UDP_TOTAL_LENGTH = 4; + + /** Offset into the UDP packet of the UDP checksum. */ + public static final int OFFSET_UDP_CHECKSUM = 6; + + /** Length of the UDP packet header in bytes. */ + public static final int LENGTH_UDP_HEADER = 8; + + /** The byte offset into the IP packet where the UDP packet begins. */ + private int __offset; + + /** + * Creates a new UDP packet of a given size. + * + * @param size The number of bytes in the packet. + */ + public UDPPacket(int size) { + super(size); + __offset = 0; + } + + + /** + * Creates a new UDP packet that is a copy of a given packet. + * + * @param packet The packet to replicate. + */ + public UDPPacket(UDPPacket packet) { + super(packet.size()); + copy(packet); + __offset = packet.__offset; + } + + + /** + * Copies the contents of a UDPPacket. If the current data array is + * of insufficient length to store the contents, a new array is + * allocated. + * + * @param packet The UDPPacket to copy. + */ + public final void copyData(UDPPacket packet) { + if(_data_.length < packet._data_.length) { + byte[] data = new byte[packet._data_.length]; + System.arraycopy(_data_, 0, data, 0, getCombinedHeaderByteLength()); + _data_ = data; + } + int length = packet.getUDPDataByteLength(); + System.arraycopy(packet._data_, packet.getCombinedHeaderByteLength(), + _data_, getCombinedHeaderByteLength(), length); + setUDPDataByteLength(length); + } + + + public void setData(byte[] data) { + super.setData(data); + __offset = getIPHeaderByteLength(); + } + + + /** + * Sets the source port. + * + * @param port The new source port. + */ + public final void setSourcePort(int port) { + _data_[__offset + OFFSET_SOURCE_PORT] = (byte)((port >> 8) & 0xff); + _data_[__offset + OFFSET_SOURCE_PORT + 1] = (byte)(port & 0xff); + } + + + /** + * Sets the destination port. + * + * @param port The new destination port. + */ + public final void setDestinationPort(int port) { + _data_[__offset + OFFSET_DESTINATION_PORT] = (byte)((port >> 8) & 0xff); + _data_[__offset + OFFSET_DESTINATION_PORT + 1] = (byte)(port & 0xff); + } + + + /** + * @return The source port. + */ + public final int getSourcePort() { + return (((_data_[__offset + OFFSET_SOURCE_PORT] & 0xff) << 8) | + (_data_[__offset + OFFSET_SOURCE_PORT + 1] & 0xff)); + } + + + /** + * @return The destination port. + */ + public final int getDestinationPort() { + return (((_data_[__offset + OFFSET_DESTINATION_PORT] & 0xff) << 8) | + (_data_[__offset + OFFSET_DESTINATION_PORT + 1] & 0xff)); + } + + + public void setIPHeaderLength(int length) { + super.setIPHeaderLength(length); + __offset = getIPHeaderByteLength(); + } + + + /** + * Sets the UDP total length header field. + * + * @param length The length of the UDP packet in bytes. + */ + public void setUDPPacketLength(int length) { + _data_[__offset + OFFSET_UDP_TOTAL_LENGTH] = (byte)((length >> 8) & 0xff); + _data_[__offset + OFFSET_UDP_TOTAL_LENGTH + 1] = (byte)(length & 0xff); + } + + + /** + * @return The value of the UDP total length header field. + */ + public final int getUDPPacketLength() { + return (((_data_[__offset + OFFSET_UDP_TOTAL_LENGTH] & 0xff) << 8) | + (_data_[__offset + OFFSET_UDP_TOTAL_LENGTH + 1] & 0xff)); + } + + + /** + * @return The UDP checksum. + */ + public final int getUDPChecksum() { + return (((_data_[__offset + OFFSET_UDP_CHECKSUM] & 0xff) << 8) | + (_data_[__offset + OFFSET_UDP_CHECKSUM + 1] & 0xff)); + } + + + /** + * @return The UDP packet length in bytes. This is the size of the + * IP packet minus the size of the IP header. Normally, you want + * this to equal the length stored in the UDP header + * (see {@link #getUDPPacketLength}). + */ + public final int getUDPPacketByteLength() { + return getIPPacketLength() - __offset; + } + + + /** + * @return The IP header length plus the UDP header length in bytes. + */ + public final int getCombinedHeaderByteLength() { + return __offset + LENGTH_UDP_HEADER; + } + + + /** + * Sets the length of the UDP data payload. + * + * @param length The length of the UDP data payload in bytes. + */ + public final void setUDPDataByteLength(int length) { + if(length < 0) + length = 0; + + setIPPacketLength(getCombinedHeaderByteLength() + length); + } + + + public final int getUDPDataByteLength() { + return getIPPacketLength() - getCombinedHeaderByteLength(); + } + + + private final int __getVirtualHeaderTotal() { + int s1 = + ((_data_[OFFSET_SOURCE_ADDRESS] & 0xff) << 8) | + (_data_[OFFSET_SOURCE_ADDRESS + 1] & 0xff); + int s2 = + ((_data_[OFFSET_SOURCE_ADDRESS + 2] & 0xff) << 8) | + (_data_[OFFSET_SOURCE_ADDRESS + 3] & 0xff); + int d1 = + ((_data_[OFFSET_DESTINATION_ADDRESS] & 0xff) << 8) | + (_data_[OFFSET_DESTINATION_ADDRESS + 1] & 0xff); + int d2 = + ((_data_[OFFSET_DESTINATION_ADDRESS + 2] & 0xff) << 8) | + (_data_[OFFSET_DESTINATION_ADDRESS + 3] & 0xff); + return s1 + s2 + d1 + d2 + getProtocol() + getUDPPacketByteLength(); + } + + + /** + * Computes the UDP checksum, optionally updating the UDP checksum header. + * + * @param update Specifies whether or not to update the UDP checksum + * header after computing the checksum. A value of true indicates + * the header should be updated, a value of false indicates it + * should not be updated. + * @return The computed UDP checksum. + */ + public final int computeUDPChecksum(boolean update) { + return _computeChecksum_(__offset, __offset + OFFSET_UDP_CHECKSUM, + getIPPacketLength(), __getVirtualHeaderTotal(), + update); + } + + + /** + * Same as computeUDPChecksum(true); + * + * @return The computed UDP checksum value. + */ + public final int computeUDPChecksum() { + return computeUDPChecksum(true); + } +} diff --git a/ipscan/resources/Labels.txt b/ipscan/resources/Labels.txt new file mode 100755 index 00000000..52cbf4c8 --- /dev/null +++ b/ipscan/resources/Labels.txt @@ -0,0 +1,189 @@ +icon=images/icon.gif +encoding=ISO-8859-1 +menu.file=&File +menu.file.saveAll=Export &results... Ctrl+S +menu.file.saveSelection=Export &selected results... +menu.file.exportOptions=Export &options... +menu.file.importOptions=&Import options... +menu.file.exit=E&xit Alt+F4 +menu.goto=&Go to +menu.goto.aliveHost=Next alive &host Ctrl+Shift+H +menu.goto.deadHost=Next d&ead host Ctrl+Shift+D +menu.goto.openPort=Next open &port Ctrl+Shift+P +menu.goto.find=Find... Ctrl+F +menu.commands=&Commands +menu.commands.details=&Show details Dbl-Clk +menu.commands.rescan=&Rescan IP(s) Ctrl+R +menu.commands.delete=&Delete IP(s) Del +menu.commands.copy=&Copy IP Ctrl+C +menu.commands.copyDetails=Co&py details +menu.commands.show=Show +menu.commands.open=Open +menu.commands.open.edit=Edit openers... +menu.favorites=Fa&vorites +menu.favorites.add=Add current... Ctrl+D +menu.favorites.edit=Manage favorites... +menu.tools=&Tools +menu.tools.options=&Options... Ctrl+O +menu.tools.fetchers=Select &fetchers... +menu.tools.delete=Delete from list +menu.tools.lastInfo=Show last scan &info Ctrl+I +menu.help=&Help +menu.help.gettingStarted=Getting &Started F1 +menu.help.website=Official Website +menu.help.forum=Forum +menu.help.plugins=Download plugins +menu.help.cmdLine=Command-line usage +menu.help.checkVersion=Check for newer version... +menu.help.about=&About... F12 +menu.columns.sortBy=Sort by +menu.columns.sortDirection=Change sort direction +menu.columns.info=Fetcher info +menu.columns.options=Fetcher options +state.ready=Ready +state.scanning=Scanning +state.waitForThreads=Wait for all threads to terminate... +state.killingThreads=Killing all threads... +state.saving=Exporting results... +state.searching=Searching... +state.opening=Opening +state.retrievingVersion=Retrieving the latest version... +title.about=About +title.options=Options +title.options.scanning=Scanning +title.options.display=Display +title.options.fetchers=Fetchers +title.options.ports=Ports +title.details=IP address details +title.saveAll=Export All Results +title.saveSelection=Export Selected Results +title.gettingStarted=Getting Started +title.favorite.add=Add a favorite +title.favorite.edit=Edit favorites +title.openers.edit=Edit Openers +title.fetchers.select=Select Fetchers +title.find=Find +text.ip=IP +text.threads=Threads: +text.favorite.add=Enter the name of the new favorite +text.favorite.edit=Below you can rearrange or delete favorites +text.find=Enter the text to search for +text.find.notFound=Nothing was found. +text.find.restart=Would you like to start from the beginning? +text.version.latest=You are running the latest version. +text.version.old=The latest version is %LATEST, but you are running %VERSION. +text.openers.edit=Below you can edit or add new openers +text.openers.name=Opener name (menu item): +text.openers.string=Execution string: +text.openers.directory=Working directory: +text.openers.inTerminal=Run the program in terminal +text.openers.new=New opener +text.openers.hint=&Substitutions... +text.openers.hintText=You may use any scanned values returned by fetchers in the execution string.\n\nThe following fetchers are currently available for substitution:\n\n +text.fetchers.select=Here you can select fetchers for scanning. Fetchers are represented by columns. +text.fetchers.selectedList=Selected fetchers +text.fetchers.availableList=Available fetchers +text.about=%NAME\n\nVersion %VERSION\n%COPYLEFT\n\n%WEBSITE\n%MAILTO\n\nThis is an Open Source Software released under the GPL. +text.gettingStarted=Dummy +text.gettingStarted1=Angry IP Scanner is an IP address scanner tool.\n\nIt is used for scanning IP addresses for finding alive hosts, gathering any kind of needed information about each host. +text.gettingStarted2=Main terminology:\n\nFeeder - generator of IP addresses for scanning. Angry IP Scanner provides various kinds of feeders: IP Range, Random, and IP List File. You can select a feeder using the combo box next to the "Start" button.\n\nFetcher - gathers specific information about a host, e.g. ping time, hostname, open ports. Feeders usually represent columns in the scanning results list. +button.OK=OK +button.cancel=Cancel +button.close=Close +button.next=Next -> +button.start.img=images/buttons/start.gif +button.stop.img=images/buttons/stop.gif +button.kill.img=images/buttons/kill.gif +button.ipUp.img=images/buttons/ipup.gif +button.up=&Up +button.down=&Down +button.delete=De&lete +button.save=&Save +button.insert=&Insert +button.add=&Add +button.left=< +button.right=> +combobox.feeder.tooltip=IP Feeder selection. Change this if you need another source for IP addresses to scan +list.unknown.img=images/list/unknown.gif +list.dead.img=images/list/dead.gif +list.alive.img=images/list/alive.gif +list.addinfo.img=images/list/addinfo.gif +pinger.icmp=ICMP Echo +pinger.icmp2=ICMP Echo (Alternative) +pinger.udp=UDP packet +pinger.tcp=TCP port probe +opener.web=Web Browser +opener.ftp=FTP +opener.telnet=Telnet +opener.ssh=SSH +opener.netbios=Windows Shares +opener.email=E-mail sample +feeder.range=IP Range +feeder.range.startIP=IP Range: +feeder.range.endIP=to +feeder.range.netmask=Netmask +feeder.range.netmask.tooltip=Netmask of the IP range. Use either number of bits (e.g. /24) or the dotted notation (.255. = ..) +feeder.range.hostname=Hostname: +feeder.range.hostname.tooltip=Use this field to resolve hostnames to IP addresses +feeder.file=IP List File +feeder.file.name=Filename +feeder.file.browse=Browse... +feeder.random=Random +feeder.random.prototype=Base IP: +feeder.random.mask=IP Mask: +feeder.random.hostname=Hostname: +feeder.random.count=Count: +fetcher.ip=IP +fetcher.ping=Ping +fetcher.ping.ttl=TTL +fetcher.hostname=Hostname +fetcher.ports=Ports +fetcher.ports.filtered=Filtered Ports +fetcher.value.ms= ms +fetcher.value.notAvailable=[n/a] +fetcher.value.notScanned=[n/s] +options.threads=Threads +options.threads.delay=Delay between starting threads (in ms): +options.threads.maxThreads=Maximum number of threads: +options.pinging.deadHosts=Scan dead hosts, which don't reply to pings +options.pinging=Pinging +options.pinging.type=Pinging method: +options.pinging.count=Number of ping probes (packets to send): +options.pinging.timeout=Ping timeout (in ms): +options.broadcast=Broadcast +options.broadcast.skip=Skip likely broadcast IP addresses +options.fetchers.info=Here you can change options, specific to fetchers +options.ports.timing=Timing +options.ports.timing.timeout=Default port connect timeout (in ms): +options.ports.timing.adaptTimeout=Adapt timeout to ping roundtrip time (if available) +options.ports.ports=Port selection +options.ports.portsDescription=Specify ports to scan here. Ranges are supported.\nExample: 1-3,5,7,10-15,6000-6100\nIf many ports are specified, scanning can take a lot of time. +exporter.txt=Text file (txt) +exporter.txt.generated=Generated by +exporter.txt.scanned=Scanned %INFO +exporter.csv=Comma-separated file (csv) +exporter.xml=XML file +exporter.ipList=IP:List file (lst) +exception.FeederException.invalidNetmask=Invalid netmask specified. Must be in the A.B.C.D format +exception.FeederException.invalidHostname=Invalid or inexistent hostname specified +exception.FeederException.malformedIP=Malformed IP address specified, it should look like A.B.C.D +exception.FeederException.range.greaterThan=The starting IP should be lower than the ending IP +exception.FeederException.random.invalidCount=Random address count must be greater than 0 +exception.FeederException.file.notExists=Specified file doesn't exist or you don't have permissions to read it +exception.FeederException.file.errorWhileReading=Error while reading the file +exception.FeederException.file.nothingFound=No IP addresses found in the file +exception.ExporterException.failed=Exporting failed +exception.ExporterException.exporter.unknown=Unknown file type, please specify correct extension in the file name. +exception.ExporterException.xml.noAppend=Appending to XML files is not supported. +exception.ExporterException.fetcher.notFound=Not enough data in the scanning results to export to this file type. +exception.UserErrorException.openURL.failed=Unable to launch your default browser, sorry.\nURL: +exception.UserErrorException.openTerminal.failed=Unable to launch the terminal, sorry\n +exception.UserErrorException.opener.failed=Unable to launch an external process, sorry.\nCommand-line: +exception.UserErrorException.opener.unknownFetcher=The referenced fetcher cannot be resolved in the current scanning result. Cannot execute the opener with parameter: +exception.UserErrorException.opener.nullFetcherValue=The replacement value of the fetcher is empty in the scanning results. Cannot execute the opener with parameter: +exception.UserErrorException.opener.edit.noSelection=Please select the position where do you want to save your opener and or the Insert button to add a new one. +exception.UserErrorException.commands.noSelection=No IP address selected +exception.UserErrorException.commands.noResults=No scanning results available yet, please perform a scan first +exception.UserErrorException.favorite.alreadyExists=A favorite with the same name already exists, please try a different one +exception.UserErrorException.version.latestFailed=Failed to retrieve the latest version. Please visit the website manually. +exception.OutOfMemoryError=Out Of Memory. The amount of available to the program heap memory has been exceeded.\nPlease increase the maximum heap size for this program. diff --git a/ipscan/resources/images/buttons/ipup.gif b/ipscan/resources/images/buttons/ipup.gif new file mode 100755 index 00000000..f50fe3c9 Binary files /dev/null and b/ipscan/resources/images/buttons/ipup.gif differ diff --git a/ipscan/resources/images/buttons/kill.gif b/ipscan/resources/images/buttons/kill.gif new file mode 100755 index 00000000..f015e163 Binary files /dev/null and b/ipscan/resources/images/buttons/kill.gif differ diff --git a/ipscan/resources/images/buttons/start.gif b/ipscan/resources/images/buttons/start.gif new file mode 100755 index 00000000..4c542428 Binary files /dev/null and b/ipscan/resources/images/buttons/start.gif differ diff --git a/ipscan/resources/images/buttons/stop.gif b/ipscan/resources/images/buttons/stop.gif new file mode 100755 index 00000000..0dd6a1f2 Binary files /dev/null and b/ipscan/resources/images/buttons/stop.gif differ diff --git a/ipscan/resources/images/icon.gif b/ipscan/resources/images/icon.gif new file mode 100755 index 00000000..a2f0ab65 Binary files /dev/null and b/ipscan/resources/images/icon.gif differ diff --git a/ipscan/resources/images/list/addinfo.gif b/ipscan/resources/images/list/addinfo.gif new file mode 100755 index 00000000..c4e77cc9 Binary files /dev/null and b/ipscan/resources/images/list/addinfo.gif differ diff --git a/ipscan/resources/images/list/alive.gif b/ipscan/resources/images/list/alive.gif new file mode 100755 index 00000000..aa82c7c7 Binary files /dev/null and b/ipscan/resources/images/list/alive.gif differ diff --git a/ipscan/resources/images/list/dead.gif b/ipscan/resources/images/list/dead.gif new file mode 100755 index 00000000..10c774b3 Binary files /dev/null and b/ipscan/resources/images/list/dead.gif differ diff --git a/ipscan/resources/images/list/unknown.gif b/ipscan/resources/images/list/unknown.gif new file mode 100755 index 00000000..e09f1c5f Binary files /dev/null and b/ipscan/resources/images/list/unknown.gif differ diff --git a/ipscan/src/net/azib/ipscan/Main.java b/ipscan/src/net/azib/ipscan/Main.java new file mode 100755 index 00000000..55605020 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/Main.java @@ -0,0 +1,120 @@ +/** + * + */ +package net.azib.ipscan; + +import java.security.Security; +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.GUIComponentContainer; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.gui.MainWindow; +import net.azib.ipscan.gui.UserErrorException; + +/** + * The main executable class. + * It initializes all the needed stuff and launches the user interface. + * + * All Exceptions, which are thrown out of the program, are catched and logged + * using the java.util.logging facilities. + * + * @author anton + */ +public class Main { + + public static void main(String[] args) { + + Logger.global.setLevel(Level.CONFIG); + + initProperties(); + + Display display = Display.getDefault(); + + // initalize Labels instance + Labels.initialize(new Locale("en")); // TODO: retrieve locale normally + + // initialize Config instance + Config.initialize(); + + // create the main window using dependency injection + MainWindow mainWindow = new GUIComponentContainer().createMainWindow(); + + while (!mainWindow.isDisposed()) { + try { + if (!display.readAndDispatch()) + display.sleep(); + } + catch (Throwable e) { + // display a nice error message + String localizedMessage = getLocalizedMessage(e); + Shell parent = display.getActiveShell(); + MessageBox messageBox = new MessageBox(parent != null ? parent : mainWindow.getShell(), SWT.OK | SWT.ICON_ERROR); + messageBox.setText("Error"); + messageBox.setMessage(localizedMessage); + messageBox.open(); + } + } + + // save config on exit + Config.store(); + + // dispose the native objects + display.dispose(); + } + + private static void initProperties() { + // currently we support IPv4 only + System.setProperty("java.net.preferIPv4Stack", "true"); + // disable DNS caches + Security.setProperty("networkaddress.cache.ttl", "0"); + Security.setProperty("networkaddress.cache.negative.ttl", "0"); + } + + /** + * Returns a nice localized message for the passed exception + * in case it is possible, or toString() otherwise. + */ + static String getLocalizedMessage(Throwable e) { + String localizedMessage; + try { + // try to load localized message + if (e instanceof UserErrorException) { + localizedMessage = e.getMessage(); + } + else { + String exceptionClassName = getClassShortName(e.getClass()); + String originalMessage = e.getMessage(); + localizedMessage = Labels.getLabel("exception." + exceptionClassName + (originalMessage != null ? "." + originalMessage : "")); + } + // add cause summary, if it exists + if (e.getCause() != null) { + localizedMessage += "\n\n" + e.getCause().toString(); + } + Logger.global.log(Level.FINE, "error", e); + } + catch (Exception e2) { + // fallback to default text + localizedMessage = e.toString(); + // output stack trace to the console + Logger.global.log(Level.SEVERE, "unexpected error", e); + } + return localizedMessage; + } + + /** + * @return the short name of a class (without package name) + */ + static String getClassShortName(Class clazz) { + String className = clazz.getName(); + return className.substring(className.lastIndexOf('.') + 1); + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/Config.java b/ipscan/src/net/azib/ipscan/config/Config.java new file mode 100755 index 00000000..f88732af --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/Config.java @@ -0,0 +1,80 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.util.prefs.Preferences; + +/** + * This class encapsulates configuration options of the program. + * It is a singleton class. + * + * @author anton + */ +public final class Config { + + private static Preferences preferences; + + /** easily accessible global configuration */ + private static GlobalConfig globalConfig; + /** favorites are stored here */ + private static NamedListConfig favoritesConfig; + /** openers are stored here */ + private static OpenersConfig openersConfig; + /** various dimensions are stored here */ + private static DimensionsConfig dimensionsConfig; + + private Config() { + } + + /** + * Initializes the singleton instance + */ + public static void initialize() { + preferences = Preferences.userRoot().node("ipscan"); + globalConfig = new GlobalConfig(); + favoritesConfig = new FavoritesConfig(); + openersConfig = new OpenersConfig(); + dimensionsConfig = new DimensionsConfig(); + } + + public static void store() { + globalConfig.store(); + favoritesConfig.store(); + openersConfig.store(); + dimensionsConfig.store(); + } + + public static Preferences getPreferences() { + return preferences; + } + + /** + * @return GlobalConfig instance (quick access) + */ + public static GlobalConfig getGlobal() { + return globalConfig; + } + + /** + * @return Favorites config (quick access); + */ + public static NamedListConfig getFavoritesConfig() { + return favoritesConfig; + } + + /** + * @return Openers config (quick access); + */ + public static OpenersConfig getOpenersConfig() { + return openersConfig; + } + + /** + * @return Dimensions config (quick access); + */ + public static DimensionsConfig getDimensionsConfig() { + return dimensionsConfig; + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/DimensionsConfig.java b/ipscan/src/net/azib/ipscan/config/DimensionsConfig.java new file mode 100755 index 00000000..49e52056 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/DimensionsConfig.java @@ -0,0 +1,96 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.util.prefs.Preferences; + +import org.eclipse.swt.graphics.Rectangle; + +/** + * DimensionsConfig + * + * @author anton + */ +public class DimensionsConfig { + + private Preferences preferences; + + public int windowHeight; + public int windowWidth; + public int windowTop; + public int windowLeft; + public boolean isWindowMaximized; + + // package local constructor + DimensionsConfig() { + preferences = Config.getPreferences(); + load(); + } + + /** + * This constructor is for tests + * @param preferences + */ + DimensionsConfig(Preferences preferences) { + this.preferences = preferences; + load(); + } + + private void load() { + windowHeight = preferences.getInt("windowHeight", 350); + windowWidth = preferences.getInt("windowWidth", 560); + windowTop = preferences.getInt("windowTop", 100); + windowLeft = preferences.getInt("windowLeft", 100); + isWindowMaximized = preferences.getBoolean("windowMaximized", false); + } + + public void store() { + if (!isWindowMaximized) { + preferences.putInt("windowHeight", windowHeight); + preferences.putInt("windowWidth", windowWidth); + preferences.putInt("windowTop", windowTop); + preferences.putInt("windowLeft", windowLeft); + } + preferences.putBoolean("windowMaximized", isWindowMaximized); + } + + /** + * @return + */ + public Rectangle getWindowBounds() { + return new Rectangle(windowLeft, windowTop, windowWidth, windowHeight); + } + + /** + * @param bounds + * @param isMaximized + */ + public void setWindowBounds(Rectangle bounds, boolean isMaximized) { + if (!isMaximized) { + windowTop = bounds.y; + windowLeft = bounds.x; + windowHeight = bounds.height; + windowWidth = bounds.width; + } + isWindowMaximized = isMaximized; + } + + /** + * @param fetcherName + * @return column width corresponding to a fetcher + */ + public int getColumnWidth(String fetcherName) { + return preferences.getInt("columnWidth." + fetcherName, 90); + } + + /** + * Persist the width of a column corresponding to a fetcher + * @param fetcherName + * @param width + */ + public void setColumnWidth(String fetcherName, int width) { + preferences.putInt("columnWidth." + fetcherName, width); + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/FavoritesConfig.java b/ipscan/src/net/azib/ipscan/config/FavoritesConfig.java new file mode 100755 index 00000000..90080a90 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/FavoritesConfig.java @@ -0,0 +1,17 @@ +/** + * + */ +package net.azib.ipscan.config; + +/** + * FavoritesConfig + * + * @author anton + */ +public class FavoritesConfig extends NamedListConfig { + + public FavoritesConfig() { + super("favorites"); + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/GUIComponentContainer.java b/ipscan/src/net/azib/ipscan/config/GUIComponentContainer.java new file mode 100755 index 00000000..f9849f69 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/GUIComponentContainer.java @@ -0,0 +1,161 @@ +/** + * + */ +package net.azib.ipscan.config; + +import net.azib.ipscan.core.Scanner; +import net.azib.ipscan.core.ScannerThreadFactory; +import net.azib.ipscan.core.ScanningResultList; +import net.azib.ipscan.core.net.PingerRegistry; +import net.azib.ipscan.core.net.PingerRegistryImpl; +import net.azib.ipscan.exporters.CSVExporter; +import net.azib.ipscan.exporters.ExporterRegistry; +import net.azib.ipscan.exporters.IPListExporter; +import net.azib.ipscan.exporters.TXTExporter; +import net.azib.ipscan.exporters.XMLExporter; +import net.azib.ipscan.fetchers.FetcherRegistry; +import net.azib.ipscan.fetchers.FetcherRegistryImpl; +import net.azib.ipscan.fetchers.FilteredPortsFetcher; +import net.azib.ipscan.fetchers.HostnameFetcher; +import net.azib.ipscan.fetchers.IPFetcher; +import net.azib.ipscan.fetchers.PingFetcher; +import net.azib.ipscan.fetchers.PingTTLFetcher; +import net.azib.ipscan.fetchers.PortsFetcher; +import net.azib.ipscan.gui.MainMenu; +import net.azib.ipscan.gui.MainWindow; +import net.azib.ipscan.gui.OptionsWindow; +import net.azib.ipscan.gui.ResultTable; +import net.azib.ipscan.gui.SelectFetchersDialog; +import net.azib.ipscan.gui.StatusBar; +import net.azib.ipscan.gui.MainMenu.CommandsMenu; +import net.azib.ipscan.gui.actions.ColumnsActions; +import net.azib.ipscan.gui.actions.OpenerLauncher; +import net.azib.ipscan.gui.actions.StartStopScanningAction; +import net.azib.ipscan.gui.feeders.FeederGUIRegistry; +import net.azib.ipscan.gui.feeders.FileFeederGUI; +import net.azib.ipscan.gui.feeders.RandomFeederGUI; +import net.azib.ipscan.gui.feeders.RangeFeederGUI; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Shell; +import org.picocontainer.MutablePicoContainer; +import org.picocontainer.Parameter; +import org.picocontainer.PicoContainer; +import org.picocontainer.defaults.ComponentParameter; +import org.picocontainer.defaults.ConstantParameter; +import org.picocontainer.defaults.DefaultPicoContainer; + +/** + * This class is a dependency injection configuration + * using the Pico Container. + * + * @author anton + */ +public class GUIComponentContainer { + + private PicoContainer container; + + public GUIComponentContainer() { + MutablePicoContainer container = new DefaultPicoContainer(); + this.container = container; + + ComponentParameter anyComponentParameter = new ComponentParameter(); + + // non-GUI TODO: move to a separate container + container.registerComponentImplementation(ExporterRegistry.class); + container.registerComponentImplementation(TXTExporter.class); + container.registerComponentImplementation(CSVExporter.class); + container.registerComponentImplementation(XMLExporter.class); + container.registerComponentImplementation(IPListExporter.class); + + container.registerComponentImplementation(FetcherRegistry.class, FetcherRegistryImpl.class); + container.registerComponentImplementation(IPFetcher.class); + container.registerComponentImplementation(PingFetcher.class); + container.registerComponentImplementation(PingTTLFetcher.class); + container.registerComponentImplementation(HostnameFetcher.class); + container.registerComponentImplementation(PortsFetcher.class); + container.registerComponentImplementation(FilteredPortsFetcher.class); + + container.registerComponentImplementation(PingerRegistry.class, PingerRegistryImpl.class); + container.registerComponentImplementation(ScanningResultList.class); + container.registerComponentImplementation(Scanner.class); + container.registerComponentImplementation(ScannerThreadFactory.class); + + // GUI follows + + // Some "shared" GUI components + container.registerComponentImplementation("mainShell", Shell.class); + container.registerComponentImplementation("mainMenu", Menu.class, new Parameter[] { + new ComponentParameter("mainShell"), + new ConstantParameter(new Integer(SWT.BAR))}); + container.registerComponentImplementation("commandsMenu", CommandsMenu.class); + + container.registerComponentImplementation("feederArea", Composite.class, new Parameter[] { + new ComponentParameter("mainShell"), + new ConstantParameter(new Integer(SWT.NONE))}); + container.registerComponentImplementation("controlsArea", Composite.class, new Parameter[] { + new ComponentParameter("mainShell"), + new ConstantParameter(new Integer(SWT.NONE))}); + container.registerComponentImplementation("startStopButton", Button.class, new Parameter[] { + new ComponentParameter("controlsArea"), + new ConstantParameter(new Integer(SWT.NONE))}); + container.registerComponentImplementation("feederSelectionCombo", Combo.class, new Parameter[] { + new ComponentParameter("controlsArea"), + new ConstantParameter(new Integer(SWT.READ_ONLY))}); + + // GUI Feeders + container.registerComponentImplementation(FeederGUIRegistry.class); + Parameter[] feederGUIParameters = new Parameter[] {new ComponentParameter("feederArea")}; + container.registerComponentImplementation(RangeFeederGUI.class, RangeFeederGUI.class, feederGUIParameters); + container.registerComponentImplementation(RandomFeederGUI.class, RandomFeederGUI.class, feederGUIParameters); + container.registerComponentImplementation(FileFeederGUI.class, FileFeederGUI.class, feederGUIParameters); + + container.registerComponentImplementation(OpenerLauncher.class); + container.registerComponentImplementation(MainWindow.class, MainWindow.class, new Parameter[] { + new ComponentParameter("mainShell"), + new ComponentParameter("feederArea"), + new ComponentParameter("controlsArea"), + new ComponentParameter("feederSelectionCombo"), + new ComponentParameter("startStopButton"), + anyComponentParameter, + anyComponentParameter, + anyComponentParameter, + anyComponentParameter, + anyComponentParameter}); + container.registerComponentImplementation(ResultTable.class, ResultTable.class, new Parameter[] { + new ComponentParameter("mainShell"), + anyComponentParameter, + anyComponentParameter, + anyComponentParameter}); + container.registerComponentImplementation(StatusBar.class, StatusBar.class, new Parameter[] { + new ComponentParameter("mainShell")}); + + container.registerComponentImplementation(MainMenu.class, MainMenu.class, new Parameter[] { + new ComponentParameter("mainShell"), + new ComponentParameter("mainMenu"), + new ComponentParameter("commandsMenu"), + new ConstantParameter(container)}); + container.registerComponentImplementation(MainMenu.ColumnsMenu.class, MainMenu.ColumnsMenu.class, new Parameter[] { + new ComponentParameter("mainShell"), + anyComponentParameter}); + + container.registerComponentImplementation(OptionsWindow.class); + container.registerComponentImplementation(SelectFetchersDialog.class); + + // various actions / listener + container.registerComponentImplementation(StartStopScanningAction.class); + container.registerComponentImplementation(ColumnsActions.SortBy.class); + } + + public MainWindow createMainWindow() { + // initialize the main menu + container.getComponentInstance(MainMenu.class); + // initialize and return the main window + return (MainWindow) container.getComponentInstance(MainWindow.class); + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/GlobalConfig.java b/ipscan/src/net/azib/ipscan/config/GlobalConfig.java new file mode 100755 index 00000000..28606d33 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/GlobalConfig.java @@ -0,0 +1,61 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.util.prefs.Preferences; + +/** + * Global configuration holder. + * + * @author anton + */ +public final class GlobalConfig { + + private static final String MAX_THREADS = "maxThreads"; + private static final String THREAD_DELAY = "threadDelay"; + private static final String ACTIVE_FEEDER = "activeFeeder"; + private static final String SCAN_DEAD_HOSTS = "scanDeadHosts"; + private static final String SELECTED_PINGER = "selectedPinger"; + private static final String PING_TIMEOUT = "pingTimeout"; + private static final String PING_COUNT = "pingCount"; + private static final String SKIP_BROADCAST_ADDRESSES = "skipBroadcastAddresses"; + private static final String PORT_TIMEOUT = "portTimeout"; + private static final String ADAPT_PORT_TIMEOUT = "adaptPortTimeout"; + private static final String PORT_STRING = "portString"; + + private Preferences preferences = Config.getPreferences(); + + public int maxThreads = preferences.getInt(MAX_THREADS, 100); + public int threadDelay = preferences.getInt(THREAD_DELAY, 20); + public int activeFeeder = preferences.getInt(ACTIVE_FEEDER, 0); + public boolean scanDeadHosts = preferences.getBoolean(SCAN_DEAD_HOSTS, false); + public String selectedPinger = preferences.get(SELECTED_PINGER, "pinger.icmp"); + public int pingTimeout = preferences.getInt(PING_TIMEOUT, 3000); + public int pingCount = preferences.getInt(PING_COUNT, 3); + public boolean skipBroadcastAddresses = preferences.getBoolean(SKIP_BROADCAST_ADDRESSES, true); + public int portTimeout = preferences.getInt(PORT_TIMEOUT, 3000);; + public boolean adaptPortTimeout = preferences.getBoolean(ADAPT_PORT_TIMEOUT, true); + public String portString = preferences.get(PORT_STRING, ""); + + /** + * Stores all the internal properties to the storage media + */ + public void store() { + preferences.putInt(MAX_THREADS, maxThreads); + preferences.putInt(THREAD_DELAY, threadDelay); + preferences.putInt(ACTIVE_FEEDER, activeFeeder); + preferences.putBoolean(SCAN_DEAD_HOSTS, scanDeadHosts); + preferences.put(SELECTED_PINGER, selectedPinger); + preferences.putInt(PING_TIMEOUT, pingTimeout); + preferences.putInt(PING_COUNT, pingCount); + preferences.putBoolean(SKIP_BROADCAST_ADDRESSES, skipBroadcastAddresses); + preferences.putInt(PORT_TIMEOUT, portTimeout); + preferences.putBoolean(ADAPT_PORT_TIMEOUT, adaptPortTimeout); + preferences.put(PORT_STRING, portString); + } + + // package local constructor + GlobalConfig() { + } +} diff --git a/ipscan/src/net/azib/ipscan/config/Labels.java b/ipscan/src/net/azib/ipscan/config/Labels.java new file mode 100755 index 00000000..84f98440 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/Labels.java @@ -0,0 +1,98 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; + +/** + * Labels class for localization, based on PropertyResourceBundle. + * It adds some special methods for loading of images by IDs. + * + * It is a singleton, so use getInstance() in order to use this class. + * + * Use initialize() to create an instance of this class. + * + * @author anton + */ +public final class Labels { + + private static Labels instance; + + PropertyResourceBundle labels; + Locale locale; + + static { + // this is needed for Visual Editor to display + // labels at design time + initialize(new Locale("en")); + } + + private Labels() { + // private constructor + } + + public static final Labels getInstance() { + return instance; + } + + /** + * Initialized the internal locale-specific data. + * The files Labels_LANG.txt and Labels.txt are searched for + * in the same package as this class. + * This method must be called prior to using this class. + */ + public static void initialize(Locale locale) { + if (instance != null && locale.equals(instance.locale)) { + // do not reload locale, because it was already initialized in the static block + return; + } + // create a new instance + instance = new Labels(); + + instance.locale = locale; + InputStream labelsStream = null; + labelsStream = Labels.class.getClassLoader().getResourceAsStream("Labels_" + locale.getLanguage().toUpperCase() + ".txt"); + if (labelsStream == null) { + labelsStream = Labels.class.getClassLoader().getResourceAsStream("Labels.txt"); + } + if (labelsStream == null) { + throw new MissingResourceException("Labels not found!", Labels.class.getName(), "Labels"); + } + try { + instance.labels = new PropertyResourceBundle(labelsStream); + } + catch (IOException e) { + throw new MissingResourceException(e.toString(), Labels.class.getName(), "Labels"); + } + } + + /** + * Retrieves an InputStream to load the image, specified by a key in resource file. + * @param key + */ + public InputStream getImageAsStream(String key) { + String imagePath = labels.getString(key); + return getClass().getClassLoader().getResourceAsStream(imagePath); + } + + /** + * Retrieves a String specified by the label key + * @param key + */ + public String get(String key) { + return labels.getString(key); + } + + /** + * A shortened form of Labels.getLabel() + */ + public static String getLabel(String key) { + return getInstance().get(key); + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/NamedListConfig.java b/ipscan/src/net/azib/ipscan/config/NamedListConfig.java new file mode 100755 index 00000000..8c967c26 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/NamedListConfig.java @@ -0,0 +1,117 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.prefs.Preferences; + +/** + * This is a generic named list config. + * Can be used for storing favorites, openers, and other + * user-defined configurations. + * + * @author anton + */ +public class NamedListConfig { + + protected String preferenceName; + protected Preferences preferences = Config.getPreferences(); + protected Map namedList = new LinkedHashMap(); + + // package local constructor + NamedListConfig(String preferenceName) { + this.preferenceName = preferenceName; + load(); + } + + /** + * This constructor is for tests + * @param preferences + */ + NamedListConfig(Preferences preferences, String preferenceName) { + this.preferenceName = preferenceName; + this.preferences = preferences; + load(); + } + + /** + * Loads preferences + */ + public void load() { + if (preferences == null) { + return; + } + + String[] namedListPrefs = preferences.get(preferenceName, "").split("###"); + for (int i = 0; i < namedListPrefs.length; i += 2) { + if (namedListPrefs[i].length() > 0) { + namedList.put(namedListPrefs[i], serializeValue(namedListPrefs[i+1])); + } + } + } + + Object serializeValue(String value) { + return value; + } + + /** + * Stores the currently available named list + */ + public void store() { + StringBuffer sb = new StringBuffer(32); + for (Iterator i = namedList.entrySet().iterator(); i.hasNext();) { + Map.Entry e = (Map.Entry) i.next(); + sb.append(e.getKey()).append("###").append(e.getValue()).append("###"); + } + if (sb.length() > 3) { + sb.delete(sb.length() - 3, sb.length()); + } + preferences.put(preferenceName, sb.toString()); + } + + /** + * @param name displayed to the user + * @param value to store according to the name + */ + public void add(String name, Object value) { + namedList.put(name, value); + } + + /** + * @param name name + * @return stored value + */ + public String get(String name) { + return (String) namedList.get(name); + } + + /** + * @return an Iterator for iterating names of available items + */ + public Iterator iterateNames() { + return namedList.keySet().iterator(); + } + + public int size() { + return namedList.size(); + } + + /** + * Updates the list, retaining only items that are passed in the array. + * The order of elements will be the same as in the array. + * + * @param names + */ + public void update(String[] names) { + // rebuild the map (to recreate the new order of elements) + Map newList = new LinkedHashMap(); + for (int i = 0; i < names.length; i++) { + newList.put(names[i], namedList.get(names[i])); + } + namedList = newList; + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/OpenersConfig.java b/ipscan/src/net/azib/ipscan/config/OpenersConfig.java new file mode 100755 index 00000000..d74c8bc5 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/OpenersConfig.java @@ -0,0 +1,87 @@ +/** + * + */ +package net.azib.ipscan.config; + +import java.io.File; +import java.util.logging.Logger; +import java.util.prefs.Preferences; + +/** + * OpenersConfig + * + * @author anton + */ +public class OpenersConfig extends NamedListConfig { + + public OpenersConfig() { + super("openers"); + + if (size() == 0) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + + Labels labels = Labels.getInstance(); + // add default openers + if (isWindows) add(labels.get("opener.netbios"), new Opener("\\\\${fetcher.ip}", false, null)); + add(labels.get("opener.web"), new Opener("http://${fetcher.ip}/", false, null)); + add(labels.get("opener.ftp"), new Opener("ftp://${fetcher.ip}/", false, null)); + add(labels.get("opener.telnet"), new Opener("telnet ${fetcher.ip}", true, null)); + if (!isWindows) add(labels.get("opener.ssh"), new Opener("ssh ${fetcher.ip}", true, null)); + add(labels.get("opener.email"), new Opener("mailto:somebody@example.com?subject=IP: ${fetcher.ip}", true, null)); + } + } + + /** + * This constructor is for tests + * @param preferences + */ + OpenersConfig(Preferences preferences) { + super(preferences, "openers"); + } + + Object serializeValue(String value) { + return new Opener(value); + } + + public void add(String name, Object value) { + if (value instanceof Opener) + super.add(name, value); + else + // ensure only Openers are allowed here + throw new IllegalArgumentException(); + } + + public Opener getOpener(String name) { + return (Opener)namedList.get(name); + } + + public static class Opener { + public String execString; + public boolean inTerminal; + public File workingDir; + + Opener(String serialized) { + try { + String[] parts = serialized.split("@@@"); + execString = parts[0]; + inTerminal = parts[1].charAt(0) == '1'; + workingDir = parts.length >= 3 && parts[2].length() > 0 ? new File(parts[2]) : null; + } + catch (ArrayIndexOutOfBoundsException e) { + // this happens when broken settings have been loaded + Logger.global.fine("Broken opener config read: " + serialized); + } + } + + public Opener(String execString, boolean inTerminal, File workingDir) { + this.execString = execString; + this.inTerminal = inTerminal; + this.workingDir = workingDir; + } + + public String toString() { + return execString + "@@@" + (inTerminal ? '1' : '0') + "@@@" + (workingDir != null ? workingDir.toString() : ""); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/config/Version.java b/ipscan/src/net/azib/ipscan/config/Version.java new file mode 100755 index 00000000..bab7ba72 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/config/Version.java @@ -0,0 +1,30 @@ +/** + * This is a part of Angry IP Scanner source. + */ +package net.azib.ipscan.config; + +/** + * Class with accessors to version information of the program. + * + * @author anton + * @version $Id: Version.java,v 1.2 2005/11/20 14:08:28 angryziber Exp $ + */ +public class Version { + public static final String NAME = "Angry IP Scanner"; + + public static final String VERSION = "2.9-alpha"; + + public static final String FULL_NAME = NAME + " " + VERSION; + + public static final String COPYLEFT = "(C) 1998-2006 Anton Keks"; + + public static final String WEBSITE = "http://www.azib.net/ipscan/"; + + public static final String MAILTO = "support@azib.net"; + + public static final String FORUM_URL = "http://www.azib.net/ipscan/forum/"; + + public static final String PLUGINS_URL = "http://www.azib.net/ipscan/plugins/"; + + public static final String LATEST_VERSION_URL = "http://www.azib.net/ipscan/IPSCAN.VERSION"; +} diff --git a/ipscan/src/net/azib/ipscan/core/InetAddressUtils.java b/ipscan/src/net/azib/ipscan/core/InetAddressUtils.java new file mode 100755 index 00000000..96412f3a --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/InetAddressUtils.java @@ -0,0 +1,160 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +/** + * This class provides various utility static methods, + * useful for transforming InetAddress objects. + * + * @author anton + */ +public class InetAddressUtils { + + // Warning! IPv4 specific code + public static final Pattern IP_ADDRESS_REGEX = Pattern.compile("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + public static InetAddress startRangeByNetmask(InetAddress address, InetAddress netmask) { + byte[] netmaskBytes = netmask.getAddress(); + byte[] addressBytes = address.getAddress(); + for (int i = 0; i < addressBytes.length; i++) { + addressBytes[i] = (byte) (addressBytes[i] & netmaskBytes[i]); + } + try { + return InetAddress.getByAddress(addressBytes); + } + catch (UnknownHostException e) { + // this should never happen as we are modifying the same bytes + // received from the InetAddress + return null; + } + } + + public static InetAddress endRangeByNetmask(InetAddress address, InetAddress netmask) { + byte[] netmaskBytes = netmask.getAddress(); + byte[] addressBytes = address.getAddress(); + for (int i = 0; i < addressBytes.length; i++) { + addressBytes[i] = (byte) (addressBytes[i] | ~(netmaskBytes[i])); + } + try { + return InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + // this should never happen as we are modifying the same bytes + // received from the InetAddress + return null; + } + } + + /** + * Compares two IP addresses. + * @return true in case inetAddress1 is greater than inetAddress2 + */ + public static boolean greaterThan(InetAddress inetAddress1, InetAddress inetAddress2) { + byte[] address1 = inetAddress1.getAddress(); + byte[] address2 = inetAddress2.getAddress(); + for (int i = 0; i < address1.length; i++) { + if ((address1[i] & 0xFF) > (address2[i] & 0xFF)) + return true; + else + if ((address1[i] & 0xFF) < (address2[i] & 0xFF)) + break; + } + return false; + } + + /** + * Increments an IP address by 1. + */ + public static InetAddress increment(InetAddress address) { + try { + byte[] newAddress = address.getAddress(); + for (int i = newAddress.length-1; i >= 0; i--) { + if (++newAddress[i] != 0x00) + break; + } + return InetAddress.getByAddress(newAddress); + } + catch (UnknownHostException e) { + // this exception is unexpected here + assert false : e; + return null; + } + } + + /** + * Parses the netmask string provided in special text format: + * A.B.C.D, where each term is 0-255 or empty. If any term is empty, it is the same as 255. + * @param netmaskString + * @throws UnknownHostException + */ + public static InetAddress parseNetmask(String netmaskString) throws UnknownHostException { + netmaskString = netmaskString.replaceAll("\\.\\.", ".255."); + netmaskString = netmaskString.replaceAll("\\.\\.", ".255."); + InetAddress netmask = InetAddress.getByName(netmaskString); + return netmask; + } + + /** + * Where mask bits are set, we use prototype bits. + * Where mask bits are cleared, we leave bits as is. + * @param addressBytes this array is modified according to the maskBytes and prototypeBytes + * @param maskBytes + * @param prototypeBytes + */ + public static void maskPrototypeAddressBytes(byte[] addressBytes, byte[] maskBytes, byte[] prototypeBytes) { + for (int i = 0; i < addressBytes.length; i++) { + addressBytes[i] = (byte) ((addressBytes[i] & ~maskBytes[i]) | (prototypeBytes[i] & maskBytes[i])); + } + } + + /** + * Checks whether the passed address is likely either a broadcast or network address + * @param address + */ + public static boolean isLikelyBroadcast(InetAddress address) { + byte[] bytes = address.getAddress(); + return bytes[bytes.length-1] == 0 || bytes[bytes.length-1] == (byte)0xFF; + } + + /** + * Returns an IP address by hostname. + * This method correctly resolves the local IP address on Linux. + * @param hostname + * @return IP address as String + * @throws UnknownHostException + */ + public static String getAddressByName(String hostname) throws UnknownHostException { + InetAddress address = InetAddress.getByName(hostname); + if (address.isLoopbackAddress()) { + // loopback address (127.0.0.1) was returned, try to find the local address + // by enumeration of network interfaces + try { + outer: + for (Enumeration i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements(); ) { + NetworkInterface networkInterface = (NetworkInterface) i.nextElement(); + for (Enumeration i2 = networkInterface.getInetAddresses(); i2.hasMoreElements();) { + InetAddress currentAddress = (InetAddress) i2.nextElement(); + if (!currentAddress.isLoopbackAddress()) { + address = currentAddress; + break outer; + } + } + } + } + catch (SocketException e) { + Logger.global.log(Level.FINE, "Cannot enumerate network interfaces", e); + } + } + return address.getHostAddress(); + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/IntegerWithUnit.java b/ipscan/src/net/azib/ipscan/core/IntegerWithUnit.java new file mode 100755 index 00000000..444048f1 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/IntegerWithUnit.java @@ -0,0 +1,54 @@ +/** + * + */ +package net.azib.ipscan.core; + +import net.azib.ipscan.config.Labels; + +/** + * IntegerWithUnit - an Integer value together with a unit, e.g. "10 ms" + * + * @author anton + */ +public class IntegerWithUnit implements Comparable { + + private int value; + private String unitLabel; + + public IntegerWithUnit(int value, String unitLabel) { + this.value = value; + this.unitLabel = unitLabel; + } + + public int intValue() { + return value; + } + + public String toString() { + return value + Labels.getLabel(unitLabel); + } + + public int hashCode() { + return value; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (obj instanceof IntegerWithUnit) + return value == ((IntegerWithUnit) obj).value; + return false; + } + + public int compareTo(Object obj) { + if (this == obj) + return 0; + if (obj == null) + return 1; + int other = ((IntegerWithUnit) obj).value; + return value == other ? 0 : value > other ? 1 : -1; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/NotAvailableValue.java b/ipscan/src/net/azib/ipscan/core/NotAvailableValue.java new file mode 100755 index 00000000..5a733e8a --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/NotAvailableValue.java @@ -0,0 +1,37 @@ +/** + * + */ +package net.azib.ipscan.core; + +import net.azib.ipscan.config.Labels; + +/** + * The value for displaying in the result list, meaning that the actual value is unknown, + * because it wasn't resolved successfully. + * + * @author anton + */ +public class NotAvailableValue implements Comparable { + + public static final NotAvailableValue INSTANCE = new NotAvailableValue(); + + private NotAvailableValue() {} + + /** + * Displays a user-friendly text string :-) + */ + public String toString() { + // TODO: make this configurable + return Labels.getLabel("fetcher.value.notAvailable"); + } + + public int compareTo(Object obj) { + if (this == obj) + return 0; + if (obj == null) + return 1; + // this value is smaller than any other object (except null) + return -1; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/NotScannedValue.java b/ipscan/src/net/azib/ipscan/core/NotScannedValue.java new file mode 100755 index 00000000..c9b14003 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/NotScannedValue.java @@ -0,0 +1,37 @@ +/** + * + */ +package net.azib.ipscan.core; + +import net.azib.ipscan.config.Labels; + +/** + * The value for displaying in the result list, meaning that the actual value is unknown, + * because it was not scanned. + * + * @author anton + */ +public class NotScannedValue implements Comparable { + + public static final NotScannedValue INSTANCE = new NotScannedValue(); + + private NotScannedValue() {} + + /** + * Displays a user-friendly text string :-) + */ + public String toString() { + // TODO: make this configurable + return Labels.getLabel("fetcher.value.notScanned"); + } + + public int compareTo(Object obj) { + if (this == obj) + return 0; + if (obj == null) + return 1; + // this value is smaller than any other object (except null) + return -1; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/PortIterator.java b/ipscan/src/net/azib/ipscan/core/PortIterator.java new file mode 100755 index 00000000..71ca1f14 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/PortIterator.java @@ -0,0 +1,87 @@ +/** + * + */ +package net.azib.ipscan.core; + +/** + * A class for iteration of ports, specified in special format, like: + * 1,5-7,35-40 + * + * @author anton + */ +public final class PortIterator implements Cloneable { + + private int[] portRangeStart; + private int[] portRangeEnd; + + private int rangeCountMinus1; + private int rangeIndex; + private int currentPort; + + private boolean hasNext; + + /** + * Constructs the PortIterator instance + * @param portString the port string to parse + */ + public PortIterator(String portString) { + + if (portString != null && (portString = portString.trim()).length() > 0) { + String[] portRanges = portString.split("[ \t\n\r,;]+"); + + // initialize storage + portRangeStart = new int[portRanges.length+1]; // +1 for optimiation of 'next' method, prevents ArrayIndexOutOfBoundsException + portRangeEnd = new int[portRanges.length]; + + // parse ints + for (int i = 0; i < portRanges.length; i++) { + String range = portRanges[i]; + int dashPos = range.indexOf('-') + 1; + int endPort = Integer.parseInt(range.substring(dashPos)); + portRangeEnd[i] = endPort; + portRangeStart[i] = dashPos == 0 ? endPort : Integer.parseInt(range.substring(0, dashPos-1)); + } + + currentPort = portRangeStart[0]; + rangeCountMinus1 = portRanges.length - 1; + hasNext = rangeCountMinus1 >= 0; + } + } + + /** + * @return true if there are more ports left + */ + public boolean hasNext() { + return hasNext; + } + + /** + * @return next port number + */ + public int next() { + int returnPort = currentPort++; + + if (currentPort > portRangeEnd[rangeIndex]) { + hasNext = rangeIndex < rangeCountMinus1; + rangeIndex++; + currentPort = portRangeStart[rangeIndex]; + } + + return returnPort; + } + + /** + * Clones the PortIterator instance. + * @return a shallow copy + */ + public PortIterator copy() { + try { + return (PortIterator) super.clone(); + } + catch (CloneNotSupportedException e) { + assert false : "this should never happen"; + return null; + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/Scanner.java b/ipscan/src/net/azib/ipscan/core/Scanner.java new file mode 100755 index 00000000..808078c7 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/Scanner.java @@ -0,0 +1,72 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; +import java.util.Iterator; + +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; + +/** + * Scanner functionality is encapsulated in this class. + * It uses a list of fetchers to perform the actual scanning. + * + * @author anton + */ +public class Scanner { + + private FetcherRegistry fetcherRegistry; + + public Scanner(FetcherRegistry fetcherRegistry) { + this.fetcherRegistry = fetcherRegistry; + } + + /** + * Executes all registered fetchers for the current IP address. + * @param address the IP address to scan + * @param result where the results are injected + */ + public void scan(InetAddress address, ScanningResult result) { + + // create a scanning subject object, which will be used by fetchers + // to cache common information + ScanningSubject scanningSubject = new ScanningSubject(address); + + // populate results + int fetcherIndex = 0; + for (Iterator i = fetcherRegistry.getSelectedFetchers().iterator(); i.hasNext();) { + Fetcher fetcher = (Fetcher) i.next(); + if (!scanningSubject.isScanningAborted()) { + Object value = fetcher.scan(scanningSubject); + result.setValue(fetcherIndex, value != null ? value : NotAvailableValue.INSTANCE); + } + else { + result.setValue(fetcherIndex, NotScannedValue.INSTANCE); + } + fetcherIndex++; + } + + result.setType(scanningSubject.getResultType()); + } + + /** + * Init everything needed for scanning, including Fetchers + */ + public void init() { + for (Iterator i = fetcherRegistry.getSelectedFetchers().iterator(); i.hasNext();) { + ((Fetcher)i.next()).init(); + } + } + + /** + * Cleanup after a scan + */ + public void cleanup() { + for (Iterator i = fetcherRegistry.getSelectedFetchers().iterator(); i.hasNext();) { + ((Fetcher)i.next()).cleanup(); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/ScannerThread.java b/ipscan/src/net/azib/ipscan/core/ScannerThread.java new file mode 100755 index 00000000..ad46fae2 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScannerThread.java @@ -0,0 +1,148 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.feeders.Feeder; + +/** + * Scanning thread. + * + * @author anton + */ +public class ScannerThread extends Thread { + + private Scanner scanner; + private ScanningResultList scanningResultList; + private Feeder feeder; + private ScanningStateCallback statusCallback; + private ScanningResultsCallback resultsCallback; + private int state; + private int runningThreads; + private int maxThreads = Config.getGlobal().maxThreads; + private int threadDelay = Config.getGlobal().threadDelay; + + public ScannerThread(Feeder feeder, Scanner scanner, ScanningResultList scanningResults) { + super("Scanner Thread"); + // this thread is daemon because we want JVM to terminate it + // automatically if user closes the program (Main thread, that is) + setDaemon(true); + this.feeder = feeder; + this.scanner = scanner; + this.scanningResultList = scanningResults; + } + + public void run() { + changeStatus(ScanningStateCallback.STATE_SCANNING); + + scanner.init(); + + while(feeder.hasNext() && state == ScanningStateCallback.STATE_SCANNING) { + try { + + // make a small delay between thread creation + Thread.sleep(threadDelay); + + if (runningThreads >= maxThreads) { + // skip this iteration until more threads can be created + continue; + } + + // rerieve the next IP address to scan + final InetAddress address = feeder.next(); + + // check if this is a likely broadcast address and needs to be skipped + if (Config.getGlobal().skipBroadcastAddresses && InetAddressUtils.isLikelyBroadcast(address)) { + continue; + } + + // now increment the number of active threads, because we are going + // to start a new one below + runningThreads++; + + // prepare results receiver for upcoming results + int preparationNumber = resultsCallback.prepareForResults(address); + + // notify listeners of the progress we are doing + statusCallback.updateProgress(address, runningThreads, feeder.getPercentageComplete()); + + // scan each IP in parallel, in a separate thread + new IPThread(address, preparationNumber).start(); + } + catch (InterruptedException e) { + return; + } + } + + // inform that no more addresses left + changeStatus(ScanningStateCallback.STATE_STOPPING); + + // now wait for all threads, which are still running + try { + // TODO: make a better and safer implementation + while (runningThreads > 0) { + Thread.sleep(200); + statusCallback.updateProgress(null, runningThreads, 100); + } + } + catch (InterruptedException e) { + // nothing special to do here + } + + scanner.cleanup(); + + // finally, the scanning is complete + changeStatus(ScanningStateCallback.STATE_IDLE); + } + + private void changeStatus(int status) { + this.state = status; + statusCallback.scannerStateChanged(status); + } + + public void forceStop() { + changeStatus(ScanningStateCallback.STATE_STOPPING); + } + + public void abort() { + changeStatus(ScanningStateCallback.STATE_KILLING); + } + + public void setResultsCallback(ScanningResultsCallback resultsCallback) { + this.resultsCallback = resultsCallback; + } + + public void setStatusCallback(ScanningStateCallback statusCallback) { + this.statusCallback = statusCallback; + } + + /** + * This thread gets executed for each scanned IP address to do the actual + * scanning. + */ + private class IPThread extends Thread { + private InetAddress address; + private int preparationIndex; + + IPThread(InetAddress address, int preparationIndex) { + super("IP Thread: " + address.getHostAddress()); + setDaemon(true); + this.address = address; + this.preparationIndex = preparationIndex; + } + + public void run() { + try { + ScanningResult result = scanningResultList.getResult(preparationIndex); + scanner.scan(address, result); + resultsCallback.consumeResults(preparationIndex, result); + } + finally { + runningThreads--; + } + } + } +} diff --git a/ipscan/src/net/azib/ipscan/core/ScannerThreadFactory.java b/ipscan/src/net/azib/ipscan/core/ScannerThreadFactory.java new file mode 100755 index 00000000..f153fd4b --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScannerThreadFactory.java @@ -0,0 +1,27 @@ +/** + * + */ +package net.azib.ipscan.core; + +import net.azib.ipscan.feeders.Feeder; + +/** + * ScannerThreadFactory + * + * @author anton + */ +public class ScannerThreadFactory { + + private ScanningResultList scanningResults; + private Scanner scanner; + + public ScannerThreadFactory(ScanningResultList scanningResults, Scanner scanner) { + this.scanningResults = scanningResults; + this.scanner = scanner; + } + + public ScannerThread createScannerThread(Feeder feeder) { + return new ScannerThread(feeder, scanner, scanningResults); + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/ScanningResult.java b/ipscan/src/net/azib/ipscan/core/ScanningResult.java new file mode 100755 index 00000000..0d606868 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScanningResult.java @@ -0,0 +1,71 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.List; + +/** + * The holder of scanning result for a single IP address. + * + * @author anton + */ +public class ScanningResult { + + /** The scanned IP address */ + private InetAddress address; + /** Scanning results, result of each Fetcher is an element */ + private Object[] values; + /** Scanning result type, see constants in {@link ScanningSubject} */ + private int type; + + /** + * Creates a new instance, initializing the first value to the + * provided address + * @param address + * @param numberOfFetchers the number of currently available fetchers + */ + ScanningResult(InetAddress address, int numberOfFetchers) { + this.address = address; + values = new Object[numberOfFetchers]; + values[0] = address.getHostAddress(); + type = ScanningSubject.RESULT_TYPE_UNKNOWN; + } + + public InetAddress getAddress() { + return address; + } + + /** + * @return the scanning results as an unmodifiable List, result of each Fetcher is an element + */ + public List getValues() { + return Arrays.asList(values); + } + + /** + * Sets scanning result type, see constants in {@link ScanningSubject} + */ + void setType(int type) { + this.type = type; + } + + /** + * @return the scanning result type, see constants in {@link ScanningSubject} + */ + public int getType() { + return type; + } + + /** + * Sets the value returned by the specified fetcher + * @param fetcherIndex + * @param value + */ + public void setValue(int fetcherIndex, Object value) { + values[fetcherIndex] = value; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/ScanningResultList.java b/ipscan/src/net/azib/ipscan/core/ScanningResultList.java new file mode 100755 index 00000000..25156239 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScanningResultList.java @@ -0,0 +1,153 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; + +/** + * The holder of scanning results. + * + * @author anton + */ +public class ScanningResultList { + + private static final int RESULT_LIST_INITIAL_SIZE = 1024; + + private FetcherRegistry fetcherRegistry; + // selected fetchers are cached here, because the may be changed in the registry already + private List selectedFetchers; + + private List resultList = new ArrayList(1024); + private ResultsComparator resultsComparator = new ResultsComparator(); + + public ScanningResultList(FetcherRegistry fetcherRegistry) { + this.fetcherRegistry = fetcherRegistry; + clear(); + } + + /** + * @return selected fetchers that were used for the last scan + * Note: they may be different from {@link FetcherRegistry#getSelectedFetchers()} + */ + public List getFetchers() { + return selectedFetchers; + } + + /** + * Adds the new scanned IP address + * @param address + * @return the index of the added address, can be used in calls to other methods + */ + public synchronized int add(InetAddress address) { + int index = resultList.size(); + resultList.add(new ScanningResult(address, fetcherRegistry.getSelectedFetchers().size())); + return index; + } + + /** + * Returns all results for a particular IP address as a String. + * This is used in showing the IP Details dialog box. + * TODO: write tests! + * + * @param index + * @return + */ + public synchronized String getResultsAsString(int index) { + // cross-platform newline :-) + String newLine = System.getProperty("line.separator"); + + ScanningResult scanningResult = (ScanningResult) resultList.get(index); + StringBuffer details = new StringBuffer(1024); + Iterator iterator = scanningResult.getValues().iterator(); + for (int i = 0; iterator.hasNext(); i++) { + String fetcherName = Labels.getLabel(((Fetcher)selectedFetchers.get(i)).getLabel()); + details.append(fetcherName).append(":\t"); + Object value = iterator.next(); + details.append(value != null ? value : ""); + details.append(newLine).append("--------------------------------------------------------------------------------------").append(newLine); + } + return details.toString(); + } + + /** + * Clears previous scanning results, prepares for a new scan. + */ + public synchronized void clear() { + // clear the results + resultList.clear(); + // reload currently selected fetchers + selectedFetchers = new ArrayList(fetcherRegistry.getSelectedFetchers()); + } + + /** + * @return an Iterator of scanning results + * + * Note: the returned Iterator is not synchronized + */ + public synchronized Iterator iterator() { + return resultList.iterator(); + } + + /** + * @param index + * @return the results of the IP adress, corresponding to an index + */ + public synchronized ScanningResult getResult(int index) { + return (ScanningResult) resultList.get(index); + } + + /** + * Removes the elements by the provided indices + * Note: old indices returned by {@link #add(InetAddress)} are no longer valid + * @param indices a sorted list of indices to remove + */ + public synchronized void remove(int[] indices) { + // this rebuild is faster then a number of calls to remove() + // however, a further speedup can be obtained by using a Set instead of binarySearch() + List newList = new ArrayList(RESULT_LIST_INITIAL_SIZE); + for (int i = 0; i < resultList.size(); i++) { + if (Arrays.binarySearch(indices, i) < 0) + newList.add(resultList.get(i)); + } + resultList = newList; + } + + /** + * Sorts by the specified column index. + * Note: old indices returned by {@link #add(InetAddress)} are no longer valid + * @param columnIndex + */ + public synchronized void sort(int columnIndex) { + resultsComparator.index = columnIndex; + Collections.sort(resultList, resultsComparator); + } + + private static class ResultsComparator implements Comparator { + + private int index; + + public int compare(Object o1, Object o2) { + if (!(o1 instanceof ScanningResult)) + return -1; + if (!(o2 instanceof ScanningResult)) + return 1; + + Object val1 = ((ScanningResult)o1).getValues().get(index); + Object val2 = ((ScanningResult)o2).getValues().get(index); + + return val1.toString().compareTo(val2.toString()); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/ScanningResultsCallback.java b/ipscan/src/net/azib/ipscan/core/ScanningResultsCallback.java new file mode 100755 index 00000000..fec87e00 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScanningResultsCallback.java @@ -0,0 +1,30 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; + +/** + * This callback is called to consume scanning results. + * + * @author anton + */ +public interface ScanningResultsCallback { + + /** + * This method is called just before starting to retrieve + * scanning results for the specified address. + * @param address + * @return the method should return an int + */ + public int prepareForResults(InetAddress address); + + /** + * This method is called when scanning results are ready. + * @param preparationNumber the number, which was previously returned by prepareForResults(). + * @param results the List of Strings, each String corresponds to a Fetcher + */ + public void consumeResults(int preparationNumber, ScanningResult results); + +} diff --git a/ipscan/src/net/azib/ipscan/core/ScanningStateCallback.java b/ipscan/src/net/azib/ipscan/core/ScanningStateCallback.java new file mode 100755 index 00000000..bb40454f --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScanningStateCallback.java @@ -0,0 +1,40 @@ +/** + * + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; + +/** + * This callback is called on scanning status updates. + * + * @author anton + */ +public interface ScanningStateCallback { + + public static final int STATE_IDLE = 0; + public static final int STATE_SCANNING = 1; + public static final int STATE_STOPPING = 2; + public static final int STATE_KILLING = 3; + + /** + * This method is called on scanner status changes, + * eg. when scanning is about to stop. + * + * @param status integer value of current status, having the + * corresponding STATE_XXX constant + */ + public void scannerStateChanged(int status); + + /** + * This method is called on scanning progress updates. + * There are no guarantees that this method is called on every + * scanning iteration. + * + * @param currentAddress currently scanned IP address, can be null + * @param runningThreads number of currently running threads + * @param percentageComplete value from 0 to 100, showing how much work + * is already done. + */ + public void updateProgress(InetAddress currentAddress, int runningThreads, int percentageComplete); +} diff --git a/ipscan/src/net/azib/ipscan/core/ScanningSubject.java b/ipscan/src/net/azib/ipscan/core/ScanningSubject.java new file mode 100755 index 00000000..a0a76807 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/ScanningSubject.java @@ -0,0 +1,100 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.core; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; + +/** + * Scanning subject represents a single scanned + * IP address and any additional arbitrary parameters, + * which may be used to cache some intermediate data + * among different Fetchers. + * + * @author anton + */ +public class ScanningSubject { + + // constants for result type (they can be modified by some Fetchers) + public static final int RESULT_TYPE_UNKNOWN = 0; + public static final int RESULT_TYPE_DEAD = 1; + public static final int RESULT_TYPE_ALIVE = 2; + public static final int RESULT_TYPE_ADDITIONAL_INFO = 3; + + /** The address being scanned */ + private InetAddress address; + /** Arbitrary parameters for sharing among different (but related) Fetchers */ + private Map parameters; + /** The result type constant value, can be modified by some Fetchers */ + private int resultType = RESULT_TYPE_UNKNOWN; + /** Whether we need to continue scanning or it can be aborted */ + private boolean isScanningAborted = false; + + /** + * This constructor should only be used by the Scanner class or unit tests. + */ + public ScanningSubject(InetAddress address) { + this.address = address; + this.parameters = new HashMap(); + } + + public InetAddress getIPAddress() { + return address; + } + + /** + * Sets a subject specific named parameter. + */ + public void setParameter(String name, Object value) { + parameters.put(name, value); + } + + /** + * Gets a subject specific named parameter, + * previosly set by setParameter(). + */ + public Object getParameter(String name) { + return parameters.get(name); + } + + /** + * @return true in case parameter with given name was specified. + * This method is useful in case parameter value was null. + */ + public boolean hasParameter(String name) { + return parameters.containsKey(name); + } + + /** + * @return the result type constant value, possibly modified by Fetchers + */ + public int getResultType() { + return resultType; + } + + /** + * Provides an ability for Fetchers to determine the result type of scanning this particular address + * @param resultType constant value + */ + public void setResultType(int resultType) { + this.resultType = resultType; + } + + /** + * @return true if a fetcher has instructed to abort scanning + */ + public boolean isScanningAborted() { + return isScanningAborted; + } + + /** + * Can be used to inform the scanner to abort scanning + */ + public void abortScanning() { + this.isScanningAborted = true; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/ICMPPinger.java b/ipscan/src/net/azib/ipscan/core/net/ICMPPinger.java new file mode 100644 index 00000000..7561129c --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/ICMPPinger.java @@ -0,0 +1,139 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.savarese.rocksaw.net.RawSocket; +import org.savarese.vserv.tcpip.ICMPEchoPacket; +import org.savarese.vserv.tcpip.ICMPPacket; +import org.savarese.vserv.tcpip.IPPacket; +import org.savarese.vserv.tcpip.OctetConverter; + +/** + * Pinging code is encapsulated here. + * + * @author anton + */ +public class ICMPPinger implements Pinger { + + private static final Logger LOG = Logger.getLogger(ICMPPinger.class.getName()); + + private int timeout; + + public ICMPPinger(int timeout) { + this.timeout = timeout; + } + + private RawSocket createRawSocket() throws IOException { + RawSocket socket = new RawSocket(); + socket.open(RawSocket.PF_INET, IPPacket.PROTOCOL_ICMP); + + try { + socket.setSendTimeout(timeout); + socket.setReceiveTimeout(timeout); + } catch (java.net.SocketException se) { + socket.setUseSelectTimeout(true); + socket.setSendTimeout(timeout); + socket.setReceiveTimeout(timeout); + } + return socket; + } + + private void sendReceiveEchoPacket(RawSocket socket, InetAddress address, int sequence, PingResult result) throws IOException { + + ICMPEchoPacket packet = new ICMPEchoPacket(1); + byte[] data = new byte[84]; + packet.setData(data); + packet.setIPHeaderLength(5); + packet.setICMPDataByteLength(56); + packet.setType(ICMPPacket.TYPE_ECHO_REQUEST); + packet.setCode(0); + packet.setIdentifier(hashCode() & 0xFFFF); // some identification stuff + packet.setSequenceNumber(sequence); + + int offset = packet.getIPHeaderByteLength(); + int dataOffset = offset + packet.getICMPHeaderByteLength(); + int length = packet.getICMPPacketByteLength(); + + OctetConverter.longToOctets(System.currentTimeMillis(), data, dataOffset); + packet.computeICMPChecksum(); + + socket.write(address, data, offset, length); + + try { + int skippedCount = 0; + do { + socket.read(address, data); + skippedCount++; + //if (packet.getType() == ICMPPacket.TYPE_ECHO_REPLY) + // System.err.println(Thread.currentThread() + " " + packet.getSourceAsInetAddress().getHostAddress() + ": " + skippedCount); + } + while (packet.getType() != ICMPPacket.TYPE_ECHO_REPLY || + packet.getIdentifier() != (hashCode() & 0xFFFF) || + packet.getSequenceNumber() != sequence); + + if (packet.getSourceAsInetAddress().equals(address)) { + long end = System.currentTimeMillis(); + long start = OctetConverter.octetsToLong(data, dataOffset); + long time = end - start; + + result.totalTime += time; + result.replyCount++; + result.ttl = packet.getTTL() & 0xFF; + } + } + catch (InterruptedIOException e) { + // socket read timeout + LOG.finer("Receive timeout"); + // TODO: make RawSocket to throw Exceptions without the stack trace (for speed) + } + catch (UnknownHostException e) { + LOG.log(Level.WARNING, "Cannot retrieve the source address of an ICMP packet", e); + } + catch (IOException e) { + LOG.log(Level.WARNING, "Unable to read from the socket", e); + } + + } + + /** + * Issues the specified number of pings and + * waits for replies. + * + * @param address address to ping + * @param count number of pings to perform + */ + public PingResult ping(InetAddress address, int count) throws IOException { + + PingResult result = new PingResult(address); + RawSocket socket = createRawSocket(); + + try { + // send a bunch of packets + for (int i = 0; i < count; i++) { + try { + sendReceiveEchoPacket(socket, address, i, result); + } + catch (InterruptedIOException e) { + // ignore timeouts + } + } + } + finally { + socket.close(); + } + + return result; + } + + public void close() { + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/ICMPSharedPinger.java b/ipscan/src/net/azib/ipscan/core/net/ICMPSharedPinger.java new file mode 100755 index 00000000..783b43a2 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/ICMPSharedPinger.java @@ -0,0 +1,240 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.savarese.rocksaw.net.RawSocket; +import org.savarese.vserv.tcpip.ICMPEchoPacket; +import org.savarese.vserv.tcpip.ICMPPacket; +import org.savarese.vserv.tcpip.IPPacket; +import org.savarese.vserv.tcpip.OctetConverter; + +/** + * Shared multithreaded pinger. + * + * @author anton + */ +public class ICMPSharedPinger implements Pinger { + + private static final Logger LOG = Logger.getLogger(ICMPSharedPinger.class.getName()); + + /** a single raw socket for sending of all ICMP packets */ + private RawSocket sendingSocket; + /** a single raw socket for receiving of all ICMP packets */ + private RawSocket receivingSocket; + /** the map with PingResults, keys are InetAddress */ + private Map results = Collections.synchronizedMap(new HashMap()); + + private Thread receiverThread; + + private int timeout; + private int timeOffsetInPacket; + + public ICMPSharedPinger(int timeout) throws IOException { + // we use two shared sockets, because it works more efficiently + // OSs tend to copy all received ICMP packets to all open raw sockets, + // so it is very bad to have a separate raw socket for each scanning thread + sendingSocket = new RawSocket(); + sendingSocket.open(RawSocket.PF_INET, IPPacket.PROTOCOL_ICMP); + receivingSocket = new RawSocket(); + receivingSocket.open(RawSocket.PF_INET, IPPacket.PROTOCOL_ICMP); + this.timeout = timeout; + + try { + sendingSocket.setSendTimeout(timeout); + receivingSocket.setReceiveTimeout(timeout); + //receivingSocket.setReceiveBufferSize() + } + catch (java.net.SocketException se) { + sendingSocket.setUseSelectTimeout(true); + receivingSocket.setUseSelectTimeout(true); + sendingSocket.setSendTimeout(timeout); + receivingSocket.setReceiveTimeout(timeout); + } + + receiverThread = new PacketReceiverThread(); + receiverThread.start(); + } + + public void close() throws IOException { + synchronized (sendingSocket) { + sendingSocket.close(); + } + receiverThread.interrupt(); + } + + public PingResult ping(InetAddress address, int count) throws IOException { + + PingResult result = new PingResult(address); + results.put(address, result); + + // TODO: make ICMPEchoPacket accept byte array in the constructor + ICMPEchoPacket packet = new ICMPEchoPacket(1); + byte[] data = new byte[84]; + packet.setData(data); + packet.setIPHeaderLength(5); + packet.setICMPDataByteLength(56); + packet.setType(ICMPPacket.TYPE_ECHO_REQUEST); + packet.setCode(0); + packet.setIdentifier(hashCode() & 0xFFFF); // some identification stuff + + try { + // send a bunch of packets + // note: we send sequence numbers starting from 1 (this is used by the ReceiverThread) + for (int i = 1; i <= count; i++) { + packet.setSequenceNumber(i); + + int offset = packet.getIPHeaderByteLength(); + timeOffsetInPacket = offset + packet.getICMPHeaderByteLength(); + int length = packet.getICMPPacketByteLength(); + + OctetConverter.longToOctets(System.currentTimeMillis(), data, timeOffsetInPacket); + packet.computeICMPChecksum(); + + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("Pinging " + i + result.address); + } + synchronized (sendingSocket) { + sendingSocket.write(result.address, data, offset, length); + } + + try { + // a small pause between sending the packets + Thread.sleep(15); + } + catch (InterruptedException e) {} + } + + int totalTimeout = timeout * count; + while (totalTimeout > 0 && result.replyCount < count) { + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("Waiting for response " + address + ": " + totalTimeout); + } + synchronized (result) { + // wait until we have an answer + try { + result.wait(timeout); + } + catch (InterruptedException e) {} + } + totalTimeout -= timeout; + } + + + return result; + } + finally { + // remove garbage + results.remove(address); + } + } + + /** + * An internal thread for receiving of packets + */ + private class PacketReceiverThread extends Thread { + + public PacketReceiverThread() { + super("Ping packet receiver"); + setDaemon(true); + setPriority(Thread.MAX_PRIORITY); + } + + public void run() { + ICMPEchoPacket packet = new ICMPEchoPacket(1); + byte[] data = new byte[84]; + packet.setData(data); + packet.setIPHeaderLength(5); + packet.setICMPDataByteLength(56); + + // we use this address for receiving + // due to some reason, raw sockets return packets coming from any addresses anyway + InetAddress tmpAddress = null; + try { + tmpAddress = InetAddress.getLocalHost(); + } + catch (UnknownHostException e) { + LOG.log(Level.SEVERE, null, e); + } + + try { + // Windows OS cannot read from a raw socket before anything has been sent through it + receivingSocket.write(tmpAddress, data); + } + catch (IOException e) { + LOG.log(Level.WARNING, "Sending of test packet failed", e); + } + + do { + try { + receivingSocket.read(tmpAddress, data); + + if (packet.getType() == ICMPPacket.TYPE_ECHO_REPLY && + packet.getIdentifier() == (ICMPSharedPinger.this.hashCode() & 0xFFFF) && + packet.getSequenceNumber() > 0) { + + long endTime = System.currentTimeMillis(); + + PingResult result = (PingResult) results.get(packet.getSourceAsInetAddress()); + if (result == null) { + LOG.warning("ICMP packet received from an unknown address: " + packet.getSourceAsInetAddress()); + continue; + } + + long startTime = OctetConverter.octetsToLong(data, timeOffsetInPacket); + long time = endTime - startTime; + + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("Received " + packet.getSequenceNumber() + packet.getSourceAsInetAddress() + ": " + time); + } + + result.totalTime += time; + result.replyCount++; + // TTL should be the same among all packets + result.ttl = packet.getTTL() & 0xFF; + + synchronized (result) { + // notify the sender that we have an answer :-) + result.notifyAll(); + } + } + else + if (packet.getType() == ICMPPacket.TYPE_HOST_UNREACHABLE) { + // TODO: received non-ECHO_REPLY packets may also be useful, saying "destination is unreachable" + // packet body in this case is the sent ICMP_REQUEST packet + } + } + catch (InterruptedIOException e) { + // socket read timeout + LOG.finer("Receive timeout"); + // TODO: make RawSocket to throw Exceptions without the stack trace (for speed) + } + catch (UnknownHostException e) { + LOG.log(Level.WARNING, "Cannot retrieve the source address of an ICMP packet", e); + } + catch (IOException e) { + LOG.log(Level.WARNING, "Unable to read from the socket", e); + } + + } + while(!interrupted()); + + try { + receivingSocket.close(); + } + catch (IOException e) { } + LOG.fine("Terminated"); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/PingResult.java b/ipscan/src/net/azib/ipscan/core/net/PingResult.java new file mode 100755 index 00000000..753de288 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/PingResult.java @@ -0,0 +1,41 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.net.InetAddress; + +/** + * The result of pinging + * + * @author anton + */ +public class PingResult { + + InetAddress address; + + int ttl; + long totalTime; + int replyCount; + + public PingResult(InetAddress address) { + this.address = address; + + } + + public int getTTL() { + return ttl; + } + + public int getAverageTime() { + return (int)(totalTime / replyCount); + } + + /** + * @return true in case at least one reply was received + */ + public boolean isAlive() { + return replyCount > 0; + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/Pinger.java b/ipscan/src/net/azib/ipscan/core/net/Pinger.java new file mode 100755 index 00000000..2907a1b7 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/Pinger.java @@ -0,0 +1,30 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * Pinger + * + * @author anton + */ +public interface Pinger { + + /** + * Closes the raw socket opened by the constructor. After calling this + * method, the object cannot be used. + */ + public void close() throws IOException; + + /** + * Issues the specified number of pings and + * waits for replies. + * + * @param count number of pings to perform + */ + public PingResult ping(InetAddress address, int count) throws IOException; + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/PingerRegistry.java b/ipscan/src/net/azib/ipscan/core/net/PingerRegistry.java new file mode 100755 index 00000000..f013bb3c --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/PingerRegistry.java @@ -0,0 +1,25 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +/** + * PingerRegistry + * + * @author Anton Keks + */ +public interface PingerRegistry { + + /** + * @return a String array of pinger names (labels) + */ + public String[] getRegisteredNames(); + + /** + * Creates a new instance of currently selected Pinger + * @param timeout + * @return the instance + */ + public Pinger createPinger(String pingerName, int timeout); + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/PingerRegistryImpl.java b/ipscan/src/net/azib/ipscan/core/net/PingerRegistryImpl.java new file mode 100755 index 00000000..8a82c849 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/PingerRegistryImpl.java @@ -0,0 +1,58 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * PingerRegistryImpl + * + * @author Anton Keks + */ +public class PingerRegistryImpl implements PingerRegistry { + + private static final Logger LOG = Logger.getLogger(PingerRegistryImpl.class.getName()); + + /** All available Pinger implementations */ + private Map pingers; + + public PingerRegistryImpl() { + pingers = new LinkedHashMap(); + pingers.put("pinger.icmp", ICMPSharedPinger.class); + pingers.put("pinger.icmp2", ICMPPinger.class); + pingers.put("pinger.udp", UDPPinger.class); + pingers.put("pinger.tcp", TCPPinger.class); + + // TODO: implement a windows-specific ICMP pinger for XP SP2 and beyond that uses ping.dll + // TODO: autodetect working pingers here + } + + public String[] getRegisteredNames() { + return (String[]) pingers.keySet().toArray(new String[pingers.size()]); + } + + public Pinger createPinger(String pingerName, int timeout) { + Class pingerClass = (Class) pingers.get(pingerName); + Constructor constructor; + try { + constructor = pingerClass.getConstructor(new Class[] {int.class}); + return (Pinger) constructor.newInstance(new Object[] {new Integer(timeout)}); + } + catch (Exception e) { + Throwable t = e instanceof InvocationTargetException ? e.getCause() : e; + String message = "Unable to create pinger: " + pingerName; + LOG.log(Level.SEVERE, message, t); + if (t instanceof RuntimeException) + throw (RuntimeException) t; + throw new RuntimeException(message); + } + + } + +} diff --git a/ipscan/src/net/azib/ipscan/core/net/TCPPinger.java b/ipscan/src/net/azib/ipscan/core/net/TCPPinger.java new file mode 100755 index 00000000..84ef1c6b --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/TCPPinger.java @@ -0,0 +1,71 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NoRouteToHostException; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * TCP Pinger. Uses a TCP port to ping, doesn't require root privileges. + * + * @author anton + */ +public class TCPPinger implements Pinger { + + private static final Logger LOG = Logger.getLogger(UDPPinger.class.getName()); + + private static final int PROBE_TCP_PORT = 80; + + private int timeout; + + public TCPPinger(int timeout) { + // use double timeout, because TCP connect() produces more packets + this.timeout = timeout * 2; + } + + public PingResult ping(InetAddress address, int count) throws IOException { + PingResult result = new PingResult(address); + + Socket socket = new Socket(); + socket.setSoTimeout(timeout); + + long startTime = System.currentTimeMillis(); + try { + socket.connect(new InetSocketAddress(address, PROBE_TCP_PORT), timeout); + result.replyCount++; + result.totalTime+=System.currentTimeMillis()-startTime; + } + catch (ConnectException e) { + result.replyCount++; + result.totalTime+=System.currentTimeMillis()-startTime; + } + catch (SocketTimeoutException e) { + } + catch (NoRouteToHostException e) { + // TODO: this means that the host is down + } + catch (IOException e) { + LOG.setLevel(Level.ALL); + LOG.log(Level.FINER, null, e); + } + + try { + socket.close(); + } + catch (Exception e) {} + + return result; + } + + public void close() throws IOException { + // nothing to do here + } +} diff --git a/ipscan/src/net/azib/ipscan/core/net/UDPPinger.java b/ipscan/src/net/azib/ipscan/core/net/UDPPinger.java new file mode 100755 index 00000000..5e4be830 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/core/net/UDPPinger.java @@ -0,0 +1,65 @@ +/** + * + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.PortUnreachableException; +import java.net.SocketTimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * UDP Pinger. Uses an UDP port to ping, doesn't require root privileges. + * + * @author anton + */ +public class UDPPinger implements Pinger { + + private static final Logger LOG = Logger.getLogger(UDPPinger.class.getName()); + + private static final int PROBE_UDP_PORT = 33381; + + private int timeout; + + public UDPPinger(int timeout) { + this.timeout = timeout; + } + + public PingResult ping(InetAddress address, int count) throws IOException { + PingResult result = new PingResult(address); + + DatagramSocket socket = new DatagramSocket(); + socket.setSoTimeout(timeout); + socket.connect(address, PROBE_UDP_PORT); + + for (int i = 0; i < count; i++) { + DatagramPacket packet = new DatagramPacket(new byte[]{}, 0); + long startTime = System.currentTimeMillis(); + try { + socket.send(packet); + socket.receive(packet); + } + catch (PortUnreachableException e) { + result.replyCount++; + result.totalTime+=System.currentTimeMillis()-startTime; + } + catch (SocketTimeoutException e) { + } + catch (IOException e) { + LOG.log(Level.FINER, null, e); + } + } + + socket.disconnect(); + + return result; + } + + public void close() throws IOException { + // nothing to do here + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/CSVExporter.java b/ipscan/src/net/azib/ipscan/exporters/CSVExporter.java new file mode 100755 index 00000000..3480eba5 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/CSVExporter.java @@ -0,0 +1,105 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * CSV Exporter + * + * @author anton + */ +public class CSVExporter implements Exporter { + + /* CSV delimeter character */ + static final char DELIMETER = ','; + /* Delimeter escaping character (if data contains DELIMETER) */ + static final char DELIMETER_ESCAPED = '.'; + /* Newline character */ + static final String NEWLINE = System.getProperty("line.separator"); + + private Writer output; + private boolean isAppend; + + /* + * @see net.azib.ipscan.exporters.Exporter#getLabel() + */ + public String getLabel() { + return "exporter.csv"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#getFilenameExtension() + */ + public String getFilenameExtension() { + return "csv"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setAppend(boolean) + */ + public void setAppend(boolean append) { + isAppend = append; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#start(java.io.OutputStream, String) + */ + public void start(OutputStream outputStream, String feederInfo) { + output = new OutputStreamWriter(outputStream); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#end() + */ + public void end() throws IOException { + output.flush(); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setFetchers(String[]) + */ + public void setFetchers(String[] fetcherNames) throws IOException { + if (!isAppend) { + output.write(csvSafeString(fetcherNames[0])); + for (int i = 1; i < fetcherNames.length; i++) { + output.write(DELIMETER); + output.write(csvSafeString(fetcherNames[i])); + } + output.write(NEWLINE); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#nextAdressResults(Object[]) + */ + public void nextAdressResults(Object[] results) throws IOException { + output.write(csvSafeString(results[0])); + for (int i = 1; i < results.length; i++) { + Object result = results[i]; + output.write(DELIMETER); + output.write(csvSafeString(result)); + } + output.write(NEWLINE); + } + + /** + * @return a safe string to be outputted in CSV format (it doesn't contain the DELIMETER) + */ + String csvSafeString(Object o) { + if (o == null) + return ""; + return o.toString().replace(DELIMETER, DELIMETER_ESCAPED); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#clone() + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/ExportProcessor.java b/ipscan/src/net/azib/ipscan/exporters/ExportProcessor.java new file mode 100755 index 00000000..dd1cc3d7 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/ExportProcessor.java @@ -0,0 +1,79 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.FileOutputStream; +import java.util.Iterator; +import java.util.List; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.ScanningResult; +import net.azib.ipscan.core.ScanningResultList; +import net.azib.ipscan.fetchers.Fetcher; + +/** + * Export Processor controls the actual exporting using the provided Exporter. + * + * @author anton + */ +public class ExportProcessor { + + private Exporter exporter; + private String fileName; + + public ExportProcessor(Exporter exporter, String fileName) { + this.exporter = exporter; + this.fileName = fileName; + } + + /** + * Called to execute the actual scanning process. + * @param scanningResults the scanning results, which are available + * @param feederInfo info about the Feeder configuration as String + * @param resultSelector optional (can be null) - determines results for saving or skipping + */ + public void process(ScanningResultList scanningResults, String feederInfo, ScanningResultSelector resultSelector) { + FileOutputStream outputStream = null; + try { + outputStream = new FileOutputStream(fileName); + + exporter.start(outputStream, feederInfo); + + // set fetchers + List fetchers = scanningResults.getFetchers(); + String[] fetcherNames = new String[fetchers.size()]; + int i = 0; + for (Iterator j = fetchers.iterator(); j.hasNext(); i++) { + fetcherNames[i] = Labels.getLabel(((Fetcher)j.next()).getLabel()); + } + exporter.setFetchers(fetcherNames); + + int index = 0; + for (Iterator j = scanningResults.iterator(); j.hasNext(); index++) { + ScanningResult scanningResult = (ScanningResult) j.next(); + if (resultSelector == null || resultSelector.isResultSelected(index, scanningResult)) { + exporter.nextAdressResults(scanningResult.getValues().toArray()); + } + } + + exporter.end(); + } + catch (Exception e) { + throw new ExporterException("exporting failed", e); + } + finally { + try { + outputStream.close(); + } + catch (Exception e) {} + } + } + + /** + * ScanningResultSelector can be implemented and passed to {@link ExportProcessor#process(ScanningResultList, String)} + */ + public static interface ScanningResultSelector { + boolean isResultSelected(int index, ScanningResult result); + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/Exporter.java b/ipscan/src/net/azib/ipscan/exporters/Exporter.java new file mode 100755 index 00000000..3025e3ad --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/Exporter.java @@ -0,0 +1,78 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An Exporter is a class, which is able to export scanning results into a + * specific output format. + * + * This interface is callback-like. Each method of it is called when more + * data is available for writing. + * + * The sequence of calling: + * start, setFetchers, nextAddressResult, ..., end + * + * Exporters are created by cloning (prototype pattern). + * + * @author anton + */ +public interface Exporter extends Cloneable { + + /** + * @return label ID, representing the name of this exporter + */ + public String getLabel(); + + /** + * @return the filename extension of the file type this Exporter produces (like txt, html, etc) + */ + public String getFilenameExtension(); + + /** + * @param append determines whether to append to the existing file or create a new one. + * false by default. + */ + public void setAppend(boolean append); + + /** + * Called on start of the exporting. + * @param outputStream this OutputStream should be used to output exported data. + * @param feederInfo summary of feeder options, which were used for this scan + * @throws IOException + */ + public void start(OutputStream outputStream, String feederInfo) throws IOException; + + /** + * Called when no more data is available for exporting. This is the last + * method, which is called on any exporter. + * @throws IOException + */ + public void end() throws IOException; + + /** + * Called after the start to provide the whole list of fetchers + * @param fetcherNames + * @throws IOException + */ + public void setFetchers(String[] fetcherNames) throws IOException; + + /** + * Called to provide the actual scanning results for the IP address. + * @param results the results, returned by the Fetcher. This is an array of String + * most of the time or objects, which provide toString() methods. + * The IP address itself is the first element in the provided array. + * Any element of results can be null. + * @throws IOException + */ + public void nextAdressResults(Object[] results) throws IOException; + + /** + * Clones the Exporter instance + */ + public Object clone() throws CloneNotSupportedException; + +} diff --git a/ipscan/src/net/azib/ipscan/exporters/ExporterException.java b/ipscan/src/net/azib/ipscan/exporters/ExporterException.java new file mode 100755 index 00000000..d6af65b9 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/ExporterException.java @@ -0,0 +1,23 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +/** + * Exception for throwing in case of problems in Exporters. + * + * @author anton + */ +public class ExporterException extends IllegalArgumentException { + + static final long serialVersionUID = 746237846273847L; + + public ExporterException(String message) { + super(message); + } + + public ExporterException(String message, Throwable cause) { + super(message); + initCause(cause); + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/ExporterRegistry.java b/ipscan/src/net/azib/ipscan/exporters/ExporterRegistry.java new file mode 100755 index 00000000..e32b30a5 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/ExporterRegistry.java @@ -0,0 +1,58 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * The registry of all Exporters. + * It registers both plugins and builtins. + * + * @author anton + */ +public class ExporterRegistry { + + /** All available Exporter implementations, Map of Exporter instances (prototypes) */ + private Map exporters; + + public ExporterRegistry(Exporter[] registeredExporters) { + exporters = new LinkedHashMap(); + + for (int i = 0; i < registeredExporters.length; i++) { + exporters.put(registeredExporters[i].getFilenameExtension(), registeredExporters[i]); + } + } + + /** + * Iterates Exporter instances within this Registry + */ + public Iterator iterator() { + return exporters.values().iterator(); + } + + /** + * Creates a new exporter instance examining the extension of the provided file name + * @param fileName the file name (with extension) + * @throws ExporterException in case such exporter is not registered + */ + public Exporter createExporter(String fileName) throws ExporterException { + + int extensionPos = fileName.lastIndexOf('.') + 1; + String extension = fileName.substring(extensionPos); + + Exporter prototype = (Exporter) exporters.get(extension); + if (prototype == null) { + throw new ExporterException("exporter.unknown"); + } + try { + return (Exporter) prototype.clone(); + } + catch (CloneNotSupportedException e) { + // this is not possible + throw new RuntimeException(e); + } + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/IPListExporter.java b/ipscan/src/net/azib/ipscan/exporters/IPListExporter.java new file mode 100755 index 00000000..840702e3 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/IPListExporter.java @@ -0,0 +1,120 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.PortIterator; + +/** + * IP List Exporter + *

+ * Exports only IP:port info, outputting each distinct IP:port pair on separate line. + * + * @author anton + */ +public class IPListExporter implements Exporter { + + /* CSV delimeter character */ + static final char DELIMETER = ':'; + + private int ipFetcherIndex; + private int portsFetcherIndex; + private PrintWriter output; + + /* + * @see net.azib.ipscan.exporters.Exporter#getLabel() + */ + public String getLabel() { + return "exporter.ipList"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#getFilenameExtension() + */ + public String getFilenameExtension() { + return "lst"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setAppend(boolean) + */ + public void setAppend(boolean append) { + // no difference in this fetcher + } + + /* + * @see net.azib.ipscan.exporters.Exporter#start(java.io.OutputStream, String) + */ + public void start(OutputStream outputStream, String feederInfo) { + output = new PrintWriter(new OutputStreamWriter(outputStream)); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#end() + */ + public void end() throws IOException { + if (output.checkError()) { + throw new IOException(); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setFetchers(String[]) + */ + public void setFetchers(String[] fetcherNames) throws IOException { + ipFetcherIndex = findFetcherByLabel("fetcher.ip", fetcherNames); + portsFetcherIndex = findFetcherByLabel("fetcher.ports", fetcherNames); + } + + /** + * Searches for the needed fetcher by name. + * + * @param label + * @param fetcherNames + * @return fetcher's index + * @throws ExporterException in case fetcher is not found + */ + static int findFetcherByLabel(String label, String[] fetcherNames) { + String fetcherName = Labels.getLabel(label); + for (int i = 0; i < fetcherNames.length; i++) { + if (fetcherName.equals(fetcherNames[i])) { + return i; + } + } + throw new ExporterException("fetcher.notFound"); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#nextAdressResults(InetAddress, Object[]) + */ + public void nextAdressResults(Object[] results) throws IOException { + String address = results[ipFetcherIndex].toString(); + String portList; + try { + portList = results[portsFetcherIndex].toString(); + } + catch (Exception e) { + // ignore empty results + return; + } + + if (portList != null) { + for (PortIterator i = new PortIterator(portList); i.hasNext(); ) { + output.println(address + DELIMETER + i.next()); + } + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#clone() + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/TXTExporter.java b/ipscan/src/net/azib/ipscan/exporters/TXTExporter.java new file mode 100755 index 00000000..393404c9 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/TXTExporter.java @@ -0,0 +1,138 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.DateFormat; +import java.util.Date; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.Version; + +/** + * TXT Exporter + * + * @author anton + */ +public class TXTExporter implements Exporter { + + /** Newline character */ + static final String NEWLINE = System.getProperty("line.separator"); + + private Writer output; + private boolean isAppend; + int[] padLengths; + + /* + * @see net.azib.ipscan.exporters.Exporter#getLabel() + */ + public String getLabel() { + return "exporter.txt"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#getFilenameExtension() + */ + public String getFilenameExtension() { + return "txt"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setAppend(boolean) + */ + public void setAppend(boolean append) { + isAppend = append; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#start(java.io.OutputStream, String) + */ + public void start(OutputStream outputStream, String feederInfo) throws IOException { + output = new OutputStreamWriter(outputStream, Labels.getLabel("encoding")); + if (!isAppend) { + output.write(Labels.getLabel("exporter.txt.generated")); + println(Version.FULL_NAME); + println(Version.WEBSITE); + output.write(NEWLINE); + + String scanned = Labels.getLabel("exporter.txt.scanned"); + scanned = scanned.replaceFirst("%INFO", feederInfo); + println(scanned); + println(DateFormat.getDateTimeInstance().format(new Date())); + output.write(NEWLINE); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#end() + */ + public void end() throws IOException { + output.flush(); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setFetchers(String[]) + */ + public void setFetchers(String[] fetcherNames) throws IOException { + padLengths = new int[fetcherNames.length]; + for (int i = 0; i < fetcherNames.length; i++) { + padLengths[i] = fetcherNames[i].length() * 3; + if (!isAppend) { + output.write(pad(fetcherNames[i], padLengths[i])); + } + } + if (!isAppend) { + output.write(NEWLINE); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#nextAdressResults(InetAddress, Object[]) + */ + public void nextAdressResults(Object[] results) throws IOException { + output.write(pad(results[0], padLengths[0])); + for (int i = 1; i < results.length; i++) { + Object result = results[i]; + output.write(pad(result, padLengths[i])); + } + output.write(NEWLINE); + } + + /** + * Pads the passed string with spaces. + * @param s + * @param length the total returned length, minimum is 13 + */ + String pad(Object o, int length) { + if (length < 16) + length = 16; + + String s; + if (o == null) + s = ""; + else + s = o.toString(); + + if (s.length() >= length) { + return s; + } + return s + " ". + substring(0, length - s.length()); + } + + void println(String s) throws IOException { + output.write(s); + output.write(NEWLINE); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#clone() + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/ipscan/src/net/azib/ipscan/exporters/XMLExporter.java b/ipscan/src/net/azib/ipscan/exporters/XMLExporter.java new file mode 100755 index 00000000..c5bd9d96 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/exporters/XMLExporter.java @@ -0,0 +1,120 @@ +/** + * + */ +package net.azib.ipscan.exporters; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +import net.azib.ipscan.config.Version; + +/** + * XMLExporter + * + * @author anton + */ +public class XMLExporter implements Exporter { + + static final String ENCODING = "UTF-8"; + + private PrintWriter output; + private int ipFetcherIndex; + private String[] fetcherNames; + + /* + * @see net.azib.ipscan.exporters.Exporter#getLabel() + */ + public String getLabel() { + return "exporter.xml"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#getFilenameExtension() + */ + public String getFilenameExtension() { + return "xml"; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setAppend(boolean) + */ + public void setAppend(boolean append) { + if (append) { + throw new ExporterException("xml.noAppend"); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#start(java.io.OutputStream, java.lang.String) + */ + public void start(OutputStream outputStream, String feederInfo) throws IOException { + output = new PrintWriter(new OutputStreamWriter(outputStream, ENCODING)); + output.println(""); + output.println(""); + output.println(""); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + output.println(""); + + // this is a hack to extract feeder name from the feederInfo + // this may not work with some non-standard feeders + int colonPos = feederInfo.indexOf(':'); + String feederName = null; + if (colonPos >= 0) { + feederName = feederInfo.substring(0, colonPos); + feederInfo = feederInfo.substring(colonPos + 1); + } + output.print("\t"); + output.print(""); + output.println(""); + + output.println("\t"); + } + + /* + * @see net.azib.ipscan.exporters.Exporter#end() + */ + public void end() throws IOException { + output.println("\t"); + output.println(""); + if (output.checkError()) { + throw new IOException(); + } + } + + /* + * @see net.azib.ipscan.exporters.Exporter#setFetchers(java.lang.String[]) + */ + public void setFetchers(String[] fetcherNames) throws IOException { + ipFetcherIndex = IPListExporter.findFetcherByLabel("fetcher.ip", fetcherNames); + this.fetcherNames = fetcherNames; + } + + /* + * @see net.azib.ipscan.exporters.Exporter#nextAdressResults(java.lang.Object[]) + */ + public void nextAdressResults(Object[] results) throws IOException { + output.println("\t\t"); + + for (int i = 0; i < results.length; i++) { + if (results[i] != null) { + output.println("\t\t\t"); + } + } + + output.println("\t\t"); + } + + + /* + * @see net.azib.ipscan.exporters.Exporter#clone() + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/ipscan/src/net/azib/ipscan/feeders/Feeder.java b/ipscan/src/net/azib/ipscan/feeders/Feeder.java new file mode 100755 index 00000000..e1facd9c --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/Feeder.java @@ -0,0 +1,56 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +import java.net.InetAddress; + +/** + * Interface of a Feeder, which is used to feed scanner with IP addresses. + * Basically, classes implementing Feeder must provide an algorithm of + * sequentially generating the list of scanned IP addresses. + * + * Feeders are created with an empty constructor only once in the applications life time. + * All subsequent calls to the {@link #initialize(String[])} should reset the state of + * the Feeder and begin a new "feeding" process. + * + * @author anton + */ +public interface Feeder { + + /** + * @return label ID, representing the name of this Feeder + */ + public String getLabel(); + + /** + * Initializes the Feeder, passing Strings as initialization parameters. + * This method is used for resetting the state of the Feeder (similar to a constructor) + * in both GUI and console interfaces. + * + * @param params the meaning and the number of these Strings depend on the implementation. + * @return the number of consumed parameters + */ + public int initialize(String[] params); + + /** + * @return true in case there are more IPs left for processing + */ + public boolean hasNext(); + + /** + * @return the next IP for processing + */ + public InetAddress next(); + + /** + * @return value from 0 to 100, describing the amount of work already done + */ + public int getPercentageComplete(); + + /** + * @return information about feeder's current settings. + * Used for creation of Favorites, saving to file, etc. + */ + public String getInfo(); +} diff --git a/ipscan/src/net/azib/ipscan/feeders/FeederException.java b/ipscan/src/net/azib/ipscan/feeders/FeederException.java new file mode 100755 index 00000000..b69290b8 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/FeederException.java @@ -0,0 +1,24 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +/** + * Exception for throwing in case of problems with Feeders. + * + * @author anton + */ +public class FeederException extends IllegalArgumentException { + + static final long serialVersionUID = 746237846273847L; + + public FeederException(String message) { + super(message); + } + + public FeederException(String message, Throwable cause) { + super(message); + initCause(cause); + } + +} diff --git a/ipscan/src/net/azib/ipscan/feeders/FileFeeder.java b/ipscan/src/net/azib/ipscan/feeders/FileFeeder.java new file mode 100755 index 00000000..ba12f569 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/FileFeeder.java @@ -0,0 +1,129 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; + +import net.azib.ipscan.core.InetAddressUtils; + +/** + * Feeder, taking IP addresses from text files in any format. + * It uses regular expressions for matching of IP addresses. + * TODO: tests!!! + * + * @author anton + */ +public class FileFeeder implements Feeder { + + /** Found IP address Strings are put here */ + private List foundIPAddresses; + private Iterator foundIPAddressesIterator; + + /** Total number of found IP addresses. Equivalent to foundIPAddresses.size(), + * which is very ineffective in case of a LinkedList. + */ + private int totalAddresses; + private int currentIndex; + + /** + * @see Feeder#getLabel() + */ + public String getLabel() { + return "feeder.file"; + } + + /** + * Initializes the FileFeeder with required parameters + * @see Feeder#initialize(String[]) + * @param params 1 parameter: + * params[0] fileName + */ + public int initialize(String[] params) { + initialize(params[0]); + return 1; + } + + public void initialize(String fileName) { + try { + initialize(new FileReader(fileName)); + } + catch (FileNotFoundException e) { + throw new FeederException("file.notExists"); + } + } + + void initialize(Reader reader) { + BufferedReader fileReader = new BufferedReader(reader); + + totalAddresses = 0; + currentIndex = 0; + foundIPAddresses = new LinkedList(); + try { + String fileLine; + while ((fileLine = fileReader.readLine()) != null) { + Matcher matcher = InetAddressUtils.IP_ADDRESS_REGEX.matcher(fileLine); + while (matcher.find()) { + foundIPAddresses.add(matcher.group()); + totalAddresses++; + } + } + if (totalAddresses == 0) { + throw new FeederException("file.nothingFound"); + } + } + catch (IOException e) { + throw new FeederException("file.errorWhileReading"); + } + finally { + try { + fileReader.close(); + } + catch (IOException e) { + // ignore, what else to do? + } + } + + foundIPAddressesIterator = foundIPAddresses.iterator(); + } + + public int getPercentageComplete() { + return Math.round((float)currentIndex * 100 / totalAddresses); + } + + public boolean hasNext() { + return foundIPAddressesIterator.hasNext(); + } + + public InetAddress next() { + try { + currentIndex++; + return InetAddress.getByName((String) foundIPAddressesIterator.next()); + } + catch (UnknownHostException e) { + Logger.global.log(Level.WARNING, "malformedIP", e); + throw new FeederException("malformedIP"); + } + } + + /** + * @see net.azib.ipscan.feeders.Feeder#getInfo() + */ + public String getInfo() { + // let's return the number of found addresses + return Integer.toString(totalAddresses); + } + +} diff --git a/ipscan/src/net/azib/ipscan/feeders/RandomFeeder.java b/ipscan/src/net/azib/ipscan/feeders/RandomFeeder.java new file mode 100755 index 00000000..a08a75ad --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/RandomFeeder.java @@ -0,0 +1,111 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.SecureRandom; + +import net.azib.ipscan.core.InetAddressUtils; + +/** + * A feeder, that generates random IP addresses. + * + * @author anton + */ +public class RandomFeeder implements Feeder { + + SecureRandom random = new SecureRandom(); + InetAddress currentAddress; + + byte[] prototypeBytes; + byte[] maskBytes; + byte[] currentBytes; + + int addressCount; + int currentNumber; + + /** + * @see Feeder#getLabel() + */ + public String getLabel() { + return "feeder.random"; + } + + /** + * Initializes the RandomFeeder with required parameters + * @see Feeder#initialize(String[]) + * @param params 3 parameters: + * params[0] prototypeIP + * params[1] mask + * params[2] count + */ + public int initialize(String[] params) { + try { + initialize(params[0], params[1], Integer.parseInt(params[2])); + return 3; + } + catch (NumberFormatException e) { + throw new FeederException("random.invalidCount"); + } + } + + public void initialize(String prototypeIP, String mask, int count) { + try { + this.prototypeBytes = InetAddress.getByName(prototypeIP).getAddress(); + } + catch (UnknownHostException e) { + throw new FeederException("malformedIP"); + } + + try { + this.maskBytes = InetAddressUtils.parseNetmask(mask).getAddress(); + } + catch (UnknownHostException e) { + throw new FeederException("invalidNetmask"); + } + + if (count <= 0) { + throw new FeederException("random.invalidCount"); + } + + this.currentNumber = 0; + this.addressCount = count; + this.currentBytes = new byte[prototypeBytes.length]; + } + + public int getPercentageComplete() { + return Math.round((float)currentNumber * 100 / addressCount); + } + + public boolean hasNext() { + return currentNumber < addressCount; + } + + public InetAddress next() { + currentNumber++; + random.nextBytes(currentBytes); + try { + InetAddressUtils.maskPrototypeAddressBytes(currentBytes, maskBytes, prototypeBytes); + return InetAddress.getByAddress(currentBytes); + } + catch (UnknownHostException e) { + // this should never happen + throw new RuntimeException(e); + } + } + + /** + * @see net.azib.ipscan.feeders.Feeder#getInfo() + */ + public String getInfo() { + try { + return InetAddress.getByAddress(prototypeBytes).getHostAddress() + " / " + InetAddress.getByAddress(maskBytes).getHostAddress() + ": " + addressCount; + } + catch (UnknownHostException e) { + assert false : e; + return null; + } + } +} diff --git a/ipscan/src/net/azib/ipscan/feeders/RangeFeeder.java b/ipscan/src/net/azib/ipscan/feeders/RangeFeeder.java new file mode 100755 index 00000000..e81d8c44 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/RangeFeeder.java @@ -0,0 +1,108 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import net.azib.ipscan.core.InetAddressUtils; + +import org.savarese.vserv.tcpip.OctetConverter; + +/** + * IP Range Feeder. + * It contains the starting and ending values, which + * are then iterated sequentially. + * + * @author anton + */ +public class RangeFeeder implements Feeder { + + private InetAddress startIP; + private InetAddress endIP; + private InetAddress originalEndIP; + private InetAddress currentIP; + + double percentageComplete; + double percentageIncrement; + + /** + * @see Feeder#getLabel() + */ + public String getLabel() { + return "feeder.range"; + } + + /** + * Initializes the RangeFeeder with required parameters + * @see Feeder#initialize(String[]) + * @param params 2 IP addresses: + * params[0] - startIP + * params[1] - endIP + */ + public int initialize(String[] params) { + initialize(params[0], params[1]); + return 2; + } + + public void initialize(String startIP, String endIP) { + try { + this.startIP = this.currentIP = InetAddress.getByName(startIP); + this.endIP = this.originalEndIP = InetAddress.getByName(endIP); + } + catch (UnknownHostException e) { + throw new FeederException("malformedIP"); + } + if (InetAddressUtils.greaterThan(this.startIP, this.endIP)) { + throw new FeederException("range.greaterThan"); + } + initPercentageIncrement(); + this.endIP = InetAddressUtils.increment(this.endIP); + } + + /** + * Initalizes fields, used for computation of percentage of completion. + */ + private void initPercentageIncrement() { + // Warning: IPv4 specific code! + long rawEndIP = OctetConverter.octetsToInt(this.endIP.getAddress()); + long rawStartIP = OctetConverter.octetsToInt(this.startIP.getAddress()); + // make 32-bit usigned values + rawEndIP = rawEndIP >= 0 ? rawEndIP : rawEndIP + Integer.MAX_VALUE; + rawStartIP = rawStartIP >= 0 ? rawStartIP : rawStartIP + Integer.MAX_VALUE; + // compute 1% of the whole range + percentageIncrement = 100.0/(rawEndIP - rawStartIP + 1); + percentageComplete = 0; + } + + /** + * @see net.azib.ipscan.feeders.Feeder#hasNext() + */ + public boolean hasNext() { + // equals() is faster than greaterThan() + return !currentIP.equals(endIP); + } + + /** + * @see net.azib.ipscan.feeders.Feeder#next() + */ + public InetAddress next() { + percentageComplete += percentageIncrement; + InetAddress prevIP = this.currentIP; + this.currentIP = InetAddressUtils.increment(prevIP); + return prevIP; + } + + public int getPercentageComplete() { + return (int)Math.round(percentageComplete); + } + + /** + * @see net.azib.ipscan.feeders.Feeder#getInfo() + */ + public String getInfo() { + // let's return the range + return startIP.getHostAddress() + " - " + originalEndIP.getHostAddress(); + } +} diff --git a/ipscan/src/net/azib/ipscan/feeders/SmartTextFeeder.java b/ipscan/src/net/azib/ipscan/feeders/SmartTextFeeder.java new file mode 100755 index 00000000..b8cc6843 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/feeders/SmartTextFeeder.java @@ -0,0 +1,67 @@ +/** + * + */ +package net.azib.ipscan.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import net.azib.ipscan.core.InetAddressUtils; + +import org.savarese.vserv.tcpip.OctetConverter; + +/** + * Smart text feeder for advenced users. + * + * TODO: implement SmartTextFeeder to accept text, e.g. + * 127.0.0.1-255 + * 127.0-10.13-15.1 + * 127.0.0.1/24 + * + * Warning: IPv4-specific! + * + * @author anton + */ +public class SmartTextFeeder implements Feeder { + + private String netmask; + + public String getLabel() { + return null; + } + + public int initialize(String[] params) { + return 0; + } + + public void initialize(String text) { + // remove all whitespace + text = text.replaceAll("\\w+", ""); + + // extract netmask + int slashPos = text.indexOf('/'); + if (slashPos >= 0) { + netmask = text.substring(slashPos+1); + text = text.substring(0, slashPos); + } + + String[] tokens = text.split("\\."); + // TODO: use port list parsing code here + } + + public boolean hasNext() { + return false; + } + + public InetAddress next() { + return null; + } + + public int getPercentageComplete() { + return 0; + } + + public String getInfo() { + return null; + } +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/CommentFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/CommentFetcher.java new file mode 100755 index 00000000..27769716 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/CommentFetcher.java @@ -0,0 +1,39 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.ScanningSubject; + +/** + * A fetcher for displaying of user-defined comments about every IP address. + * + * TODO: implement CommentFetcher + * TODO: make an editor for comments + * + * @author anton + */ +public class CommentFetcher implements Fetcher { + + /** + * @see net.azib.ipscan.fetchers.Fetcher#getLabel() + */ + public String getLabel() { + return "fetcher.ip"; + } + + /** + * @see net.azib.ipscan.fetchers.Fetcher#scan(net.azib.ipscan.core.ScanningSubject) + */ + public Object scan(ScanningSubject subject) { + return "a dummy comment!!!"; + } + + public void init() { + } + + public void cleanup() { + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/Fetcher.java b/ipscan/src/net/azib/ipscan/fetchers/Fetcher.java new file mode 100755 index 00000000..919e906e --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/Fetcher.java @@ -0,0 +1,50 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.NotAvailableValue; +import net.azib.ipscan.core.NotScannedValue; +import net.azib.ipscan.core.ScanningSubject; + +/** + * Interface of all IP Fetchers. + * + * Fetcher is responsible for gathering a certain type of + * information about the provided scanning subject + * (in GUI terms, Fetcher is a column in the results list). + * + * Fetchers do the actual information fetching about each + * scanned IP address. + * + * Instances of this classes are shared among all the threads, + * so implementations must be thread safe and stateless. + * + * @author anton + */ +public interface Fetcher extends Cloneable { + + /** + * @return label ID, representing the name of this fetcher + */ + public String getLabel(); + + /** + * Does the actual fetching. + * @param subject the scanning subject, containing an IP address + * @return the fetched data (a String in most cases), null in case of any error. + * Special values may also be returned, such as {@link NotAvailableValue} or {@link NotScannedValue} + */ + public Object scan(ScanningSubject subject); + + /** + * Called before scanning has started to do any intialization stuff + */ + public void init(); + + /** + * Called after the scanning has been completed to do any cleanup needed + */ + public void cleanup(); +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/FetcherException.java b/ipscan/src/net/azib/ipscan/fetchers/FetcherException.java new file mode 100755 index 00000000..6c83fc2e --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/FetcherException.java @@ -0,0 +1,19 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +/** + * FetcherException + * + * @author anton + */ +public class FetcherException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public FetcherException(Throwable cause) { + super(cause); + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistry.java b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistry.java new file mode 100755 index 00000000..4560c787 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistry.java @@ -0,0 +1,46 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +import java.util.Collection; + +/** + * FetcherRegistry + * + * @author anton + */ +public interface FetcherRegistry { + + /** + * @return a List of all registered Fetchers + */ + public Collection getRegisteredFetchers(); + + /** + * @return a List of selected Fetchers only + */ + public Collection getSelectedFetchers(); + + /** + * Searches for selected fetcher with the given label + * @param label + * @return the index, if found, or -1 + */ + public int getSelectedFetcherIndex(String label); + + /** + * Updates the list, retaining only items that are passed in the array. + * The order of elements will be the same as in the array. + * + * @param names + */ + public void updateSelectedFetchers(String[] names); + + /** + * Adds a listener to observe FetcherRegistry events, like modification of selected fetchers. + * @param listener + */ + public void addListener(FetcherRegistryUpdateListener listener); + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryImpl.java b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryImpl.java new file mode 100755 index 00000000..e1d5bcdd --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryImpl.java @@ -0,0 +1,80 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Fetcher Registry singleton class. + * Actually, it registers both plugins and builtins. + * + * @author anton + */ +public class FetcherRegistryImpl implements FetcherRegistry { + + /** All available Fetcher implementations, List of Fetcher instances */ + private List registeredFetchers; + /** Selected for scanning Fetcher implementations, keys are fetcher labels, values are Fetcher instances */ + private Map selectedFetchers; + /** A collection of update listeners - observers of FetcherRegistry */ + private List updateListeners = new ArrayList(); + + public FetcherRegistryImpl(Fetcher[] registeredFetchers) { + this.registeredFetchers = Arrays.asList(registeredFetchers); + this.registeredFetchers = Collections.unmodifiableList(this.registeredFetchers); + + // TODO: this should be loaded from config as well as reasonable defaults should be made + this.selectedFetchers = new LinkedHashMap(); + for (Iterator i = this.registeredFetchers.iterator(); i.hasNext();) { + Fetcher fetcher = (Fetcher) i.next(); + this.selectedFetchers.put(fetcher.getLabel(), fetcher); + } + } + + public void addListener(FetcherRegistryUpdateListener listener) { + updateListeners.add(listener); + } + + public Collection getRegisteredFetchers() { + return registeredFetchers; + } + + public Collection getSelectedFetchers() { + return selectedFetchers.values(); + } + + public int getSelectedFetcherIndex(String label) { + int index = -1; + for (Iterator i = selectedFetchers.values().iterator(); i.hasNext();) { + if (((Fetcher)i.next()).getLabel().equals(label)) + break; + index++; + + } + return index; + } + + public void updateSelectedFetchers(String[] labels) { + // rebuild the map (to recreate the new order of elements) + Map newList = new LinkedHashMap(); + for (int i = 0; i < labels.length; i++) { + newList.put(labels[i], selectedFetchers.get(labels[i])); + } + selectedFetchers = newList; + + // invorm observers + for (Iterator i = updateListeners.iterator(); i.hasNext();) { + FetcherRegistryUpdateListener listener = (FetcherRegistryUpdateListener) i.next(); + listener.handleUpdateOfSelectedFetchers(this); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryUpdateListener.java b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryUpdateListener.java new file mode 100755 index 00000000..03e08c7e --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/FetcherRegistryUpdateListener.java @@ -0,0 +1,20 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +/** + * FetcherRegistryUpdateListener. + * Implement this interface if you need to react to FetcherRegistry updates. + * + * @author Anton Keks + */ +public interface FetcherRegistryUpdateListener { + + /** + * This method is called when the list of selected Fetchers was changed. + * @param fetcherRegistry + */ + void handleUpdateOfSelectedFetchers(FetcherRegistry fetcherRegistry); + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/FilteredPortsFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/FilteredPortsFetcher.java new file mode 100755 index 00000000..24ec3fdf --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/FilteredPortsFetcher.java @@ -0,0 +1,27 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +import java.util.Set; + +import net.azib.ipscan.core.ScanningSubject; + +/** + * FilteredPortsFetcher uses the scanning results of PortsFetcher to display filtered ports. + * + * @author anton + */ +public class FilteredPortsFetcher extends PortsFetcher { + + public String getLabel() { + return "fetcher.ports.filtered"; + } + + public Object scan(ScanningSubject subject) { + scanPorts(subject); + Set filteredPorts = getFilteredPorts(subject); + return filteredPorts.size() > 0 ? portListToRange(filteredPorts, displayAsRanges) : null; + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/HostnameFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/HostnameFetcher.java new file mode 100755 index 00000000..fc3dd307 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/HostnameFetcher.java @@ -0,0 +1,38 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.ScanningSubject; + +/** + * HostnameFetcher retrieves hostnames of IP addresses by reverse DNS lookups. + * + * @author anton + */ +public class HostnameFetcher implements Fetcher { + + /** + * @see net.azib.ipscan.fetchers.Fetcher#getLabel() + */ + public String getLabel() { + return "fetcher.hostname"; + } + + /** + * @see net.azib.ipscan.fetchers.Fetcher#scan(net.azib.ipscan.core.ScanningSubject) + */ + public Object scan(ScanningSubject subject) { + String hostname = subject.getIPAddress().getCanonicalHostName(); + // return the returned hostname only if it is not the same as the IP address (this is how the above method works) + return subject.getIPAddress().getHostAddress().equals(hostname) ? null : hostname; + } + + public void init() { + } + + public void cleanup() { + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/IPFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/IPFetcher.java new file mode 100755 index 00000000..6dc4a909 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/IPFetcher.java @@ -0,0 +1,37 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.ScanningSubject; + +/** + * Dummy fetcher, which is able to return the textual representation + * of the passed IP address. + * + * @author anton + */ +public class IPFetcher implements Fetcher { + + /** + * @see net.azib.ipscan.fetchers.Fetcher#getLabel() + */ + public String getLabel() { + return "fetcher.ip"; + } + + /** + * @see net.azib.ipscan.fetchers.Fetcher#scan(net.azib.ipscan.core.ScanningSubject) + */ + public Object scan(ScanningSubject subject) { + return subject.getIPAddress().getHostAddress(); + } + + public void init() { + } + + public void cleanup() { + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/PacketLossFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/PacketLossFetcher.java new file mode 100755 index 00000000..e17d53fc --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/PacketLossFetcher.java @@ -0,0 +1,19 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.net.PingerRegistry; + +/** + * TODO PacketLossFetcher + * + * @author anton + */ +public class PacketLossFetcher extends PingFetcher { + + public PacketLossFetcher(PingerRegistry pingerRegistry) { + super(pingerRegistry); + } + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/PingFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/PingFetcher.java new file mode 100755 index 00000000..11416850 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/PingFetcher.java @@ -0,0 +1,101 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.core.IntegerWithUnit; +import net.azib.ipscan.core.ScanningSubject; +import net.azib.ipscan.core.net.PingResult; +import net.azib.ipscan.core.net.Pinger; +import net.azib.ipscan.core.net.PingerRegistry; + +/** + * PingFetcher is able to ping IP addresses. + * It returns the average round trip time of all pings sent. + * + * @author anton + */ +public class PingFetcher implements Fetcher { + + public static final String PARAMETER_PINGER = "pinger"; + + /** The shared pinger - this one must be static, because PingTTLFetcher will use it as well */ + private static Pinger pinger; + + /** The registry used for creation of Pinger instances */ + private PingerRegistry pingerRegistry; + + public PingFetcher(PingerRegistry pingerRegistry) { + this.pingerRegistry = pingerRegistry; + } + + public String getLabel() { + return "fetcher.ping"; + } + + protected PingResult executePing(ScanningSubject subject) { + + PingResult result = null; + + if (subject.hasParameter(PARAMETER_PINGER)) { + result = (PingResult) subject.getParameter(PARAMETER_PINGER); + } + else { + try { + result = pinger.ping(subject.getIPAddress(), Config.getGlobal().pingCount); + } + catch (IOException e) { + // if this is not a timeout + Logger.global.log(Level.WARNING, "Pinging failed", e); + // return an empty ping result + result = new PingResult(subject.getIPAddress()); + } + // remember the result for other fetchers to use + subject.setParameter(PARAMETER_PINGER, result); + } + return result; + } + + public Object scan(ScanningSubject subject) { + PingResult result = executePing(subject); + subject.setResultType(result.isAlive() ? ScanningSubject.RESULT_TYPE_ALIVE : ScanningSubject.RESULT_TYPE_DEAD); + + if (!result.isAlive() && !Config.getGlobal().scanDeadHosts) { + // the host is dead, we are not going to continue... + subject.abortScanning(); + } + + return result.isAlive() ? new IntegerWithUnit(result.getAverageTime(), "fetcher.value.ms") : null; + } + + public void init() { + try { + if (pinger == null) { + pinger = pingerRegistry.createPinger(Config.getGlobal().selectedPinger, Config.getGlobal().pingTimeout); + } + } + catch (Exception e) { + throw new FetcherException(e); + } + } + + public void cleanup() { + try { + if (pinger != null) { + pinger.close(); + } + } + catch (IOException e) { + throw new FetcherException(e); + } + pinger = null; + } + + +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/PingTTLFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/PingTTLFetcher.java new file mode 100755 index 00000000..41ac5307 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/PingTTLFetcher.java @@ -0,0 +1,32 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + */ +package net.azib.ipscan.fetchers; + +import net.azib.ipscan.core.ScanningSubject; +import net.azib.ipscan.core.net.PingResult; +import net.azib.ipscan.core.net.PingerRegistry; + +/** + * PingTTLFetcher shares pinging results with PingFetcher + * and returns the TTL field of the last received packet. + * + * @author anton + */ +public class PingTTLFetcher extends PingFetcher { + + public PingTTLFetcher(PingerRegistry pingerRegistry) { + super(pingerRegistry); + } + + public String getLabel() { + return "fetcher.ping.ttl"; + } + + public Object scan(ScanningSubject subject) { + PingResult result = executePing(subject); + subject.setResultType(result.isAlive() ? ScanningSubject.RESULT_TYPE_ALIVE : ScanningSubject.RESULT_TYPE_DEAD); + return result.isAlive() && result.getTTL() > 0 ? new Integer(result.getTTL()) : null; + } +} diff --git a/ipscan/src/net/azib/ipscan/fetchers/PortsFetcher.java b/ipscan/src/net/azib/ipscan/fetchers/PortsFetcher.java new file mode 100755 index 00000000..1e6bbc9b --- /dev/null +++ b/ipscan/src/net/azib/ipscan/fetchers/PortsFetcher.java @@ -0,0 +1,178 @@ +/** + * + */ +package net.azib.ipscan.fetchers; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.core.PortIterator; +import net.azib.ipscan.core.ScanningSubject; +import net.azib.ipscan.core.net.PingResult; + +/** + * PortsFetcher scans TCP ports. + * Port list is obtained using the {@link net.azib.ipscan.core.PortIterator}. + * + * TODO: return a specialized "list" object instead of a String + * + * @author anton + */ +public class PortsFetcher implements Fetcher { + + private static final String PARAMETER_OPEN_PORTS = "openPorts"; + private static final String PARAMETER_FILTERED_PORTS = "filteredPorts"; + + // initialize options for this scan + private int timeout = Config.getGlobal().portTimeout; + private boolean adaptTimeout = Config.getGlobal().adaptPortTimeout; + private PortIterator portIteratorPrototype = new PortIterator(Config.getGlobal().portString); + protected boolean displayAsRanges = true; // TODO: make configurable + + /** + * @see net.azib.ipscan.fetchers.Fetcher#getLabel() + */ + public String getLabel() { + return "fetcher.ports"; + } + + /** + * This method does the actual port scanning. + * It then remembers the results for other extending fetchers to use, like FilteredPortsFetcher. + * @param subject + */ + protected void scanPorts(ScanningSubject subject) { + Set openPorts = getOpenPorts(subject); + + if (openPorts == null) { + // no results are available yet, let's proceed with the scanning + openPorts = new TreeSet(); + Set filteredPorts = new TreeSet(); + subject.setParameter(PARAMETER_OPEN_PORTS, openPorts); + subject.setParameter(PARAMETER_FILTERED_PORTS, filteredPorts); + + int adaptedTimeout = timeout; + + // now try to adapt timeout if it is enabled and pinging results are availbale + PingResult pingResult = (PingResult) subject.getParameter(PingFetcher.PARAMETER_PINGER); + if (adaptTimeout && pingResult.isAlive()) { + // TODO: use longest time istead of the average one for adapting + adaptedTimeout = Math.min(Math.max(pingResult.getAverageTime() * 4, 30), timeout); + } + + Socket socket = null; + // clone port iterator for performance instead of creating for every thread + for (PortIterator i = portIteratorPrototype.copy(); i.hasNext(); ) { + // TODO: UDP ports? + // TODO: reuse sockets? + socket = new Socket(); + int port = i.next(); + try { + socket.connect(new InetSocketAddress(subject.getIPAddress(), port), adaptedTimeout); + if (socket.isConnected()) { + openPorts.add(new Integer(port)); + } + } + catch (SocketTimeoutException e) { + filteredPorts.add(new Integer(port)); + } + catch (IOException e) { + // connection refused + assert e instanceof ConnectException : e; + } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) {} + } + } + } + } + } + + /** + * @param subject + * @return + */ + protected Set getFilteredPorts(ScanningSubject subject) { + return (Set) subject.getParameter(PARAMETER_FILTERED_PORTS); + } + + /** + * @param subject + * @return + */ + protected Set getOpenPorts(ScanningSubject subject) { + return (Set) subject.getParameter(PARAMETER_OPEN_PORTS); + } + + /** + * Utility method to convert the resulting port List to String. + * @param portList source List of Integers + * @return a String + */ + protected static String portListToRange(Collection portList, boolean asRanges) { + StringBuffer sb = new StringBuffer(); + + Iterator i = portList.iterator(); + Integer prevPort = new Integer(Integer.MAX_VALUE); + boolean isRange = false; + + if (i.hasNext()) { + prevPort = (Integer) i.next(); + sb.append(prevPort); + } + + while (i.hasNext()) { + Integer port = (Integer) i.next(); + + if (asRanges && prevPort.intValue() + 1 == port.intValue()) { + isRange = true; + } + else { + if (isRange) { + sb.append('-').append(prevPort); + isRange = false; + } + sb.append(',').append(port); + } + prevPort = port; + } + + if (isRange) { + sb.append('-').append(prevPort); + } + + return sb.toString(); + } + + /* + * @see net.azib.ipscan.fetchers.Fetcher#scan(net.azib.ipscan.core.ScanningSubject) + */ + public Object scan(ScanningSubject subject) { + scanPorts(subject); + Set openPorts = getOpenPorts(subject); + boolean portsFound = openPorts.size() > 0; + if (portsFound) { + subject.setResultType(ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO); + } + return portsFound ? portListToRange(openPorts, displayAsRanges) : null; + } + + public void init() { + } + + public void cleanup() { + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/AboutWindow.java b/ipscan/src/net/azib/ipscan/gui/AboutWindow.java new file mode 100755 index 00000000..01a9c415 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/AboutWindow.java @@ -0,0 +1,96 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.Version; +import net.azib.ipscan.gui.actions.HelpActions; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * About Window + * + * @author anton + */ +public class AboutWindow extends AbstractModalDialog { + + public AboutWindow() { + createShell(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + + shell.setText(Labels.getLabel("title.about")); + shell.setSize(new Point(400, 363)); + + Label iconLabel = new Label(shell, SWT.ICON); + iconLabel.setBounds(10, 10, 0, 0); + + if (parent != null) { + iconLabel.setImage(parent.getImage()); + shell.setImage(parent.getImage()); + } + iconLabel.pack(); + + // TODO: make clicking on links work + Link textLabel = new Link(shell, SWT.NONE); + String text = Labels.getLabel("text.about"); + text = text.replaceAll("%NAME", Version.NAME); + text = text.replaceAll("%VERSION", Version.VERSION); + text = text.replaceAll("%COPYLEFT", Version.COPYLEFT); + text = text.replaceAll("%WEBSITE", Version.WEBSITE); + text = text.replaceAll("%MAILTO", Version.MAILTO); + textLabel.setText(text); + textLabel.setBounds(60, 10, 0, 0); + textLabel.addListener(SWT.Selection, new HelpActions.Website()); + textLabel.pack(); + + Text licenseText = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.WRAP); + licenseText.setBounds(60, 140, 320, 160); + licenseText.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + licenseText.setText("Licensed under the GNU General Public License Version 2\n\n" + + Version.NAME + " is free software; you can redistribute it and/or " + + "modify it under the terms of the GNU General Public License " + + "as published by the Free Software Foundation; either version 2 " + + "of the License, or (at your option) any later version.\n\n" + + Version.NAME + " is distributed in the hope that it will be useful, " + + "but WITHOUT ANY WARRANTY; without even the implied warranty of " + + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " + + "GNU General Public License for more details.\n\n" + + "You should have received a copy of the GNU General Public License " + + "along with this program; if not, write to the Free Software " + + "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA " + + "02110-1301, USA, or visit http://www.fsf.org/"); + + Button button = new Button(shell, SWT.NONE); + button.setText(Labels.getLabel("button.close")); + button.setBounds(170, 305, 80, 25); + button.setFocus(); + button.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + shell.close(); + shell.dispose(); + } + }); + + shell.setDefaultButton(button); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/AbstractModalDialog.java b/ipscan/src/net/azib/ipscan/gui/AbstractModalDialog.java new file mode 100755 index 00000000..a2992d5f --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/AbstractModalDialog.java @@ -0,0 +1,93 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; + +/** + * This is the base of a modal dialog window + * + * @author anton + */ +public abstract class AbstractModalDialog { + + protected Shell shell = null; + + public void open() { + shell.open(); + Display display = Display.getCurrent(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + shell.dispose(); + } + + // common listeners follow + + protected static class UpButtonListener implements Listener { + + private List list; + + public UpButtonListener(List list) { + this.list = list; + } + + public void handleEvent(Event event) { + if (list.isSelected(0)) { + // do not move anything if the first item is selected + return; + } + + int[] selectedItems = list.getSelectionIndices(); + for (int i = 0; i < selectedItems.length; i++) { + // here, index is always > 0 + int index = selectedItems[i]; + + list.deselect(index); + String oldItem = list.getItem(index - 1); + list.setItem(index - 1, list.getItem(index)); + list.setItem(index, oldItem); + list.select(index - 1); + } + + list.setTopIndex(selectedItems[0] - 2); + } + } + + protected static class DownButtonListener implements Listener { + + private List list; + + public DownButtonListener(List list) { + this.list = list; + } + + public void handleEvent(Event event) { + if (list.isSelected(list.getItemCount() - 1)) { + // do not move anything if the last items is selected + return; + } + + int[] selectedItems = list.getSelectionIndices(); + for (int i = selectedItems.length - 1; i >= 0; i--) { + // here, index is always < getItemCount() + int index = selectedItems[i]; + + list.deselect(index); + String oldItem = list.getItem(index + 1); + list.setItem(index + 1, list.getItem(index)); + list.setItem(index, oldItem); + list.select(index + 1); + } + + list.setTopIndex(selectedItems[0]); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/DetailsWindow.java b/ipscan/src/net/azib/ipscan/gui/DetailsWindow.java new file mode 100755 index 00000000..26ee2003 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/DetailsWindow.java @@ -0,0 +1,59 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * The "Show IP Details" Window + * + * @author anton + */ +public class DetailsWindow extends AbstractModalDialog { + + private ResultTable resultTable; + + public DetailsWindow(ResultTable resultTable) { + this.resultTable = resultTable; + createShell(resultTable.getShell()); + } + + /** + * This method initializes shell + */ + private void createShell(Shell parent) { + shell = new Shell(parent, SWT.TOOL | SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); + shell.setText(Labels.getLabel("title.details")); + shell.setSize(new Point(300, 300)); + shell.setImage(parent.getImage()); + FillLayout fillLayout = new FillLayout(); + fillLayout.spacing = 3; + fillLayout.marginHeight = 3; + fillLayout.marginWidth = 3; + shell.setLayout(fillLayout); + + Text detailsText = new Text(shell, SWT.BORDER | SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL); + detailsText.setText(resultTable.getIPDetails()); + detailsText.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + detailsText.setTabs(32); + + detailsText.addListener(SWT.Traverse, new Listener() { + public void handleEvent(Event e) { + if (e.detail == SWT.TRAVERSE_RETURN) { + shell.close(); + shell.dispose(); + } + } + }); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/EditFavoritesDialog.java b/ipscan/src/net/azib/ipscan/gui/EditFavoritesDialog.java new file mode 100755 index 00000000..fa7d8566 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/EditFavoritesDialog.java @@ -0,0 +1,108 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.util.Iterator; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.NamedListConfig; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; + +/** + * EditFavoritesDialog + * + * @author anton + */ +public class EditFavoritesDialog extends AbstractModalDialog { + + private List favoritesList; + + public EditFavoritesDialog() { + createShell(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + + shell.setText(Labels.getLabel("title.favorite.edit")); + shell.setSize(new Point(405, 297)); + shell.setLayout(null); + + Label messageLabel = new Label(shell, SWT.NONE); + messageLabel.setText(Labels.getLabel("text.favorite.edit")); + messageLabel.setBounds(new Rectangle(10, 10, 282, 14)); + + favoritesList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL); + favoritesList.setBounds(new Rectangle(10, 30, 330, 200)); + for (Iterator i = Config.getFavoritesConfig().iterateNames(); i.hasNext();) { + String name = (String) i.next(); + favoritesList.add(name); + } + + Button upButton = new Button(shell, SWT.NONE); + upButton.setText(Labels.getLabel("button.up")); + upButton.setBounds(new Rectangle(350, 30, 40, 25)); + upButton.addListener(SWT.Selection, new UpButtonListener(favoritesList)); + + Button downButton = new Button(shell, SWT.NONE); + downButton.setText(Labels.getLabel("button.down")); + downButton.setBounds(new Rectangle(350, 60, 40, 25)); + downButton.addListener(SWT.Selection, new DownButtonListener(favoritesList)); + + Button deleteButton = new Button(shell, SWT.NONE); + deleteButton.setText(Labels.getLabel("button.delete")); + deleteButton.setBounds(new Rectangle(350, 105, 40, 25)); + deleteButton.addListener(SWT.Selection, new DeleteButtonListener()); + + Button okButton = new Button(shell, SWT.NONE); + okButton.setText(Labels.getLabel("button.OK")); + okButton.setBounds(new Rectangle(180, 238, 75, 25)); + shell.setDefaultButton(okButton); + + Button cancelButton = new Button(shell, SWT.NONE); + cancelButton.setText(Labels.getLabel("button.cancel")); + cancelButton.setBounds(new Rectangle(265, 238, 75, 25)); + + okButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + saveFavorites(); + shell.close(); + } + }); + cancelButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + shell.close(); + } + }); + } + + private void saveFavorites() { + NamedListConfig favoritesConfig = Config.getFavoritesConfig(); + favoritesConfig.update(favoritesList.getItems()); + favoritesConfig.store(); + } + + private class DeleteButtonListener implements Listener { + public void handleEvent(Event event) { + favoritesList.remove(favoritesList.getSelectionIndices()); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/EditOpenersDialog.java b/ipscan/src/net/azib/ipscan/gui/EditOpenersDialog.java new file mode 100755 index 00000000..dafc6a50 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/EditOpenersDialog.java @@ -0,0 +1,253 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.io.File; +import java.util.Iterator; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.OpenersConfig; +import net.azib.ipscan.config.OpenersConfig.Opener; +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * EditOpenersDialog + * + * @author anton + */ +public class EditOpenersDialog extends AbstractModalDialog { + + private FetcherRegistry fetcherRegistry; + private List openersList; + private Group editFieldsGroup; + private Text openerNameText; + private Text openerStringText; + private Text workingDirText; + private Button isInTerminalCheckbox; + private int currentSelectionIndex; + + public EditOpenersDialog(FetcherRegistry fetcherRegistry) { + this.fetcherRegistry = fetcherRegistry; + createShell(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + + shell.setText(Labels.getLabel("title.openers.edit")); + shell.setSize(new Point(405, 307)); + shell.setLayout(null); + + Label messageLabel = new Label(shell, SWT.NONE); + messageLabel.setText(Labels.getLabel("text.openers.edit")); + messageLabel.setBounds(new Rectangle(10, 10, 282, 14)); + + openersList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL); + openersList.setBounds(new Rectangle(10, 30, 135, 200)); + for (Iterator i = Config.getOpenersConfig().iterateNames(); i.hasNext();) { + String name = (String) i.next(); + openersList.add(name); + } + openersList.addListener(SWT.Selection, new ItemSelectListener()); + + Button upButton = new Button(shell, SWT.NONE); + upButton.setText(Labels.getLabel("button.up")); + upButton.setBounds(new Rectangle(150, 30, 40, 25)); + upButton.addListener(SWT.Selection, new UpButtonListener(openersList)); + + Button downButton = new Button(shell, SWT.NONE); + downButton.setText(Labels.getLabel("button.down")); + downButton.setBounds(new Rectangle(150, 60, 40, 25)); + downButton.addListener(SWT.Selection, new DownButtonListener(openersList)); + + Button addButton = new Button(shell, SWT.NONE); + addButton.setText(Labels.getLabel("button.add")); + addButton.setBounds(new Rectangle(150, 105, 40, 25)); + addButton.addListener(SWT.Selection, new AddButtonListener()); + + Button deleteButton = new Button(shell, SWT.NONE); + deleteButton.setText(Labels.getLabel("button.delete")); + deleteButton.setBounds(new Rectangle(150, 135, 40, 25)); + deleteButton.addListener(SWT.Selection, new DeleteButtonListener()); + + Button closeButton = new Button(shell, SWT.NONE); + closeButton.setText(Labels.getLabel("button.close")); + closeButton.setBounds(new Rectangle(315, 245, 75, 25)); + + editFieldsGroup = new Group(shell, SWT.NONE); + editFieldsGroup.setBounds(205, 30, 185, 200); + RowLayout rowLayout = new RowLayout(SWT.VERTICAL); + rowLayout.fill = true; + rowLayout.justify = true; + rowLayout.marginTop = 13; + editFieldsGroup.setLayout(rowLayout); + + Label openerNameLabel = new Label(editFieldsGroup, SWT.NONE); + openerNameLabel.setText(Labels.getLabel("text.openers.name")); + openerNameLabel.setSize(SWT.DEFAULT, 18); + openerNameText = new Text(editFieldsGroup, SWT.BORDER); + openerNameText.setSize(SWT.DEFAULT, 22); + openerNameText.addListener(SWT.KeyUp, new OpenerNameChange()); + + isInTerminalCheckbox = new Button(editFieldsGroup, SWT.CHECK); + isInTerminalCheckbox.setText(Labels.getLabel("text.openers.inTerminal")); + isInTerminalCheckbox.setSize(SWT.DEFAULT, 18); + + Label openerStringLabel = new Label(editFieldsGroup, SWT.NONE); + openerStringLabel.setText(Labels.getLabel("text.openers.string")); + openerStringLabel.setSize(SWT.DEFAULT, 18); + openerStringText = new Text(editFieldsGroup, SWT.BORDER); + openerStringText.setSize(SWT.DEFAULT, 22); + + Button hintButton = new Button(editFieldsGroup, SWT.NONE); + hintButton.setText(Labels.getLabel("text.openers.hint")); + hintButton.addListener(SWT.Selection, new HintButtonListener()); + + Label openerDirLabel = new Label(editFieldsGroup, SWT.NONE); + openerDirLabel.setText(Labels.getLabel("text.openers.directory")); + openerDirLabel.setSize(SWT.DEFAULT, 18); + workingDirText = new Text(editFieldsGroup, SWT.BORDER); + workingDirText.setSize(SWT.DEFAULT, 22); + + editFieldsGroup.layout(); + + openersList.select(0); + loadFieldsForSelection(); + + shell.addListener(SWT.Close, new Listener() { + public void handleEvent(Event e) { + saveOpeners(); + } + }); + closeButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + shell.close(); + } + }); + shell.setDefaultButton(closeButton); + } + + private void saveOpeners() { + // save any possible changes in text boxes + saveCurrentFields(); + + // now save everything else (order, etc) + OpenersConfig openersConfig = Config.getOpenersConfig(); + openersConfig.update(openersList.getItems()); + openersConfig.store(); + } + + private void saveCurrentFields() { + String openerName = openerNameText.getText(); + if (openerName.length() == 0) + return; + + File workingDir = workingDirText.getText().length() > 0 ? new File(workingDirText.getText()) : null; + Config.getOpenersConfig().add(openerName, new OpenersConfig.Opener(openerStringText.getText(), isInTerminalCheckbox.getSelection(), workingDir)); + openersList.setItem(currentSelectionIndex, openerName); + } + + private void loadFieldsForSelection() { + currentSelectionIndex = openersList.getSelectionIndex(); + String openerName = openersList.getItem(currentSelectionIndex); + editFieldsGroup.setText(openerName); + Opener opener = Config.getOpenersConfig().getOpener(openerName); + openerNameText.setText(openerName); + openerStringText.setText(opener.execString); + workingDirText.setText(opener.workingDir != null ? opener.workingDir.toString() : ""); + isInTerminalCheckbox.setSelection(opener.inTerminal); + } + + private class HintButtonListener implements Listener { + + public void handleEvent(Event event) { + // compose the message with all available fetchers + StringBuffer message = new StringBuffer(Labels.getLabel("text.openers.hintText")); + for (Iterator i = fetcherRegistry.getSelectedFetchers().iterator(); i.hasNext(); ) { + String fetcherLabel = ((Fetcher)i.next()).getLabel(); + message.append("${").append(fetcherLabel).append("} - ").append(Labels.getLabel(fetcherLabel)).append('\n'); + } + + MessageBox mb = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK); + mb.setText(Labels.getLabel("title.openers.edit")); + mb.setMessage(message.toString()); + mb.open(); + } + } + + private class DeleteButtonListener implements Listener { + + public void handleEvent(Event event) { + int firstIndex = openersList.getSelectionIndex(); + openersList.remove(openersList.getSelectionIndices()); + openersList.setSelection(firstIndex); + loadFieldsForSelection(); + } + } + + private class AddButtonListener implements Listener { + + public void handleEvent(Event event) { + saveCurrentFields(); + + currentSelectionIndex = openersList.getSelectionIndex(); + if (currentSelectionIndex < 0) { + currentSelectionIndex = openersList.getItemCount(); + } + String newName = Labels.getLabel("text.openers.new"); + openersList.add(newName, currentSelectionIndex); + openersList.setSelection(currentSelectionIndex); + + // reset fields + editFieldsGroup.setText(newName); + openerNameText.setText(newName); + openerStringText.setText("${fetcher.ip}"); + workingDirText.setText(""); + isInTerminalCheckbox.setSelection(false); + + openerNameText.forceFocus(); + openerNameText.setSelection(0, newName.length()); + } + } + + private class ItemSelectListener implements Listener { + + public void handleEvent(Event event) { + saveCurrentFields(); + loadFieldsForSelection(); + } + } + + private class OpenerNameChange implements Listener { + + public void handleEvent(Event event) { + String name = openerNameText.getText(); + editFieldsGroup.setText(name); + openersList.setItem(currentSelectionIndex, name); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/GettingStartedWindow.java b/ipscan/src/net/azib/ipscan/gui/GettingStartedWindow.java new file mode 100755 index 00000000..77f428b6 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/GettingStartedWindow.java @@ -0,0 +1,100 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** + * About Window + * + * @author anton + */ +public class GettingStartedWindow extends AbstractModalDialog { + + private int activePage = 1; + private Text gettingStartedText; + private Button closeButton; + private Button nextButton; + + public GettingStartedWindow() { + createShell(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + + shell.setText(Labels.getLabel("title.gettingStarted")); + shell.setSize(new Point(400, 240)); + + Label iconLabel = new Label(shell, SWT.ICON); + iconLabel.setBounds(10, 10, 0, 0); + + if (parent != null) { + iconLabel.setImage(parent.getImage()); + shell.setImage(parent.getImage()); + } + iconLabel.pack(); + + gettingStartedText = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.WRAP); + gettingStartedText.setBounds(60, 10, 320, 160); + gettingStartedText.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + + closeButton = new Button(shell, SWT.NONE); + closeButton.setText(Labels.getLabel("button.close")); + closeButton.setBounds(110, 180, 80, 25); + closeButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + shell.close(); + shell.dispose(); + } + }); + + nextButton = new Button(shell, SWT.NONE); + nextButton.setText(Labels.getLabel("button.next")); + nextButton.setBounds(210, 180, 80, 25); + nextButton.setFocus(); + nextButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + activePage++; + displayActivePage(); + } + }); + + shell.setDefaultButton(nextButton); + + displayActivePage(); + } + + private void displayActivePage() { + String text = Labels.getLabel("text.gettingStarted" + activePage); + gettingStartedText.setText(text); + + // check for the next one + try { + Labels.getLabel("text.gettingStarted" + (activePage+1)); + } + catch (Exception e) { + // no label, disable the next button + nextButton.setEnabled(false); + shell.setDefaultButton(closeButton); + closeButton.setFocus(); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/InputDialog.java b/ipscan/src/net/azib/ipscan/gui/InputDialog.java new file mode 100755 index 00000000..5c36de0a --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/InputDialog.java @@ -0,0 +1,91 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; + +/** + * Customizable InputDialog + * + * @author anton + */ +public class InputDialog extends AbstractModalDialog { + + private Label messageLabel = null; + private Text text = null; + private Button okButton = null; + private Button cancelButton = null; + + private String message; + + public InputDialog(String title, String message) { + createShell(); + shell.setText(title); + messageLabel.setText(message); + messageLabel.pack(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + shell.setSize(new Point(300, 112)); + shell.setLayout(null); + messageLabel = new Label(shell, SWT.NONE); + messageLabel.setBounds(new Rectangle(3, 5, 282, 14)); + text = new Text(shell, SWT.BORDER); + text.setBounds(new Rectangle(5, 24, 281, 24)); + okButton = new Button(shell, SWT.NONE); + okButton.setLocation(new Point(57, 55)); + okButton.setSize(new Point(70, 25)); + okButton.setText(Labels.getLabel("button.OK")); + okButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + message = text.getText(); + shell.dispose(); + } + }); + shell.setDefaultButton(okButton); + cancelButton = new Button(shell, SWT.NONE); + cancelButton.setLocation(new Point(155, 55)); + cancelButton.setSize(new Point(70, 25)); + cancelButton.setText(Labels.getLabel("button.cancel")); + cancelButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + message = null; + shell.dispose(); + } + }); + } + + private void setText(String text) { + this.text.setText(text); + this.text.setSelection(0, -1); + } + + /** + * Opens the dialog and waits for user to input the data. + * + * @return the entered text or null in case of cancel. + */ + public String open(String text) { + setText(text); + super.open(); + return message; + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/MainMenu.java b/ipscan/src/net/azib/ipscan/gui/MainMenu.java new file mode 100755 index 00000000..06097fba --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/MainMenu.java @@ -0,0 +1,227 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.gui.actions.ColumnsActions; +import net.azib.ipscan.gui.actions.CommandsActions; +import net.azib.ipscan.gui.actions.FavoritesActions; +import net.azib.ipscan.gui.actions.FileActions; +import net.azib.ipscan.gui.actions.GotoActions; +import net.azib.ipscan.gui.actions.HelpActions; +import net.azib.ipscan.gui.actions.ToolsActions; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Decorations; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Shell; +import org.picocontainer.MutablePicoContainer; +import org.picocontainer.PicoContainer; +import org.picocontainer.defaults.ConstructorInjectionComponentAdapter; +import org.picocontainer.defaults.DefaultPicoContainer; + +/** + * MainMenu + * + * @author anton + */ +public class MainMenu { + + private MutablePicoContainer container; + + public MainMenu(Shell shell, Menu mainMenu, CommandsMenu resultsContextMenu, PicoContainer parentContainer) { + + // create the menu-specific child container + container = new DefaultPicoContainer(parentContainer); + + // register some components not registered in the main menu + container.registerComponentImplementation(FavoritesMenu.class); + container.registerComponentImplementation(FavoritesActions.ShowMenu.class); + container.registerComponentImplementation(FavoritesActions.Select.class); + container.registerComponentImplementation(FavoritesActions.Add.class); + container.registerComponentImplementation(FavoritesActions.Edit.class); + + container.registerComponentImplementation(CommandsActions.EditOpeners.class); + container.registerComponentImplementation(CommandsActions.SelectOpener.class); + container.registerComponentImplementation(CommandsActions.ShowOpenersMenu.class); + // this one is not cached because we need 2 instances of it - in the Commands menu and in the context menu + container.registerComponent(new ConstructorInjectionComponentAdapter(OpenersMenu.class, OpenersMenu.class)); + + shell.setMenuBar(mainMenu); + createMainMenuItems(mainMenu); + + createCommandsMenuItems(resultsContextMenu); + } + + private void createMainMenuItems(Menu menu) { + + Menu subMenu = initMenu(menu, "menu.file"); + initMenuItem(subMenu, "menu.file.saveAll", new Integer(SWT.CONTROL | 'S'), initListener(FileActions.SaveAll.class)); + initMenuItem(subMenu, "menu.file.saveSelection", null, initListener(FileActions.SaveSelection.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.file.exportOptions", null, null); + initMenuItem(subMenu, "menu.file.importOptions", null, null); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.file.exit", null, initListener(FileActions.Exit.class)); + + subMenu = initMenu(menu, "menu.goto"); + initMenuItem(subMenu, "menu.goto.aliveHost", new Integer(SWT.CONTROL | SWT.SHIFT | 'H'), initListener(GotoActions.NextAliveHost.class)); + initMenuItem(subMenu, "menu.goto.deadHost", new Integer(SWT.CONTROL | SWT.SHIFT | 'D'), initListener(GotoActions.NextDeadHost.class)); + initMenuItem(subMenu, "menu.goto.openPort", new Integer(SWT.CONTROL | SWT.SHIFT | 'P'), initListener(GotoActions.NextHostWithInfo.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.goto.find", new Integer(SWT.CONTROL | 'F'), initListener(GotoActions.Find.class)); + + subMenu = initMenu(menu, "menu.commands"); + createCommandsMenuItems(subMenu); + + createFavoritesMenu(menu); + + subMenu = initMenu(menu, "menu.tools"); + initMenuItem(subMenu, "menu.tools.options", new Integer(SWT.CONTROL | 'O'), initListener(ToolsActions.Options.class)); + initMenuItem(subMenu, "menu.tools.fetchers", null, initListener(ToolsActions.SelectFetchers.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.tools.delete", null, null); + initMenuItem(subMenu, "menu.tools.lastInfo", new Integer(SWT.CONTROL | 'I'), null); + + subMenu = initMenu(menu, "menu.help"); + initMenuItem(subMenu, "menu.help.gettingStarted", new Integer(SWT.F1), initListener(HelpActions.GettingStarted.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.help.website", null, initListener(HelpActions.Website.class)); + initMenuItem(subMenu, "menu.help.forum", null, initListener(HelpActions.Forum.class)); + initMenuItem(subMenu, "menu.help.plugins", null, initListener(HelpActions.Plugins.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.help.cmdLine", null, null); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.help.checkVersion", null, initListener(HelpActions.CheckVersion.class)); + initMenuItem(subMenu, null, null, null); + initMenuItem(subMenu, "menu.help.about", new Integer(SWT.F12), initListener(HelpActions.About.class)); + } + + private void createCommandsMenuItems(Menu menu) { + initMenuItem(menu, "menu.commands.details", null, initListener(CommandsActions.Details.class)); + initMenuItem(menu, null, null, null); + initMenuItem(menu, "menu.commands.rescan", new Integer(SWT.CONTROL | 'R'), null); + initMenuItem(menu, "menu.commands.delete", new Integer(SWT.DEL), initListener(CommandsActions.Delete.class)); + initMenuItem(menu, null, null, null); + initMenuItem(menu, "menu.commands.copy", new Integer(SWT.CONTROL | 'C'), initListener(CommandsActions.CopyIP.class)); + initMenuItem(menu, "menu.commands.copyDetails", null, initListener(CommandsActions.CopyIPDetails.class)); + initMenuItem(menu, null, null, null); + createOpenersMenu(menu); + // initMenuItem(subMenu, "menu.commands.show", null, initListener()); + } + + private void createOpenersMenu(Menu subMenu) { + OpenersMenu openersMenu = (OpenersMenu) container.getComponentInstance(OpenersMenu.class); + MenuItem openersMenuItem = new MenuItem(subMenu, SWT.CASCADE); + openersMenuItem.setText(Labels.getLabel("menu.commands.open")); + openersMenuItem.setMenu(openersMenu); + } + + private void createFavoritesMenu(Menu parentMenu) { + MenuItem favoritesMenuItem = new MenuItem(parentMenu, SWT.CASCADE); + favoritesMenuItem.setText(Labels.getLabel("menu.favorites")); + Menu favoritesMenu = (Menu) container.getComponentInstance(FavoritesMenu.class); + favoritesMenuItem.setMenu(favoritesMenu); + } + + private static Menu initMenu(Menu menu, String label) { + MenuItem menuItem = new MenuItem(menu, SWT.CASCADE); + menuItem.setText(Labels.getLabel(label)); + + Menu subMenu = new Menu(menu.getShell(), SWT.DROP_DOWN); + menuItem.setMenu(subMenu); + + return subMenu; + } + + private Listener initListener(Class listenerClass) { + // register the component if it is not registered yet + if (container.getComponentAdapter(listenerClass) == null) + container.registerComponentImplementation(listenerClass); + // .. and create the instance, satisfying all the dependencies + return (Listener) container.getComponentInstance(listenerClass); + } + + private static MenuItem initMenuItem(Menu parent, String label, Integer accelerator, Listener listener) { + MenuItem menuItem = new MenuItem(parent, label == null ? SWT.SEPARATOR : SWT.PUSH); + + if (label != null) + menuItem.setText(Labels.getLabel(label)); + + if (accelerator != null) + menuItem.setAccelerator(accelerator.intValue()); + + if (listener != null) + menuItem.addListener(SWT.Selection, listener); + else + menuItem.setEnabled(false); + + return menuItem; + } + + /** + * CommandsMenu wrapper for type-safety + */ + public static class CommandsMenu extends Menu { + public CommandsMenu(Decorations parent) { + super(parent, SWT.POP_UP); + } + protected void checkSubclass() { } // allow extending of Menu class + } + + /** + * OpenersMenu wrapper for type-safety + */ + public static class OpenersMenu extends Menu { + public OpenersMenu(Decorations parent, CommandsActions.EditOpeners editOpenersListener, CommandsActions.ShowOpenersMenu showOpenersMenuListener) { + super(parent, SWT.DROP_DOWN); + + initMenuItem(this, "menu.commands.open.edit", null, editOpenersListener); + initMenuItem(this, null, null, null); + + addListener(SWT.Show, showOpenersMenuListener); + + // run the listener to populate the menu initially and initialize accelerators + Event e = new Event(); + e.widget = this; + showOpenersMenuListener.handleEvent(e); + } + protected void checkSubclass() { } // allow extending of Menu class + } + + /** + * FavoritesMenu wrapper for type-safety + */ + public static class FavoritesMenu extends Menu { + public FavoritesMenu(Decorations parent, FavoritesActions.Add addListener, FavoritesActions.Edit editListener, FavoritesActions.ShowMenu showFavoritesMenuListener) { + super(parent, SWT.DROP_DOWN); + + initMenuItem(this, "menu.favorites.add", new Integer(SWT.CONTROL | 'D'), addListener); + initMenuItem(this, "menu.favorites.edit", null, editListener); + initMenuItem(this, null, null, null); + + addListener(SWT.Show, showFavoritesMenuListener); + } + protected void checkSubclass() { } // allow extending of Menu class + } + + /** + * ColumnsMenu wrapper for type-safety. + * This is the menu when clicking on a column header. + */ + public static class ColumnsMenu extends Menu { + public ColumnsMenu(Decorations parent, ColumnsActions.SortBy sortByListener) { + super(parent, SWT.POP_UP); + + initMenuItem(this, "menu.columns.sortBy", null, sortByListener); + initMenuItem(this, "menu.columns.info", null, null); + initMenuItem(this, "menu.columns.options", null, null); + } + protected void checkSubclass() { } // allow extending of Menu class + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/MainWindow.java b/ipscan/src/net/azib/ipscan/gui/MainWindow.java new file mode 100755 index 00000000..b3e3fc81 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/MainWindow.java @@ -0,0 +1,189 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.util.Iterator; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.Version; +import net.azib.ipscan.gui.MainMenu.CommandsMenu; +import net.azib.ipscan.gui.actions.StartStopScanningAction; +import net.azib.ipscan.gui.feeders.AbstractFeederGUI; +import net.azib.ipscan.gui.feeders.FeederGUIRegistry; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; + +/** + * Main window of Angry IP Scanner. + * Contains the menu, IP resultTable, status bar (with progress bar) and + * a Composite area, which can be substituted dynamically based on + * the selected feeder. + * + * @author anton + */ +public class MainWindow { + + private Shell shell; + + private Composite feederArea; + + private Combo feederSelectionCombo; + private FeederGUIRegistry feederRegistry; + + /** + * Creates and initializes the main window. + */ + public MainWindow(Shell shell, Composite feederArea, Composite controlsArea, Combo feederSelectionCombo, Button startStopButton, StartStopScanningAction startStopScanningAction, ResultTable resultTable, StatusBar statusBar, CommandsMenu resultsContextMenu, FeederGUIRegistry feederGUIRegistry) { + + initShell(shell); + + initFeederArea(feederArea, feederGUIRegistry); + + initControlsArea(controlsArea, feederSelectionCombo, startStopButton, startStopScanningAction); + + initTableAndStatusBar(resultTable, resultsContextMenu, statusBar); + + // after all controls are initialized, resize and open + shell.setBounds(Config.getDimensionsConfig().getWindowBounds()); + shell.setMaximized(Config.getDimensionsConfig().isWindowMaximized); + shell.open(); + } + + /** + * This method initializes shell + */ + private void initShell(final Shell shell) { + this.shell = shell; + + FormLayout formLayout = new FormLayout(); + shell.setLayout(formLayout); + shell.setText(Version.FULL_NAME); + + // load and set icon + Image image = new Image(shell.getDisplay(), Labels.getInstance().getImageAsStream("icon")); + shell.setImage(image); + + shell.addListener(SWT.Close, new Listener() { + public void handleEvent(Event event) { + // save dimensions! + Config.getDimensionsConfig().setWindowBounds(shell.getBounds(), shell.getMaximized()); + } + }); + } + + /** + * @return the underlying shell, used by the Main class + */ + public Shell getShell() { + return shell; + } + + /** + * @return true if the underlying shell is disposed + */ + public boolean isDisposed() { + return shell.isDisposed(); + } + + /** + * This method initializes resultTable + */ + private void initTableAndStatusBar(ResultTable resultTable, CommandsMenu resultsContextMenu, StatusBar statusBar) { + FormData formData = new FormData(); + formData.top = new FormAttachment(feederArea); + formData.left = new FormAttachment(0); + formData.right = new FormAttachment(100); + formData.bottom = new FormAttachment(statusBar.getComposite(), -3); + resultTable.setLayoutData(formData); + resultTable.setMenu(resultsContextMenu); + } + + private void initFeederArea(Composite feederArea, FeederGUIRegistry feederRegistry) { + // feederArea is the placeholder for the visible feeder + this.feederArea = feederArea; + FormData formData = new FormData(); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(0); + feederArea.setLayoutData(formData); + + this.feederRegistry = feederRegistry; + } + + /** + * This method initializes main controls of the main window + */ + private void initControlsArea(Composite controlsArea, Combo feederSelectionCombo, Button startStopButton, StartStopScanningAction startStopScanningAction) { + + FormData formData = new FormData(); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(feederArea); + formData.right = new FormAttachment(100); + formData.bottom = new FormAttachment(feederArea, 0, SWT.BOTTOM); + controlsArea.setLayoutData(formData); + + RowLayout rowLayout = new RowLayout(SWT.VERTICAL); + rowLayout.marginLeft = 7; + controlsArea.setLayout(rowLayout); + + // start/stop button + shell.setDefaultButton(startStopButton); + startStopButton.setLayoutData(new RowData(SWT.DEFAULT, 23)); + startStopButton.addSelectionListener(startStopScanningAction); + + // feeder selection combobox + this.feederSelectionCombo = feederSelectionCombo; + feederSelectionCombo.setLayoutData(new RowData(SWT.DEFAULT, 23)); + for (Iterator i = feederRegistry.iterator(); i.hasNext();) { + AbstractFeederGUI feederGUI = (AbstractFeederGUI) i.next(); + feederSelectionCombo.add(feederGUI.getFeederName()); + } + IPFeederSelectionListener feederSelectionListener = new IPFeederSelectionListener(); + feederSelectionCombo.addSelectionListener(feederSelectionListener); + // initialize the selected feeder GUI + feederSelectionCombo.select(Config.getGlobal().activeFeeder); + feederSelectionCombo.setToolTipText(Labels.getLabel("combobox.feeder.tooltip")); + feederSelectionListener.widgetSelected(null); + + ((RowData)startStopButton.getLayoutData()).height = feederSelectionCombo.getBounds().height; + ((RowData)startStopButton.getLayoutData()).width = feederSelectionCombo.getBounds().width; + } + + /** + * IP Feeder selection listener. Updates the GUI according to the IP Feeder selection. + */ + private final class IPFeederSelectionListener implements SelectionListener { + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + public void widgetSelected(SelectionEvent e) { + feederRegistry.select(feederSelectionCombo.getSelectionIndex()); + + // all this 'magic' is needed in order to resize everything properly + // and accomodate feeders with different sizes + Rectangle bounds = feederRegistry.current().getBounds(); + FormData feederAreaLayoutData = ((FormData)feederArea.getLayoutData()); + feederAreaLayoutData.height = bounds.height; + feederAreaLayoutData.width = bounds.width; + shell.layout(); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/OptionsWindow.java b/ipscan/src/net/azib/ipscan/gui/OptionsWindow.java new file mode 100755 index 00000000..cead97b5 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/OptionsWindow.java @@ -0,0 +1,312 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.GlobalConfig; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.net.PingerRegistry; + +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.layout.RowLayout; + +/** + * OptionsWindow + * + * @author anton + */ +public class OptionsWindow extends AbstractModalDialog { + + private PingerRegistry pingerRegistry; + + private TabFolder tabFolder; + private Composite scanningTab; + private Composite displayTab; + private Text threadDelayText; + private Text maxThreadsText; + private Button okButton; + private Button cancelButton; + private Button deadHostsCheckbox; + private Text pingingTimeoutText; + private Text pingingCountText; + private Combo pingersCombo; + private Button skipBroadcastsCheckbox; + private Composite fetchersTab; + private Composite portsTab; + private Text portTimeoutText; + private Button adaptTimeoutCheckbox; + private Text portsText; + + public OptionsWindow(PingerRegistry pingerRegistry) { + this.pingerRegistry = pingerRegistry; + } + + public void open() { + // widgets are created on demand + createShell(); + loadOptions(); + super.open(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + shell = new Shell(currentDisplay != null ? currentDisplay.getActiveShell() : null, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + shell.setText(Labels.getLabel("title.options")); + createTabFolder(); + shell.setSize(new Point(350, 423)); + shell.setLayout(null); + okButton = new Button(shell, SWT.NONE); + okButton.setBounds(new Rectangle(175, 365, 75, 25)); + okButton.setText("OK"); + shell.setDefaultButton(okButton); + cancelButton = new Button(shell, SWT.NONE); + cancelButton.setBounds(new Rectangle(260, 365, 75, 25)); + cancelButton.setText("Cancel"); + + okButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + saveOptions(); + shell.close(); + } + }); + cancelButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { + public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { + shell.close(); + } + }); + } + + /** + * This method initializes tabFolder + */ + private void createTabFolder() { + tabFolder = new TabFolder(shell, SWT.NONE); + createScanningTab(); + createDisplayTab(); + createFetchersTab(); + createPortsTab(); + tabFolder.setBounds(new Rectangle(5, 5, 330, 355)); + TabItem tabItem = new TabItem(tabFolder, SWT.NONE); + tabItem.setText(Labels.getLabel("title.options.scanning")); + tabItem.setControl(scanningTab); + TabItem tabItem1 = new TabItem(tabFolder, SWT.NONE); + tabItem1.setText(Labels.getLabel("title.options.ports")); + tabItem1.setControl(portsTab); + TabItem tabItem2 = new TabItem(tabFolder, SWT.NONE); + tabItem2.setText(Labels.getLabel("title.options.display")); + tabItem2.setControl(displayTab); + TabItem tabItem3 = new TabItem(tabFolder, SWT.NONE); + tabItem3.setText(Labels.getLabel("title.options.fetchers")); + tabItem3.setControl(fetchersTab); + } + + /** + * This method initializes scanningTab + */ + private void createScanningTab() { + RowLayout rowLayout = new RowLayout(); + rowLayout.type = org.eclipse.swt.SWT.VERTICAL; + rowLayout.marginTop = 9; + rowLayout.spacing = 9; + rowLayout.marginLeft = 11; + rowLayout.fill = true; + scanningTab = new Composite(tabFolder, SWT.NONE); + scanningTab.setLayout(rowLayout); + + GridLayout groupLayout = new GridLayout(); + groupLayout.numColumns = 2; + Group threadsGroup = new Group(scanningTab, SWT.NONE); + threadsGroup.setText(Labels.getLabel("options.threads")); + threadsGroup.setLayout(groupLayout); + + GridData gridData = new GridData(); + gridData.widthHint = 80; + + Label label; + + label = new Label(threadsGroup, SWT.NONE); + label.setText(Labels.getLabel("options.threads.delay")); + threadDelayText = new Text(threadsGroup, SWT.BORDER); + threadDelayText.setLayoutData(gridData); + + label = new Label(threadsGroup, SWT.NONE); + label.setText(Labels.getLabel("options.threads.maxThreads")); + maxThreadsText = new Text(threadsGroup, SWT.BORDER); + maxThreadsText.setLayoutData(gridData); + + Group pingingGroup = new Group(scanningTab, SWT.NONE); + pingingGroup.setLayout(groupLayout); + pingingGroup.setText(Labels.getLabel("options.pinging")); + + label = new Label(pingingGroup, SWT.NONE); + label.setText(Labels.getLabel("options.pinging.type")); + pingersCombo = new Combo(pingingGroup, SWT.DROP_DOWN | SWT.READ_ONLY); + pingersCombo.setLayoutData(gridData); + String[] pingerNames = pingerRegistry.getRegisteredNames(); + for (int i = 0; i < pingerNames.length; i++) { + pingersCombo.add(Labels.getLabel(pingerNames[i])); + // this is used by saveOptions() + pingersCombo.setData(Integer.toString(i), pingerNames[i]); + } + pingersCombo.select(0); + + label = new Label(pingingGroup, SWT.NONE); + label.setText(Labels.getLabel("options.pinging.count")); + pingingCountText = new Text(pingingGroup, SWT.BORDER); + pingingCountText.setLayoutData(gridData); + + label = new Label(pingingGroup, SWT.NONE); + label.setText(Labels.getLabel("options.pinging.timeout")); + pingingTimeoutText = new Text(pingingGroup, SWT.BORDER); + pingingTimeoutText.setLayoutData(gridData); + + GridData gridData1 = new GridData(); + gridData1.horizontalSpan = 2; + deadHostsCheckbox = new Button(pingingGroup, SWT.CHECK); + deadHostsCheckbox.setText(Labels.getLabel("options.pinging.deadHosts")); + deadHostsCheckbox.setLayoutData(gridData1); + + Group broadcastGroup = new Group(scanningTab, SWT.NONE); + broadcastGroup.setLayout(groupLayout); + broadcastGroup.setText(Labels.getLabel("options.broadcast")); + + skipBroadcastsCheckbox = new Button(broadcastGroup, SWT.CHECK); + skipBroadcastsCheckbox.setText(Labels.getLabel("options.broadcast.skip")); + skipBroadcastsCheckbox.setLayoutData(gridData1); + } + + /** + * This method initializes displayTab + */ + private void createDisplayTab() { + displayTab = new Composite(tabFolder, SWT.NONE); + displayTab.setLayout(new GridLayout()); + } + + /** + * This method initializes portsTab + */ + private void createPortsTab() { + RowLayout rowLayout = new RowLayout(); + rowLayout.type = org.eclipse.swt.SWT.VERTICAL; + rowLayout.marginTop = 9; + rowLayout.spacing = 9; + rowLayout.marginLeft = 11; + rowLayout.fill = true; + portsTab = new Composite(tabFolder, SWT.NONE); + portsTab.setLayout(rowLayout); + + GridLayout groupLayout = new GridLayout(); + groupLayout.numColumns = 2; + Group timingGroup = new Group(portsTab, SWT.NONE); + timingGroup.setText(Labels.getLabel("options.ports.timing")); + timingGroup.setLayout(groupLayout); + + GridData gridData = new GridData(); + gridData.widthHint = 50; + + Label label; + + label = new Label(timingGroup, SWT.NONE); + label.setText(Labels.getLabel("options.ports.timing.timeout")); + portTimeoutText = new Text(timingGroup, SWT.BORDER); + portTimeoutText.setLayoutData(gridData); + + GridData gridData1 = new GridData(); + gridData1.horizontalSpan = 2; + adaptTimeoutCheckbox = new Button(timingGroup, SWT.CHECK); + adaptTimeoutCheckbox.setText(Labels.getLabel("options.ports.timing.adaptTimeout")); + adaptTimeoutCheckbox.setLayoutData(gridData1); + + RowLayout portsLayout = new RowLayout(SWT.VERTICAL); + portsLayout.fill = true; + Group portsGroup = new Group(portsTab, SWT.NONE); + portsGroup.setText(Labels.getLabel("options.ports.ports")); + portsGroup.setLayout(portsLayout); + + label = new Label(portsGroup, SWT.WRAP); + label.setText(Labels.getLabel("options.ports.portsDescription")); + label.setLayoutData(new RowData(280, SWT.DEFAULT)); + portsText = new Text(portsGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL); + portsText.setLayoutData(new RowData(260, 60)); + // TODO: configuration string validation + + } + + /** + * This method initializes fetchersTab + */ + private void createFetchersTab() { + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + fetchersTab = new Composite(tabFolder, SWT.NONE); + fetchersTab.setLayout(gridLayout); + Label label = new Label(fetchersTab, SWT.NONE); + label.setText(Labels.getLabel("options.fetchers.info")); + } + + private void loadOptions() { + GlobalConfig global = Config.getGlobal(); + maxThreadsText.setText(Integer.toString(global.maxThreads)); + threadDelayText.setText(Integer.toString(global.threadDelay)); + String[] pingerNames = pingerRegistry.getRegisteredNames(); + for (int i = 0; i < pingerNames.length; i++) { + if (global.selectedPinger.equals(pingerNames[i])) { + pingersCombo.select(i); + } + } + pingingCountText.setText(Integer.toString(global.pingCount)); + pingingTimeoutText.setText(Integer.toString(global.pingTimeout)); + deadHostsCheckbox.setSelection(global.scanDeadHosts); + skipBroadcastsCheckbox.setSelection(global.skipBroadcastAddresses); + portTimeoutText.setText(Integer.toString(global.portTimeout)); + adaptTimeoutCheckbox.setSelection(global.adaptPortTimeout); + portsText.setText(global.portString); + } + + private void saveOptions() { + GlobalConfig global = Config.getGlobal(); + global.maxThreads = parseIntValue(maxThreadsText); + global.threadDelay = parseIntValue(threadDelayText); + global.selectedPinger = (String) pingersCombo.getData(Integer.toString(pingersCombo.getSelectionIndex())); + global.pingCount = parseIntValue(pingingCountText); + global.pingTimeout = parseIntValue(pingingTimeoutText); + global.scanDeadHosts = deadHostsCheckbox.getSelection(); + global.skipBroadcastAddresses = skipBroadcastsCheckbox.getSelection(); + global.portTimeout = parseIntValue(portTimeoutText); + global.adaptPortTimeout = adaptTimeoutCheckbox.getSelection(); + global.portString = portsText.getText(); + } + + /** + * @return an int from the passed Text control. + */ + private static int parseIntValue(Text text) { + try { + return Integer.parseInt(text.getText()); + } + catch (NumberFormatException e) { + text.forceFocus(); + throw e; + } + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/ResultTable.java b/ipscan/src/net/azib/ipscan/gui/ResultTable.java new file mode 100755 index 00000000..a30b62c4 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/ResultTable.java @@ -0,0 +1,200 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.net.InetAddress; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.ScanningResult; +import net.azib.ipscan.core.ScanningResultList; +import net.azib.ipscan.core.ScanningSubject; +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; +import net.azib.ipscan.fetchers.FetcherRegistryUpdateListener; +import net.azib.ipscan.gui.MainMenu.ColumnsMenu; +import net.azib.ipscan.gui.actions.ColumnsActions; +import net.azib.ipscan.gui.actions.CommandsActions; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +/** + * Table of scanning results. + * TODO: separate fetcher selection logic to some other calls (the registry?) + * + * @author anton + */ +public class ResultTable extends Table implements FetcherRegistryUpdateListener { + + private ScanningResultList scanningResults; + + private Image[] listImages = new Image[4]; + + private String feederInfo; + + private Listener columnClickListener; + + private Listener columnResizeListener; + + public ResultTable(Composite parent, ColumnsMenu columnsMenu, FetcherRegistry fetcherRegistry, ScanningResultList scanningResultList) { + super(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL); + this.scanningResults = scanningResultList; + + setHeaderVisible(true); + setLinesVisible(true); + + columnClickListener = new ColumnsActions.ColumnClick(columnsMenu); + columnResizeListener = new Listener() { + public void handleEvent(Event event) { + // save column width + TableColumn column = (TableColumn) event.widget; + Config.getDimensionsConfig().setColumnWidth(column.getText(), column.getWidth()); + } + }; + + fetcherRegistry.addListener(this); + handleUpdateOfSelectedFetchers(fetcherRegistry); + + // pre-load button images + listImages[ScanningSubject.RESULT_TYPE_UNKNOWN] = new Image(null, Labels.getInstance().getImageAsStream("list.unknown.img")); + listImages[ScanningSubject.RESULT_TYPE_DEAD] = new Image(null, Labels.getInstance().getImageAsStream("list.dead.img")); + listImages[ScanningSubject.RESULT_TYPE_ALIVE] = new Image(null, Labels.getInstance().getImageAsStream("list.alive.img")); + listImages[ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO] = new Image(null, Labels.getInstance().getImageAsStream("list.addinfo.img")); + + Listener detailsListener = new Listener() { + CommandsActions.Details detailsListener = new CommandsActions.Details(ResultTable.this); + public void handleEvent(Event e) { + if (e.type == SWT.MouseDoubleClick || e.detail == SWT.TRAVERSE_RETURN) { + detailsListener.handleEvent(e); + e.doit = false; + } + } + }; + addListener(SWT.Traverse, detailsListener); + addListener(SWT.MouseDoubleClick, detailsListener); + + addListener(SWT.SetData, new SetDataListener()); + +// for (int i = 0; i < getColumnCount(); i++) { +// getColumn(i).add +// } + + } + + public void handleUpdateOfSelectedFetchers(FetcherRegistry fetcherRegistry) { + Collection fetchers = fetcherRegistry.getSelectedFetchers(); + for (Iterator i = fetchers.iterator(); i.hasNext();) { + Fetcher fetcher = (Fetcher) i.next(); + TableColumn tableColumn = new TableColumn(this, SWT.NONE); + String fetcherName = Labels.getLabel(fetcher.getLabel()); + tableColumn.setWidth(Config.getDimensionsConfig().getColumnWidth(fetcherName)); + tableColumn.setText(fetcherName); + tableColumn.addListener(SWT.Selection, columnClickListener); + tableColumn.addListener(SWT.Resize, columnResizeListener); + } + } + + protected void checkSubclass() { + // This method is overriden and does nothing in order to + // be able to subclass the Table. We are not going to + // override anything important, so this should be safe (tm) + } + + public int addResultsRow(final InetAddress address) { + if (isDisposed()) + return 0; + final int index = scanningResults.add(address); + getDisplay().syncExec(new Runnable() { + public void run() { + ResultTable.this.setItemCount(index+1); + } + }); + return index; + } + + public void updateResults(final int index) { + if (isDisposed()) + return; + getDisplay().syncExec(new Runnable() { + public void run() { + // redraw the item + ResultTable.this.clear(index); + } + }); + } + + /** + * Returns the details about the currently selected IP address + * @return + */ + public String getIPDetails() { + int selectedIndex = getSelectionIndex(); + return scanningResults.getResultsAsString(selectedIndex); + } + + public void remove(int[] indices) { + // we need to remove the elements from our real storage as well + scanningResults.remove(indices); + super.remove(indices); + } + + /** + * Initializes a new scan. + * (clears all elments, etc) + * @param newFeederInfo feeder info of the new feeder/settings + */ + public void initNewScan(String newFeederInfo) { + // initialize new feeder info + this.feederInfo = newFeederInfo; + // remove previous results + scanningResults.clear(); + // remove all items from the table + removeAll(); + } + + /** + * @return the internal ScanningResultList instance, containing the results. + */ + public ScanningResultList getScanningResults() { + return scanningResults; + } + + private class SetDataListener implements Listener { + + public void handleEvent(Event event) { + TableItem item = (TableItem)event.item; + int tableIndex = ResultTable.this.indexOf(item); + + ScanningResult scanningResult = scanningResults.getResult(tableIndex); + List values = scanningResult.getValues(); + String[] resultStrings = new String[values.size()]; + for (int i = 0; i < values.size(); i++) { + Object value = values.get(i); + if (value != null) + resultStrings[i] = value.toString(); + } + item.setText(resultStrings); + item.setImage(0, listImages[scanningResult.getType()]); + } + + } + + /** + * @return the feeder info, which used in this scan + */ + public String getFeederInfo() { + return feederInfo; + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/ScanningResultsConsumer.java b/ipscan/src/net/azib/ipscan/gui/ScanningResultsConsumer.java new file mode 100755 index 00000000..adfb1d44 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/ScanningResultsConsumer.java @@ -0,0 +1,37 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.net.InetAddress; + +import net.azib.ipscan.core.ScanningResult; +import net.azib.ipscan.core.ScanningResultsCallback; + +/** + * + * @author anton + */ +public class ScanningResultsConsumer implements ScanningResultsCallback { + + private ResultTable resultTable; + + public ScanningResultsConsumer(ResultTable resultTable) { + this.resultTable = resultTable; + } + + /** + * @see net.azib.ipscan.core.ScanningResultsCallback#prepareForResults(InetAddress) + */ + public int prepareForResults(InetAddress address) { + return resultTable.addResultsRow(address); + } + + /** + * @see net.azib.ipscan.core.ScanningResultsCallback#consumeResults(int, ScanningResult) + */ + public void consumeResults(int preparationIndex, ScanningResult results) { + resultTable.updateResults(preparationIndex); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/SelectFetchersDialog.java b/ipscan/src/net/azib/ipscan/gui/SelectFetchersDialog.java new file mode 100755 index 00000000..6345a2d8 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/SelectFetchersDialog.java @@ -0,0 +1,163 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.fetchers.Fetcher; +import net.azib.ipscan.fetchers.FetcherRegistry; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; + +/** + * SelectFetchersWindow + * + * @author Anton Keks + */ +public class SelectFetchersDialog extends AbstractModalDialog { + + private FetcherRegistry fetcherRegistry; + + private List selectedFetchersList; + private List registeredFetchersList; + private Map registeredFetcherLabelsByNames = new HashMap(); + + public SelectFetchersDialog(FetcherRegistry fetcherRegistry) { + this.fetcherRegistry = fetcherRegistry; + } + + public void open() { + // create controls on demand + createShell(); + super.open(); + } + + /** + * This method initializes shell + */ + private void createShell() { + Display currentDisplay = Display.getCurrent(); + Shell parent = currentDisplay != null ? currentDisplay.getActiveShell() : null; + shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); + + shell.setText(Labels.getLabel("title.fetchers.select")); + shell.setSize(new Point(405, 332)); + shell.setLayout(null); + + Label messageLabel = new Label(shell, SWT.NONE); + messageLabel.setText(Labels.getLabel("text.fetchers.select")); + messageLabel.setBounds(new Rectangle(10, 10, 380, 14)); + + Label selectedLabel = new Label(shell, SWT.NONE); + selectedLabel.setText(Labels.getLabel("text.fetchers.selectedList")); + selectedLabel.setBounds(new Rectangle(10, 35, 155, 14)); + + selectedFetchersList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL); + selectedFetchersList.setBounds(new Rectangle(10, 55, 155, 200)); + Iterator i = fetcherRegistry.getSelectedFetchers().iterator(); + //i.next(); // skip IP + while (i.hasNext()) { + Fetcher fetcher = (Fetcher) i.next(); + String fetcherName = Labels.getLabel(fetcher.getLabel()); + selectedFetchersList.add(fetcherName); + } + + Button upButton = new Button(shell, SWT.NONE); + upButton.setText(Labels.getLabel("button.up")); + upButton.setBounds(new Rectangle(170, 55, 40, 25)); + + Button downButton = new Button(shell, SWT.NONE); + downButton.setText(Labels.getLabel("button.down")); + downButton.setBounds(new Rectangle(170, 85, 40, 25)); + + Button addButton = new Button(shell, SWT.NONE); + addButton.setText(Labels.getLabel("button.left")); + addButton.setBounds(new Rectangle(170, 130, 40, 25)); + + Button removeButton = new Button(shell, SWT.NONE); + removeButton.setText(Labels.getLabel("button.right")); + removeButton.setBounds(new Rectangle(170, 160, 40, 25)); + + Label registeredLabel = new Label(shell, SWT.NONE); + registeredLabel.setText(Labels.getLabel("text.fetchers.availableList")); + registeredLabel.setBounds(new Rectangle(230, 35, 155, 14)); + + registeredFetchersList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL); + registeredFetchersList.setBounds(new Rectangle(230, 55, 160, 200)); + i = fetcherRegistry.getRegisteredFetchers().iterator(); + //i.next(); // skip IP + while (i.hasNext()) { + Fetcher fetcher = (Fetcher) i.next(); + String fetcherName = Labels.getLabel(fetcher.getLabel()); + registeredFetcherLabelsByNames.put(fetcherName, fetcher.getLabel()); + if (selectedFetchersList.indexOf(fetcherName) < 0) + registeredFetchersList.add(fetcherName); + } + + upButton.addListener(SWT.Selection, new UpButtonListener(selectedFetchersList)); + downButton.addListener(SWT.Selection, new DownButtonListener(selectedFetchersList)); + addButton.addListener(SWT.Selection, new AddRemoveButtonListener(registeredFetchersList, selectedFetchersList)); + removeButton.addListener(SWT.Selection, new AddRemoveButtonListener(selectedFetchersList, registeredFetchersList)); + + Button closeButton = new Button(shell, SWT.NONE); + closeButton.setText(Labels.getLabel("button.close")); + closeButton.setBounds(new Rectangle(315, 270, 75, 25)); + + shell.addListener(SWT.Close, new Listener() { + public void handleEvent(Event e) { + saveSelectedFetchers(); + } + }); + closeButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + shell.close(); + } + }); + shell.setDefaultButton(closeButton); + } + + private void saveSelectedFetchers() { + String[] fetchersToRetain = new String[selectedFetchersList.getItemCount()]; + for (int i = 0; i < fetchersToRetain.length; i++) { + fetchersToRetain[i] = (String) registeredFetcherLabelsByNames.get(selectedFetchersList.getItem(i)); + } + fetcherRegistry.updateSelectedFetchers(fetchersToRetain); + } + + private static class AddRemoveButtonListener implements Listener { + + private List fromList; + private List toList; + + public AddRemoveButtonListener(List fromList, List toList) { + this.fromList = fromList; + this.toList = toList; + } + + public void handleEvent(Event event) { + int[] selectedItems = fromList.getSelectionIndices(); + + // first, add items back to the registered list + for (int i = 0; i < selectedItems.length; i++) { + toList.add(fromList.getItem(selectedItems[i])); + } + + // now, add remove the items + fromList.remove(selectedItems); + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/StatusBar.java b/ipscan/src/net/azib/ipscan/gui/StatusBar.java new file mode 100755 index 00000000..c464aac2 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/StatusBar.java @@ -0,0 +1,95 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.Shell; + +/** + * The status bar of the main window. + * + * @author anton + */ +public class StatusBar { + + private Composite composite; + + private ProgressBar progressBar; + private Label statusText; + private Label threadsText; + + public StatusBar(Shell shell) { + composite = new Composite(shell, SWT.NONE); + FormData formData = new FormData(); + formData.left = new FormAttachment(0); + formData.right = new FormAttachment(100); + formData.height = 18; + formData.bottom = new FormAttachment(100); + composite.setLayoutData(formData); + RowLayout rowLayout = new RowLayout(); + rowLayout.fill = true; + rowLayout.wrap = false; + rowLayout.spacing = 0; + composite.setLayout(/*rowLayout*/ new FillLayout()); + + statusText = new Label(composite, SWT.BORDER); + //statusText.setLayoutData(new RowData(150, SWT.DEFAULT)); + setStatusText(null); + + threadsText = new Label(composite, SWT.BORDER); + //threadsText.setLayoutData(new RowData(50, SWT.DEFAULT)); + threadsText.setText(Labels.getLabel("text.threads") + "0"); + + progressBar = new ProgressBar(composite, SWT.BORDER); + //progressBar.setLayoutData(new RowData()); + progressBar.setSelection(0); + } + + /** + * Used for the positioning of the controls in the MainWindow + */ + Composite getComposite() { + return composite; + } + + /** + * @return true if the underlying widgets are disposed + */ + public boolean isDisposed() { + return composite.isDisposed(); + } + + /** + * Sets the status bar text displayed to the user. + * @param statusText the text to set, null to use the default text (Ready) + */ + public void setStatusText(String statusText) { + if (statusText == null) { + statusText = Labels.getLabel("state.ready"); + } + if (!this.statusText.isDisposed()) + this.statusText.setText(statusText); + } + + public void setRunningThreads(int runningThreads) { + if (!threadsText.isDisposed()) + // TODO: make this more efficient + threadsText.setText(Labels.getLabel("text.threads") + runningThreads); + } + + public void setProgress(int progress) { + if (!progressBar.isDisposed()) + progressBar.setSelection(progress); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/UserErrorException.java b/ipscan/src/net/azib/ipscan/gui/UserErrorException.java new file mode 100755 index 00000000..501fbb66 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/UserErrorException.java @@ -0,0 +1,31 @@ +/** + * + */ +package net.azib.ipscan.gui; + +import net.azib.ipscan.config.Labels; + +/** + * Exception for throwing in case of user errors. + * These generally result in showing an error message. + * + * @author anton + */ +public class UserErrorException extends RuntimeException { + + private static final long serialVersionUID = 123283472834982L; + + public UserErrorException(String label) { + super(Labels.getLabel("exception.UserErrorException." + label)); + } + + public UserErrorException(String label, Throwable cause) { + this(label); + initCause(cause); + } + + public UserErrorException(String label, String rawInfo) { + super(Labels.getLabel("exception.UserErrorException." + label) + rawInfo); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/BrowserLauncher.java b/ipscan/src/net/azib/ipscan/gui/actions/BrowserLauncher.java new file mode 100755 index 00000000..157f222e --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/BrowserLauncher.java @@ -0,0 +1,51 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.lang.reflect.Method; + +import net.azib.ipscan.gui.UserErrorException; + +/** + * The cross-platform browser launcher + * + * @author anton + */ +public class BrowserLauncher { + + /** + * Opens an URL in the default browser. + * Supports Linux/Unix, MacOS, and Windows + * @param url + */ + public static void openURL(String url) { + String osName = System.getProperty("os.name"); + + try { + if (osName.startsWith("Windows")) { + Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); + } + else + if (osName.startsWith("Mac OS")) { + Class fileMgr = Class.forName("com.apple.eio.FileManager"); + Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); + openURL.invoke(null, new Object[] { url }); + } + else { // assume Linux or other Unix + // TODO: what if browser is already running as another user, not root? + String[] browsers = { "htmlview", "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; + String browser = null; + for (int count = 0; count < browsers.length && browser == null; count++) + if (Runtime.getRuntime().exec(new String[] { "which", browsers[count] }).waitFor() == 0) + browser = browsers[count]; + if (browser == null) + throw new Exception("Could not find web browser"); + Runtime.getRuntime().exec(new String[] { browser, url }); + } + } + catch (Exception e) { + throw new UserErrorException("openURL.failed", url); + } + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/ColumnsActions.java b/ipscan/src/net/azib/ipscan/gui/actions/ColumnsActions.java new file mode 100755 index 00000000..6a449ba2 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/ColumnsActions.java @@ -0,0 +1,73 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.gui.MainMenu.ColumnsMenu; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +/** + * ColumnsActions + * + * @author anton + */ +public class ColumnsActions { + + public static class ColumnClick implements Listener { + + private Menu columnsMenu; + + public ColumnClick(ColumnsMenu columnsMenu) { + this.columnsMenu = columnsMenu; + } + + public void handleEvent(Event e) { + // modify menu text a bit + TableColumn tableColumn = (TableColumn) e.widget; + MenuItem sortMenuItem = columnsMenu.getItem(0); + if (tableColumn.getParent().getSortColumn() == tableColumn) { + sortMenuItem.setText(Labels.getLabel("menu.columns.sortDirection")); + } + else { + sortMenuItem.setText(Labels.getLabel("menu.columns.sortBy") + tableColumn.getText()); + } + + // remember the clicked column (see SortBy below) + sortMenuItem.setData(tableColumn); + + // show the menu + columnsMenu.setLocation(e.display.getCursorLocation()); + columnsMenu.setVisible(true); + } + } + + public static class SortBy implements Listener { + + public void handleEvent(Event event) { + // retrieve the clicked column (see ColumnClick above) + TableColumn tableColumn = (TableColumn) event.widget.getData(); + + Table table = tableColumn.getParent(); + + if (table.getSortColumn() != tableColumn) { + table.setSortColumn(tableColumn); + table.setSortDirection(SWT.UP); + } + else { + table.setSortDirection(table.getSortDirection() == SWT.UP ? SWT.DOWN : SWT.UP); + } + + // TODO: execute ScanningResultList.sort() here!!! + } + + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/CommandsActions.java b/ipscan/src/net/azib/ipscan/gui/actions/CommandsActions.java new file mode 100755 index 00000000..7d905070 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/CommandsActions.java @@ -0,0 +1,196 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.util.Iterator; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.OpenersConfig.Opener; +import net.azib.ipscan.fetchers.FetcherRegistry; +import net.azib.ipscan.gui.DetailsWindow; +import net.azib.ipscan.gui.EditOpenersDialog; +import net.azib.ipscan.gui.ResultTable; +import net.azib.ipscan.gui.StatusBar; +import net.azib.ipscan.gui.UserErrorException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +/** + * Commands and Context menu Actions. + * All these operate on the items, selected in the results list. + * TODO: check for selection everywhere + * + * @author anton + */ +public class CommandsActions { + + public static class Details implements Listener { + private ResultTable resultTable; + + public Details(ResultTable resultTable) { + this.resultTable = resultTable; + } + + public void handleEvent(Event event) { + checkSelection(resultTable); + new DetailsWindow(resultTable).open(); + } + } + + public static class Delete implements Listener { + private ResultTable resultTable; + + public Delete(ResultTable resultTable) { + this.resultTable = resultTable; + } + + public void handleEvent(Event event) { + checkSelection(resultTable); + int firstSelection = resultTable.getSelectionIndex(); + resultTable.remove(resultTable.getSelectionIndices()); + resultTable.setSelection(firstSelection); + } + } + + public static class CopyIP implements Listener { + private ResultTable resultTable; + + public CopyIP(ResultTable resultTable) { + this.resultTable = resultTable; + } + + public void handleEvent(Event event) { + checkSelection(resultTable); + Clipboard clipboard = new Clipboard(event.display); + clipboard.setContents(new Object[] {resultTable.getItem(resultTable.getSelectionIndex()).getText()}, new Transfer[] {TextTransfer.getInstance()}); + clipboard.dispose(); + } + } + + public static class CopyIPDetails implements Listener { + private ResultTable resultTable; + + public CopyIPDetails(ResultTable resultTable) { + this.resultTable = resultTable; + } + + public void handleEvent(Event event) { + checkSelection(resultTable); + Clipboard clipboard = new Clipboard(event.display); + clipboard.setContents(new Object[] {resultTable.getIPDetails()}, new Transfer[] {TextTransfer.getInstance()}); + clipboard.dispose(); + } + } + + /** + * Checks that there is at least one item selected in the results list. + * @param mainWindow + */ + private static void checkSelection(ResultTable resultTable) { + if (resultTable.getItemCount() <= 0) { + throw new UserErrorException("commands.noResults"); + } + else + if (resultTable.getSelectionIndex() < 0) { + throw new UserErrorException("commands.noSelection"); + } + } + + public static class ShowOpenersMenu implements Listener { + + private Listener openersSelectListener; + + public ShowOpenersMenu(SelectOpener selectOpener) { + this.openersSelectListener = selectOpener; + } + + public void handleEvent(Event event) { + Menu openersMenu = (Menu)event.widget; + MenuItem[] menuItems = openersMenu.getItems(); + for (int i = 2; i < menuItems.length; i++) { + menuItems[i].dispose(); + } + + // update menu items + int index = 0; + for (Iterator i = Config.getOpenersConfig().iterateNames(); i.hasNext();) { + MenuItem menuItem = new MenuItem(openersMenu, SWT.CASCADE); + String name = (String)i.next(); + + index++; + if (index <= 9) { + name += "\tCtrl+" + index; + menuItem.setAccelerator(SWT.CONTROL | ('0' + index)); + } + + menuItem.setText(name); + menuItem.setData(new Integer(index)); + menuItem.addListener(SWT.Selection, openersSelectListener); + } + + } + } + + public static class EditOpeners implements Listener { + + FetcherRegistry fetcherRegistry; + + public EditOpeners(FetcherRegistry fetcherRegistry) { + this.fetcherRegistry = fetcherRegistry; + } + + public void handleEvent(Event event) { + new EditOpenersDialog(fetcherRegistry).open(); + } + } + + public static class SelectOpener implements Listener { + + private StatusBar statusBar; + private ResultTable resultTable; + private OpenerLauncher openerLauncher; + + public SelectOpener(StatusBar statusBar, ResultTable resultTable, OpenerLauncher openerLauncher) { + this.statusBar = statusBar; + this.resultTable = resultTable; + this.openerLauncher = openerLauncher; + } + + public void handleEvent(Event event) { + MenuItem menuItem = (MenuItem) event.widget; + String name = menuItem.getText(); + int indexOf = name.lastIndexOf('\t'); + if (indexOf >= 0) { + name = name.substring(0, indexOf); + } + Opener opener = Config.getOpenersConfig().getOpener(name); + + int selectedItem = resultTable.getSelectionIndex(); + if (selectedItem < 0) { + throw new UserErrorException("commands.noSelection"); + } + + try { + statusBar.setStatusText(Labels.getLabel("state.opening") + name); + openerLauncher.launch(opener, selectedItem); + // wait a bit to make status visible + // TODO: somehow wait until the process is started + Thread.sleep(500); + } + catch (InterruptedException e) {} + finally { + statusBar.setStatusText(null); + } + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/FavoritesActions.java b/ipscan/src/net/azib/ipscan/gui/actions/FavoritesActions.java new file mode 100755 index 00000000..e8a9bc1e --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/FavoritesActions.java @@ -0,0 +1,109 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.util.Iterator; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.NamedListConfig; +import net.azib.ipscan.gui.EditFavoritesDialog; +import net.azib.ipscan.gui.InputDialog; +import net.azib.ipscan.gui.UserErrorException; +import net.azib.ipscan.gui.feeders.FeederGUIRegistry; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +/** + * FavoritesActions + * + * @author anton + */ +public class FavoritesActions { + + public static class Add implements Listener { + private FeederGUIRegistry feederRegistry; + + public Add(FeederGUIRegistry feederRegistry) { + this.feederRegistry = feederRegistry; + } + + public void handleEvent(Event event) { + String feederInfo = feederRegistry.current().getInfo(); + InputDialog inputDialog = new InputDialog( + Labels.getLabel("title.favorite.add"), + Labels.getLabel("text.favorite.add")); + String favoriteName = inputDialog.open(feederInfo); + + if (favoriteName != null) { + NamedListConfig favoritesConfig = Config.getFavoritesConfig(); + if (favoritesConfig.get(favoriteName) != null) { + throw new UserErrorException("favorite.alreadyExists"); + } + String serializedFeeder = feederRegistry.current().getFeederName() + '\t' + feederRegistry.current().serialize(); + favoritesConfig.add(favoriteName, serializedFeeder); + } + } + } + + public static class Select implements Listener { + private FeederGUIRegistry feederRegistry; + + public Select(FeederGUIRegistry feederRegistry) { + this.feederRegistry = feederRegistry; + } + + public void handleEvent(Event event) { + MenuItem menuItem = (MenuItem) event.widget; + String serializedFeeder = Config.getFavoritesConfig().get(menuItem.getText()); + + int indexOf = serializedFeeder.indexOf('\t'); + String feederName = serializedFeeder.substring(0, indexOf); + serializedFeeder = serializedFeeder.substring(indexOf + 1); + + feederRegistry.select(feederName); + feederRegistry.current().unserialize(serializedFeeder); + } + } + + public static class Edit implements Listener { + public void handleEvent(Event event) { + new EditFavoritesDialog().open(); + } + } + + public static class ShowMenu implements Listener { + private Listener favoritesSelectListener; + + public ShowMenu(Select favoritesSelectListener) { + // the listener for favorites selections from the menu + this.favoritesSelectListener = favoritesSelectListener; + } + + public void handleEvent(Event event) { + Menu favoritesMenu = (Menu) event.widget; + // populate favorites in the menu + NamedListConfig favoritesConfig = Config.getFavoritesConfig(); + + // note: 3 is the number of items in the menu when no favorites exist + // dispose old favorites + MenuItem[] menuItems = favoritesMenu.getItems(); + for (int i = 3; i < menuItems.length; i++) { + menuItems[i].dispose(); + } + + // update favorites menu items + for (Iterator i = favoritesConfig.iterateNames(); i.hasNext();) { + MenuItem menuItem = new MenuItem(favoritesMenu, SWT.CASCADE); + menuItem.setText((String) i.next()); + menuItem.addListener(SWT.Selection, favoritesSelectListener); + } + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/FeederActions.java b/ipscan/src/net/azib/ipscan/gui/actions/FeederActions.java new file mode 100755 index 00000000..4bf78720 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/FeederActions.java @@ -0,0 +1,155 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.azib.ipscan.core.InetAddressUtils; +import net.azib.ipscan.feeders.FeederException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Text; + +/** + * FeederActions + * TODO: tests + * + * @author anton + */ +public class FeederActions { + + private static final Logger LOG = Logger.getLogger(FeederActions.class.getName()); + + public static class HostnameButton implements SelectionListener, TraverseListener { + + private String localHostname; + private Text hostnameText; + private Text ipText; + + public HostnameButton(Text hostnameText, Text ipText) { + this.hostnameText = hostnameText; + this.ipText = ipText; + try { + this.localHostname = InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException e) { + // do nothing... + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + widgetSelected(event); + } + + public void widgetSelected(SelectionEvent event) { + String hostname = hostnameText.getText(); + + String address = null; + if (hostname.equals(localHostname)) { + // retrieve local address(es) + askLocalIPAddress(); + } + else { + // resolve remote address + try { + address = InetAddressUtils.getAddressByName(hostname); + + // now update the hostname itself using a reverse lookup + try { + String realHostname = InetAddress.getByName(address).getCanonicalHostName(); + if (!address.equals(realHostname)) { + // if a hostname was returned, not the same IP adress + hostnameText.setText(realHostname); + hostnameText.setSelection(realHostname.length()); + } + } + catch (UnknownHostException e) { + // ignore if this one fails + } + } + catch (UnknownHostException e) { + throw new FeederException("invalidHostname"); + } + + ipText.setText(address); + } + } + + public void keyTraversed(TraverseEvent e) { + if (e.detail == SWT.TRAVERSE_RETURN) { + widgetSelected(null); + e.doit = false; + } + } + + /** + * Asks user which local IP address they want to use + */ + private void askLocalIPAddress() { + try { + Menu popupMenu = new Menu(Display.getCurrent().getActiveShell(), SWT.POP_UP); + Listener menuItemListener = new Listener() { + public void handleEvent(Event event) { + MenuItem menuItem = (MenuItem) event.widget; + String address = (String) menuItem.getData(); + ipText.setText(address); + menuItem.getParent().dispose(); + } + }; + + + for (Enumeration i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements(); ) { + NetworkInterface networkInterface = (NetworkInterface) i.nextElement(); + for (Enumeration i2 = networkInterface.getInetAddresses(); i2.hasMoreElements();) { + InetAddress currentAddress = (InetAddress) i2.nextElement(); + // TODO: we would benefit of Java 1.6 here by automatically initializing the netmask, too + + if (!currentAddress.isLoopbackAddress()) { + MenuItem menuItem = new MenuItem(popupMenu, 0); + menuItem.setText(networkInterface.getDisplayName() + ": " + currentAddress.getHostAddress()); + menuItem.setData(currentAddress.getHostAddress()); + menuItem.addListener(SWT.Selection, menuItemListener); + } + } + } + + if (popupMenu.getItemCount() > 1) { + popupMenu.setLocation(Display.getCurrent().getCursorLocation()); + popupMenu.setVisible(true); + } + else { + // emulate click on the single menu item + if (popupMenu.getItemCount() == 1) { + Event event = new Event(); + event.widget = popupMenu.getItem(0); + menuItemListener.handleEvent(event); + popupMenu.dispose(); + } + // otherwise, unable to retrieve any sane local addresses, + // leave the field as-is, which probably shows the loopback address already + } + } + catch (SocketException e) { + LOG.log(Level.FINE, "Cannot enumerate network interfaces", e); + } + } + } + +} + diff --git a/ipscan/src/net/azib/ipscan/gui/actions/FileActions.java b/ipscan/src/net/azib/ipscan/gui/actions/FileActions.java new file mode 100755 index 00000000..e183dc1d --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/FileActions.java @@ -0,0 +1,124 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.ScanningResult; +import net.azib.ipscan.exporters.ExportProcessor; +import net.azib.ipscan.exporters.Exporter; +import net.azib.ipscan.exporters.ExporterRegistry; +import net.azib.ipscan.exporters.ExportProcessor.ScanningResultSelector; +import net.azib.ipscan.gui.ResultTable; +import net.azib.ipscan.gui.StatusBar; +import net.azib.ipscan.gui.UserErrorException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Listener; + +/** + * FileActions + * + * @author anton + */ +public class FileActions { + + public static class Exit implements Listener { + public void handleEvent(Event event) { + event.display.getActiveShell().close(); + } + } + + private static class SaveResults implements Listener { + private ExporterRegistry exporterRegistry; + private ResultTable resultTable; + private StatusBar statusBar; + private boolean isSelection; + + private SaveResults(ExporterRegistry exporterRegistry, ResultTable resultTable, StatusBar statusBar, boolean isSelection) { + this.exporterRegistry = exporterRegistry; + this.resultTable = resultTable; + this.statusBar = statusBar; + // TODO: implement isSelection + this.isSelection = isSelection; + } + + public void handleEvent(Event event) { + if (resultTable.getItemCount() <= 0) { + throw new UserErrorException("commands.noResults"); + } + + // create the file dialog + FileDialog fileDialog = new FileDialog(resultTable.getShell(), SWT.SAVE); + + // gather lists of extensions and exporter names + List extensions = new ArrayList(); + List descriptions = new ArrayList(); + StringBuffer labelBuffer = new StringBuffer(Labels.getLabel(isSelection ? "title.saveSelection" : "title.saveAll")); + addFileExtensions(extensions, descriptions, labelBuffer); + + // initialize other stuff + fileDialog.setText(labelBuffer.toString()); + fileDialog.setFilterExtensions((String[]) extensions.toArray(new String[extensions.size()])); + fileDialog.setFilterNames((String[]) descriptions.toArray(new String[descriptions.size()])); + + // show the dialog and receive the filename + String fileName = fileDialog.open(); + + // check the received file name + if (fileName != null) { + // create exporter instance + Exporter exporter = exporterRegistry.createExporter(fileName); + + statusBar.setStatusText(Labels.getLabel("state.saving")); + + ExportProcessor exportProcessor = new ExportProcessor(exporter, fileName); + + // in case of isSelection we need to create our ScanningResultSelector + ScanningResultSelector scanningResultSelector = null; + if (isSelection) { + scanningResultSelector = new ScanningResultSelector() { + public boolean isResultSelected(int index, ScanningResult result) { + return resultTable.isSelected(index); + } + }; + } + + exportProcessor.process(resultTable.getScanningResults(), resultTable.getFeederInfo(), scanningResultSelector); + + statusBar.setStatusText(null); + } + } + + private void addFileExtensions(List extensions, List descriptions, StringBuffer sb) { + sb.append(" ("); + for (Iterator i = exporterRegistry.iterator(); i.hasNext(); ) { + Exporter exporter = (Exporter) i.next(); + extensions.add("*." + exporter.getFilenameExtension()); + sb.append(exporter.getFilenameExtension()).append(", ");; + descriptions.add(Labels.getLabel(exporter.getLabel())); + } + // strip the last comma + sb.delete(sb.length() - 2, sb.length()); + sb.append(")"); + } + } + + public static class SaveAll extends SaveResults { + public SaveAll(ExporterRegistry exporterRegistry, ResultTable resultTable, StatusBar statusBar) { + super(exporterRegistry, resultTable, statusBar, false); + } + } + + public static class SaveSelection extends SaveResults { + public SaveSelection(ExporterRegistry exporterRegistry, ResultTable resultTable, StatusBar statusBar) { + super(exporterRegistry, resultTable, statusBar, true); + } + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/GotoActions.java b/ipscan/src/net/azib/ipscan/gui/actions/GotoActions.java new file mode 100755 index 00000000..d6ba6577 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/GotoActions.java @@ -0,0 +1,153 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.util.Iterator; +import java.util.List; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.ScanningResult; +import net.azib.ipscan.core.ScanningResultList; +import net.azib.ipscan.core.ScanningSubject; +import net.azib.ipscan.gui.InputDialog; +import net.azib.ipscan.gui.ResultTable; +import net.azib.ipscan.gui.StatusBar; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; + +/** + * GotoActions + * + * @author anton + */ +public class GotoActions { + + private static class NextHost implements Listener { + + private ResultTable resultTable; + private int whatToSearchFor; + + NextHost(ResultTable resultTable, int whatToSearchFor) { + this.resultTable = resultTable; + this.whatToSearchFor = whatToSearchFor; + } + + public void handleEvent(Event event) { + ScanningResultList results = resultTable.getScanningResults(); + + int numElements = resultTable.getItemCount(); + int startElement = resultTable.getSelectionIndex() + 1; + + for (int i = startElement; i < numElements; i++) { + ScanningResult scanningResult = results.getResult(i); + + if (scanningResult.getType() >= whatToSearchFor) { + resultTable.setSelection(i); + resultTable.setFocus(); + return; + } + + } + + if (startElement > 0) { + resultTable.deselectAll(); + handleEvent(event); + } + } + + } + + public static class NextAliveHost extends NextHost { + public NextAliveHost(ResultTable resultTable) { + super(resultTable, ScanningSubject.RESULT_TYPE_ALIVE); + } + } + + public static class NextDeadHost extends NextHost { + public NextDeadHost(ResultTable resultTable) { + super(resultTable, ScanningSubject.RESULT_TYPE_DEAD); + } + } + + public static class NextHostWithInfo extends NextHost { + public NextHostWithInfo(ResultTable resultTable) { + super(resultTable, ScanningSubject.RESULT_TYPE_ADDITIONAL_INFO); + } + } + + public static class Find implements Listener { + + private ResultTable resultTable; + private StatusBar statusBar; + private String lastText = ""; + + public Find(StatusBar statusBar, ResultTable resultTable) { + this.statusBar = statusBar; + this.resultTable = resultTable; + } + + public void handleEvent(Event event) { + InputDialog dialog = new InputDialog(Labels.getLabel("title.find"), Labels.getLabel("text.find")); + String text = dialog.open(lastText); + if (text == null) { + return; + } + lastText = text; + + try { + statusBar.setStatusText(Labels.getLabel("state.searching")); + + findText(text, event.display.getActiveShell()); + } + finally { + statusBar.setStatusText(null); + } + } + + private void findText(String text, Shell activeShell) { + ScanningResultList results = resultTable.getScanningResults(); + + int numElements = resultTable.getItemCount(); + int startElement = resultTable.getSelectionIndex() + 1; + + for (int i = startElement; i < numElements; i++) { + ScanningResult scanningResult = results.getResult(i); + + List values = scanningResult.getValues(); + + for (Iterator j = values.iterator(); j.hasNext();) { + String value = (String) j.next(); + + // TODO: case-insensitive search + if (value != null && value.indexOf(text) >= 0) { + resultTable.setSelection(i); + resultTable.setFocus(); + return; + } + } + } + + if (startElement > 0) { + MessageBox messageBox = new MessageBox(activeShell, SWT.YES | SWT.NO | SWT.ICON_QUESTION); + messageBox.setText(Labels.getLabel("title.find")); + messageBox.setMessage(Labels.getLabel("text.find.notFound") + " " + Labels.getLabel("text.find.restart")); + if (messageBox.open() == SWT.YES) { + resultTable.deselectAll(); + findText(text, activeShell); + } + } + else { + MessageBox messageBox = new MessageBox(activeShell, SWT.OK | SWT.ICON_INFORMATION); + messageBox.setText(Labels.getLabel("title.find")); + messageBox.setMessage(Labels.getLabel("text.find.notFound")); + messageBox.open(); + } + } + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/HelpActions.java b/ipscan/src/net/azib/ipscan/gui/actions/HelpActions.java new file mode 100755 index 00000000..db56f87c --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/HelpActions.java @@ -0,0 +1,109 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.config.Version; +import net.azib.ipscan.gui.AboutWindow; +import net.azib.ipscan.gui.GettingStartedWindow; +import net.azib.ipscan.gui.StatusBar; +import net.azib.ipscan.gui.UserErrorException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.MessageBox; + +/** + * HelpActions + * + * @author anton + */ +public class HelpActions { + + public static class GettingStarted implements Listener { + public void handleEvent(Event event) { + new GettingStartedWindow().open(); + } + } + + public static class About implements Listener { + public void handleEvent(Event event) { + new AboutWindow().open(); + } + } + + public static class Website implements Listener { + public void handleEvent(Event event) { + BrowserLauncher.openURL(Version.WEBSITE); + } + } + + public static class Forum implements Listener { + public void handleEvent(Event event) { + BrowserLauncher.openURL(Version.FORUM_URL); + } + } + + public static class Plugins implements Listener { + public void handleEvent(Event event) { + BrowserLauncher.openURL(Version.PLUGINS_URL); + } + } + + public static class CheckVersion implements Listener { + private StatusBar statusBar; + + public CheckVersion(StatusBar statusBar) { + this.statusBar = statusBar; + } + + public void handleEvent(Event event) { + BufferedReader reader = null; + try { + statusBar.setStatusText(Labels.getLabel("state.retrievingVersion")); + + URL url = new URL(Version.LATEST_VERSION_URL); + URLConnection conn = url.openConnection(); + reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String latestVersion = reader.readLine(); + latestVersion = latestVersion.substring(latestVersion.indexOf(' ')+1); + + reader.close(); + + MessageBox messageBox = new MessageBox(event.display.getActiveShell(), SWT.ICON_INFORMATION); + messageBox.setText(Version.FULL_NAME); + + if (!Version.VERSION.equals(latestVersion)) { + String message = Labels.getLabel("text.version.old"); + message = message.replaceFirst("%LATEST", latestVersion); + message = message.replaceFirst("%VERSION", Version.VERSION); + messageBox.setMessage(message); + } + else { + messageBox.setMessage(Labels.getLabel("text.version.latest")); + } + messageBox.open(); + } + catch (Exception e) { + throw new UserErrorException("version.latestFailed", e); + } + finally { + try { + reader.close(); + } + catch (IOException e) {} + + statusBar.setStatusText(null); + } + } + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/OpenerLauncher.java b/ipscan/src/net/azib/ipscan/gui/actions/OpenerLauncher.java new file mode 100755 index 00000000..5329a631 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/OpenerLauncher.java @@ -0,0 +1,91 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.azib.ipscan.config.OpenersConfig.Opener; +import net.azib.ipscan.core.ScanningResultList; +import net.azib.ipscan.fetchers.FetcherRegistry; +import net.azib.ipscan.gui.UserErrorException; + +/** + * OpenerLauncher + * + * @author anton + */ +public class OpenerLauncher { + + private FetcherRegistry fetcherRegistry; + private ScanningResultList scanningResults; + + public OpenerLauncher(FetcherRegistry fetcherRegistry, ScanningResultList scanningResults) { + this.fetcherRegistry = fetcherRegistry; + this.scanningResults = scanningResults; + } + + public void launch(Opener opener, int selectedItem) { + String openerString = prepareOpenerStringForItem(opener.execString, selectedItem); + + // check for URLs + if (openerString.startsWith("http:") || openerString.startsWith("https:") || openerString.startsWith("ftp:") || openerString.startsWith("mailto:") || openerString.startsWith("\\\\")) { + BrowserLauncher.openURL(openerString); + } + else { + // run a process here + try { + if (opener.inTerminal) { + TerminalLauncher.launchInTerminal(openerString, opener.workingDir); + } + else { + // TODO: we probably need to support shell patterns, etc + // TODO: merge launchInTerminal with this code + Runtime.getRuntime().exec(openerString, null, opener.workingDir); + } + } + catch (Exception e) { + Logger.global.log(Level.WARNING, "opener.failed", e); + throw new UserErrorException("opener.failed", openerString); + } + } + } + + /** + * Replaces references to scanned values in an opener string. + * Refefernces look like ${fetcher_label} + * @param openerString + * @return opener string with values replaced + */ + String prepareOpenerStringForItem(String openerString, int selectedItem) { + Pattern paramsPattern = Pattern.compile("\\$\\{(.+?)\\}"); + Matcher matcher = paramsPattern.matcher(openerString); + StringBuffer sb = new StringBuffer(64); + while (matcher.find()) { + // resolve the required fetcher + String fetcherName = matcher.group(1); + int fetcherIndex = fetcherRegistry.getSelectedFetcherIndex(fetcherName); + if (fetcherIndex < 0) { + throw new UserErrorException("opener.unknownFetcher", fetcherName); + } + + // retrieve the scanned value + try { + String scannedValue = getScannedValue(selectedItem, fetcherIndex); + matcher.appendReplacement(sb, scannedValue); + } + catch (Exception e) { + throw new UserErrorException("opener.nullFetcherValue", fetcherName); + } + } + matcher.appendTail(sb); + return sb.toString(); + } + + String getScannedValue(int selectedItem, int fetcherIndex) { + return (String) scanningResults.getResult(selectedItem).getValues().get(fetcherIndex); + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java b/ipscan/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java new file mode 100755 index 00000000..3a67edb6 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java @@ -0,0 +1,137 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.net.InetAddress; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.ScannerThread; +import net.azib.ipscan.core.ScannerThreadFactory; +import net.azib.ipscan.core.ScanningStateCallback; +import net.azib.ipscan.gui.ResultTable; +import net.azib.ipscan.gui.ScanningResultsConsumer; +import net.azib.ipscan.gui.StatusBar; +import net.azib.ipscan.gui.feeders.FeederGUIRegistry; + +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Display; + +/** + * Start/Stop button action class. + * It listens to presses on the buttons as well as updates gui statuses + * + * @author anton + */ +public class StartStopScanningAction implements SelectionListener, ScanningStateCallback { + + private ScannerThreadFactory scannerThreadFactory; + private ScannerThread scannerThread; + + private StatusBar statusBar; + private ResultTable resultTable; + private FeederGUIRegistry feederRegistry; + private Button button; + private Image[] images = new Image[4]; + + private Display display; + + private int state = ScanningStateCallback.STATE_IDLE; + + public StartStopScanningAction(ScannerThreadFactory scannerThreadFactory, ResultTable resultTable, StatusBar statusBar, FeederGUIRegistry feederRegistry, Button startStopButton) { + this.scannerThreadFactory = scannerThreadFactory; + this.resultTable = resultTable; + this.statusBar = statusBar; + this.feederRegistry = feederRegistry; + this.button = startStopButton; + this.display = button.getDisplay(); + + // pre-load button images + images[ScanningStateCallback.STATE_IDLE] = new Image(null, Labels.getInstance().getImageAsStream("button.start.img")); + images[ScanningStateCallback.STATE_SCANNING] = new Image(null, Labels.getInstance().getImageAsStream("button.stop.img")); + images[ScanningStateCallback.STATE_STOPPING] = new Image(null, Labels.getInstance().getImageAsStream("button.kill.img")); + images[ScanningStateCallback.STATE_KILLING] = images[ScanningStateCallback.STATE_STOPPING]; + + // set the defaultimage + button.setImage(images[state]); + } + + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + public void widgetSelected(SelectionEvent e) { + switch (state) { + case ScanningStateCallback.STATE_IDLE: + // start the scan! + resultTable.initNewScan(feederRegistry.current().getInfo()); + ScanningResultsConsumer resultsConsumer = new ScanningResultsConsumer(resultTable); + scannerThread = scannerThreadFactory.createScannerThread(feederRegistry.current().getFeeder()); + scannerThread.setResultsCallback(resultsConsumer); + scannerThread.setStatusCallback(this); + scannerThread.start(); + break; + case ScanningStateCallback.STATE_SCANNING: + scannerThread.forceStop(); + break; + case ScanningStateCallback.STATE_STOPPING: + scannerThread.abort(); + break; + case ScanningStateCallback.STATE_KILLING: + break; + } + } + + public void scannerStateChanged(int status) { + this.state = status; + if (display.isDisposed()) + return; + display.asyncExec(new Runnable() { + public void run() { + if (statusBar.isDisposed()) + return; + + switch (StartStopScanningAction.this.state) { + case STATE_IDLE: + // reset state text + statusBar.setStatusText(null); + statusBar.setProgress(0); + break; + case STATE_STOPPING: + statusBar.setStatusText(Labels.getLabel("state.waitForThreads")); + break; + case STATE_KILLING: + statusBar.setStatusText(Labels.getLabel("state.killingThreads")); + break; + } + // change button image + button.setImage(images[StartStopScanningAction.this.state]); + } + }); + } + + public void updateProgress(final InetAddress currentAddress, final int runningThreads, final int percentageComplete) { + if (display.isDisposed()) + return; + display.asyncExec(new Runnable() { + public void run() { + if (statusBar.isDisposed()) + return; + + if (currentAddress != null) { + statusBar.setStatusText(Labels.getLabel("state.scanning") + currentAddress.getHostAddress()); + } + + statusBar.setRunningThreads(runningThreads); + statusBar.setProgress(percentageComplete); + + // change button image + button.setImage(images[StartStopScanningAction.this.state]); + } + }); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/TerminalLauncher.java b/ipscan/src/net/azib/ipscan/gui/actions/TerminalLauncher.java new file mode 100755 index 00000000..cf9a38a9 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/TerminalLauncher.java @@ -0,0 +1,52 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import java.io.File; +import java.io.FileWriter; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.azib.ipscan.gui.UserErrorException; + +/** + * The cross-platform terminal launcher + * + * @author anton + */ +public class TerminalLauncher { + + /** + * Launches the execString in the terminal. + * Supports Linux/Unix, MacOS, and Windows + * @param execString the command to launch + * @param workingDir the working directory (or null) + */ + public static void launchInTerminal(String execString, File workingDir) { + String osName = System.getProperty("os.name"); + + try { + if (osName.startsWith("Windows")) { + // generate a command file :-) + File batFile = File.createTempFile("launch", ".cmd"); + batFile.deleteOnExit(); + FileWriter writer = new FileWriter(batFile); + writer.write("@rem This is a temporary file generated by Angry IP Scanner\n" + + "@start cmd /k " + execString); + writer.close(); + + Runtime.getRuntime().exec(batFile.getAbsolutePath(), null, workingDir); + } + else { // assume Linux or other Unix + // TODO: maybe gnome-terminal, konsole, and MacOS-specific terminal should be tried as well... + // TODO: it seems that MacOS can use the $TERM environment variable to launch a terminal + Runtime.getRuntime().exec(new String[] {"xterm", "-e", "bash", "-c", execString + ";bash"}, null, workingDir); + } + } + catch (Exception e) { + Logger.global.log(Level.WARNING, "openTerminal.failed", e); + throw new UserErrorException("openTerminal.failed", execString); + } + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/actions/ToolsActions.java b/ipscan/src/net/azib/ipscan/gui/actions/ToolsActions.java new file mode 100755 index 00000000..618980fe --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/actions/ToolsActions.java @@ -0,0 +1,45 @@ +/** + * + */ +package net.azib.ipscan.gui.actions; + +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +import net.azib.ipscan.gui.OptionsWindow; +import net.azib.ipscan.gui.SelectFetchersDialog; + +/** + * ToolsActions + * + * @author anton + */ +public class ToolsActions { + + public static class Options implements Listener { + + private OptionsWindow optionsWindow; + + public Options(OptionsWindow optionsWindow) { + this.optionsWindow = optionsWindow; + } + + public void handleEvent(Event event) { + optionsWindow.open(); + } + } + + public static class SelectFetchers implements Listener { + + private SelectFetchersDialog selectFetchersDialog; + + public SelectFetchers(SelectFetchersDialog selectFetchersDialog) { + this.selectFetchersDialog = selectFetchersDialog; + } + + public void handleEvent(Event event) { + selectFetchersDialog.open(); + } + + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUI.java b/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUI.java new file mode 100755 index 00000000..8cf0308a --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUI.java @@ -0,0 +1,67 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.feeders.Feeder; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +/** + * Base class of feeder GUI classes. + * + * @author anton + */ +public abstract class AbstractFeederGUI extends Composite { + + protected Feeder feeder; + + public AbstractFeederGUI(Composite parent) { + super(parent, SWT.NONE); + setVisible(false); + initialize(); + } + + protected abstract void initialize(); + + /** + * Initializes a Feeder instance using the parameters, provided by the GUI. + * @return initialized feeder instance + */ + public abstract Feeder getFeeder(); + + /** + * @return the feeder name + */ + public String getFeederName() { + return Labels.getLabel(feeder.getLabel()); + } + + /** + * For internal usage, returns the feeder-specific label + */ + protected String getStringLabel(String name) { + return Labels.getLabel(feeder.getLabel() + '.' + name); + } + + /** + * @return the feeder's name and the information about its current settings + */ + public String getInfo() { + // getFeeder() will probably double-initialize the feeder, but it is safer + return getFeederName() + ": " + getFeeder().getInfo(); + } + + /** + * @return serialized settings to a String + */ + public abstract String serialize(); + + /** + * Restores previously serialized settings. + * @param serialized + */ + public abstract void unserialize(String serialized); +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUITest.java b/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUITest.java new file mode 100755 index 00000000..4c1b25a1 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/AbstractFeederGUITest.java @@ -0,0 +1,51 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import org.eclipse.swt.widgets.Shell; + +import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.feeders.RangeFeeder; +import junit.framework.TestCase; + +/** + * AbstractFeederGUITest + * + * @author anton + */ +public class AbstractFeederGUITest extends TestCase { + + private AbstractFeederGUI feederGUI; + + protected void setUp() throws Exception { + feederGUI = new AbstractFeederGUI(new Shell()) { + + protected void initialize() { + } + + public String getFeederName() { + return "Mega Feeder"; + } + + public Feeder getFeeder() { + feeder = new RangeFeeder(); + feeder.initialize(new String[] {"127.0.0.1", "127.0.0.2"}); + return feeder; + } + + public String serialize() { + return ""; + } + + public void unserialize(String serialized) { + } + + }; + } + + public void testGetInfo() { + assertEquals("Mega Feeder: 127.0.0.1 - 127.0.0.2", feederGUI.getInfo()); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java b/ipscan/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java new file mode 100755 index 00000000..4f263c81 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/FeederGUIRegistry.java @@ -0,0 +1,73 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Combo; + +import net.azib.ipscan.config.Config; +import net.azib.ipscan.feeders.FeederException; + +/** + * FeederGUIRegistry + * + * @author anton + */ +public class FeederGUIRegistry { + + private List feederGUIList; + private Combo feederSelectionCombo; + + private AbstractFeederGUI currentFeederGUI; + + public FeederGUIRegistry(AbstractFeederGUI[] allTheFeeders, Combo feederSelectionCombo) { + this.feederGUIList = Arrays.asList(allTheFeeders); + this.feederSelectionCombo = feederSelectionCombo; + this.currentFeederGUI = allTheFeeders[0]; + } + + public AbstractFeederGUI current() { + return currentFeederGUI; + } + + /** + * Select a new indexed feeder GUI + */ + public void select(int newActiveFeeder) { + // hide current feeder + currentFeederGUI.setVisible(false); + + // get new feeder + currentFeederGUI = (AbstractFeederGUI) feederGUIList.get(newActiveFeeder); + Config.getGlobal().activeFeeder = newActiveFeeder; + + // make new feeder visible + currentFeederGUI.setVisible(true); + } + + public Iterator iterator() { + return feederGUIList.iterator(); + } + + /** + * Select the Feeder GUI by its name, while updating the GUI + */ + public void select(String feederName) { + String[] items = feederSelectionCombo.getItems(); + for (int i = 0; i < items.length; i++) { + if (items[i].equals(feederName)) { + // select the feeder if found + feederSelectionCombo.select(i); + feederSelectionCombo.notifyListeners(SWT.Selection, null); + return; + } + } + // if not found + throw new FeederException("No such feeder found: " + feederName); + } +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/FileFeederGUI.java b/ipscan/src/net/azib/ipscan/gui/feeders/FileFeederGUI.java new file mode 100755 index 00000000..1556bcaf --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/FileFeederGUI.java @@ -0,0 +1,102 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.feeders.FileFeeder; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * GUI for initialization of FileFeeder. + * + * @author anton + */ +public class FileFeederGUI extends AbstractFeederGUI { + + private Label fileNameLabel; + private Text fileNameText; + + private Button browseButton; + + public FileFeederGUI(Composite parent) { + super(parent); + } + + protected void initialize() { + feeder = new FileFeeder(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = 3; + formLayout.marginHeight = 3; + formLayout.spacing = 3; + setLayout(formLayout); + + fileNameLabel = new Label(this, SWT.NONE); + fileNameText = new Text(this, SWT.BORDER); + browseButton = new Button(this, SWT.NONE); + + fileNameLabel.setText(getStringLabel("name") + ":"); + FormData formData = new FormData(); + formData.left = new FormAttachment(0); + formData.top = new FormAttachment(fileNameText, 0, SWT.CENTER); + formData.bottom = new FormAttachment(browseButton, 0, SWT.BOTTOM); + fileNameLabel.setLayoutData(formData); + + formData = new FormData(140, SWT.DEFAULT); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(fileNameLabel); + fileNameText.setLayoutData(formData); + + browseButton.setText(getStringLabel("browse")); + formData = new FormData(); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(fileNameText); + formData.height = 22; + browseButton.setLayoutData(formData); + browseButton.addSelectionListener(new SelectionListener() { + + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell()); + dialog.setText(getStringLabel("browse")); + String fileName = dialog.open(); + if (fileName != null) { + fileNameText.setText(fileName); + fileNameText.setSelection(fileName.length()); + } + } + + }); + + pack(); + } + + public Feeder getFeeder() { + ((FileFeeder)feeder).initialize(fileNameText.getText()); + return feeder; + } + + public String serialize() { + return fileNameText.getText(); + } + + public void unserialize(String serialized) { + fileNameText.setText(serialized); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/RandomFeederGUI.java b/ipscan/src/net/azib/ipscan/gui/feeders/RandomFeederGUI.java new file mode 100755 index 00000000..7020b32f --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/RandomFeederGUI.java @@ -0,0 +1,174 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.InetAddressUtils; +import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.feeders.RandomFeeder; +import net.azib.ipscan.gui.actions.FeederActions; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Spinner; +import org.eclipse.swt.widgets.Text; + +/** + * GUI for initialization of RandomFeeder + * + * @author anton + */ +public class RandomFeederGUI extends AbstractFeederGUI { + + private Label ipPrototypeLabel; + private Text ipPrototypeText; + + private Label ipMaskLabel; + private Combo ipMaskCombo; + + private Label hostnameLabel; + private Text hostnameText; + + private Button ipUpButton; + + private Label countLabel; + private Spinner countSpinner; + + + public RandomFeederGUI(Composite parent) { + super(parent); + } + + protected void initialize() { + feeder = new RandomFeeder(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = 3; + formLayout.marginHeight = 3; + formLayout.spacing = 4; + setLayout(formLayout); + + ipPrototypeLabel = new Label(this, SWT.NONE); + ipPrototypeText = new Text(this, SWT.BORDER); + ipMaskLabel = new Label(this, SWT.NONE); + ipMaskCombo = new Combo(this, SWT.NONE); + hostnameText = new Text(this, SWT.BORDER); + hostnameLabel = new Label(this, SWT.NONE); + ipUpButton = new Button(this, SWT.NONE); + countLabel = new Label(this, SWT.NONE); + countSpinner = new Spinner(this, SWT.BORDER); + + ipPrototypeLabel.setText(getStringLabel("prototype")); + FormData formData = new FormData(); + formData.right = new FormAttachment(hostnameLabel, 0, SWT.RIGHT); + formData.top = new FormAttachment(ipPrototypeText, 0, SWT.CENTER); + ipPrototypeLabel.setLayoutData(formData); + + formData = new FormData(105, SWT.DEFAULT); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(ipPrototypeLabel); + ipPrototypeText.setLayoutData(formData); + + ipMaskLabel.setText(getStringLabel("mask")); + formData = new FormData(); + formData.left = new FormAttachment(ipPrototypeText, 3); + formData.top = new FormAttachment(ipPrototypeText, 0, SWT.CENTER); + ipMaskLabel.setLayoutData(formData); + + ipMaskCombo.setVisibleItemCount(10); + // Warning: IPv4 specific netmasks + ipMaskCombo.add("255...128"); + ipMaskCombo.add("255...0"); + ipMaskCombo.add("255..0.0"); + ipMaskCombo.add("255.0.0.0"); + ipMaskCombo.add("0.0.0.0"); + ipMaskCombo.add("255..0.255"); + ipMaskCombo.add("255.0.0.255"); + ipMaskCombo.select(3); + formData = new FormData(105, SWT.DEFAULT); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(ipMaskLabel); + formData.bottom = new FormAttachment(ipPrototypeText, 0, SWT.BOTTOM); + ipMaskCombo.setLayoutData(formData); + + FeederActions.HostnameButton hostnameSelectionListener = new FeederActions.HostnameButton(hostnameText, ipPrototypeText); + try { + hostnameText.setText(InetAddress.getLocalHost().getHostName()); + } + catch (UnknownHostException e1) { + // leave hostnameText empty + } + hostnameText.addTraverseListener(hostnameSelectionListener); + formData = new FormData(105, SWT.DEFAULT); + formData.top = new FormAttachment(ipPrototypeText); + formData.left = new FormAttachment(ipPrototypeText, 0, SWT.LEFT); + hostnameText.setLayoutData(formData); + + hostnameLabel.setText(getStringLabel("hostname")); + formData = new FormData(); + formData.left = new FormAttachment(0); + formData.top = new FormAttachment(hostnameText, 0, SWT.CENTER); + hostnameLabel.setLayoutData(formData); + + ipUpButton.setImage(new Image(getDisplay(), Labels.getInstance().getImageAsStream("button.ipUp.img"))); + ipUpButton.addSelectionListener(hostnameSelectionListener); + formData = new FormData(35, SWT.DEFAULT); + formData.top = new FormAttachment(ipPrototypeText); + formData.left = new FormAttachment(hostnameText); + formData.bottom = new FormAttachment(hostnameText, 0, SWT.BOTTOM); + ipUpButton.setLayoutData(formData); + + countLabel.setText(getStringLabel("count")); + formData = new FormData(); + formData.left = new FormAttachment(ipUpButton, 3); + formData.top = new FormAttachment(hostnameLabel, 0, SWT.TOP); + countLabel.setLayoutData(formData); + + countSpinner.setSelection(100); + countSpinner.setMaximum(100000); + countSpinner.setMinimum(1); + formData = new FormData(); + formData.left = new FormAttachment(countLabel); + formData.top = new FormAttachment(ipUpButton, 0, SWT.CENTER); + formData.right = new FormAttachment(ipMaskCombo, 0, SWT.RIGHT); + countSpinner.setLayoutData(formData); + + // fill the IP text with local IP address + try { + ipPrototypeText.setText(InetAddressUtils.getAddressByName(hostnameText.getText())); + } + catch (UnknownHostException e) { + // don't report any errors on initialization + } + + pack(); + } + + public Feeder getFeeder() { + ((RandomFeeder)feeder).initialize(ipPrototypeText.getText(), ipMaskCombo.getText(), countSpinner.getSelection()); + return feeder; + } + + public String serialize() { + return ipPrototypeText.getText() + ":::" + ipMaskCombo.getText() + ":::" + countSpinner.getSelection(); + } + + public void unserialize(String serialized) { + String[] parts = serialized.split(":::"); + ipPrototypeText.setText(parts[0]); + ipMaskCombo.setText(parts[1]); + countSpinner.setSelection(Integer.parseInt(parts[2])); + } + +} diff --git a/ipscan/src/net/azib/ipscan/gui/feeders/RangeFeederGUI.java b/ipscan/src/net/azib/ipscan/gui/feeders/RangeFeederGUI.java new file mode 100755 index 00000000..6cf15a44 --- /dev/null +++ b/ipscan/src/net/azib/ipscan/gui/feeders/RangeFeederGUI.java @@ -0,0 +1,249 @@ +/** + * + */ +package net.azib.ipscan.gui.feeders; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.logging.Logger; + +import net.azib.ipscan.config.Labels; +import net.azib.ipscan.core.InetAddressUtils; +import net.azib.ipscan.feeders.Feeder; +import net.azib.ipscan.feeders.FeederException; +import net.azib.ipscan.feeders.RangeFeeder; +import net.azib.ipscan.gui.actions.FeederActions; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * GUI for initialization of RangeFeeder. + * + * TODO: delete button doesn't work well in edit fields + * + * @author anton + */ +public class RangeFeederGUI extends AbstractFeederGUI { + + private static final Logger LOG = Logger.getLogger(RangeFeederGUI.class.getName()); + + private Label ipRangeLabel; + private Text startIPText; + + private Label toLabel; + private Text endIPText; + private boolean isEndIPUnedited = true; + + private Label hostnameLabel; + private Text hostnameText; + + private Button ipUpButton; + + private Combo netmaskCombo; + + public RangeFeederGUI(Composite parent) { + super(parent); + } + + protected void initialize() { + feeder = new RangeFeeder(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = 3; + formLayout.marginHeight = 3; + formLayout.marginBottom = 2; + formLayout.spacing = 4; + setLayout(formLayout); + + ipRangeLabel = new Label(this, SWT.NONE); + startIPText = new Text(this, SWT.BORDER); + toLabel = new Label(this, SWT.NONE); + endIPText = new Text(this, SWT.BORDER); + hostnameLabel = new Label(this, SWT.NONE); + hostnameText = new Text(this, SWT.BORDER); + ipUpButton = new Button(this, SWT.NONE); + netmaskCombo = new Combo(this, SWT.NONE); + + ipRangeLabel.setText(getStringLabel("startIP")); + FormData formData = new FormData(); + formData.right = new FormAttachment(hostnameLabel, 0, SWT.RIGHT); + formData.top = new FormAttachment(startIPText, 0, SWT.CENTER); + ipRangeLabel.setLayoutData(formData); + + formData = new FormData(105, SWT.DEFAULT); + formData.top = new FormAttachment(0); + formData.left = new FormAttachment(ipRangeLabel); + startIPText.setLayoutData(formData); + startIPText.addModifyListener(new StartIPModifyListener()); + + toLabel.setText(getStringLabel("endIP")); + formData = new FormData(); + formData.left = new FormAttachment(startIPText); + formData.top = new FormAttachment(startIPText, 0, SWT.CENTER); + toLabel.setLayoutData(formData); + + try { + endIPText.setText(InetAddress.getLocalHost().getHostAddress()); + } + catch (UnknownHostException e) { + // leave endIPText empty + } + formData = new FormData(105, SWT.DEFAULT); + formData.left = new FormAttachment(toLabel); + endIPText.setLayoutData(formData); + endIPText.addKeyListener(new EndIPKeyListener()); + + FeederActions.HostnameButton hostnameListener = new FeederActions.HostnameButton(hostnameText, startIPText) { + public void widgetSelected(SelectionEvent event) { + // raise the flag + isEndIPUnedited = true; + // reset the netmask combo + netmaskCombo.setText(getStringLabel("netmask")); + // now do the stuff + super.widgetSelected(event); + } + }; + try { + hostnameText.setText(InetAddress.getLocalHost().getHostName()); + } + catch (UnknownHostException e1) { + // leave hostnameText empty + } + hostnameText.addTraverseListener(hostnameListener); + formData = new FormData(105, SWT.DEFAULT); + formData.top = new FormAttachment(startIPText); + formData.left = new FormAttachment(startIPText, 0, SWT.LEFT); + hostnameText.setLayoutData(formData); + hostnameText.setToolTipText(Labels.getLabel("feeder.range.hostname.tooltip")); + + hostnameLabel.setText(getStringLabel("hostname")); + formData = new FormData(); + formData.left = new FormAttachment(0); + formData.top = new FormAttachment(hostnameText, 0, SWT.CENTER); + hostnameLabel.setLayoutData(formData); + + ipUpButton.setImage(new Image(getDisplay(), Labels.getInstance().getImageAsStream("button.ipUp.img"))); + ipUpButton.addSelectionListener(hostnameListener); + formData = new FormData(35, SWT.DEFAULT); + formData.top = new FormAttachment(endIPText); + formData.left = new FormAttachment(hostnameText); + formData.bottom = new FormAttachment(hostnameText, 0, SWT.BOTTOM); + ipUpButton.setLayoutData(formData); + + netmaskCombo.setText(getStringLabel("netmask")); + netmaskCombo.setVisibleItemCount(10); + // Warning: IPv4 specific netmasks + netmaskCombo.add("/16"); // TODO: implement these + netmaskCombo.add("/24"); + netmaskCombo.add("/28"); + netmaskCombo.add("255...240"); + netmaskCombo.add("255...224"); + netmaskCombo.add("255...192"); + netmaskCombo.add("255...128"); + netmaskCombo.add("255...0"); + netmaskCombo.add("255..0.0"); + netmaskCombo.add("255.0.0.0"); + NetmaskSelectionListener netmaskSelectionListener = new NetmaskSelectionListener(); + netmaskCombo.addSelectionListener(netmaskSelectionListener); + netmaskCombo.addTraverseListener(netmaskSelectionListener); + formData = new FormData(); + formData.top = new FormAttachment(startIPText); + formData.left = new FormAttachment(ipUpButton, 5); + formData.right = new FormAttachment(endIPText, 0, SWT.RIGHT); + formData.bottom = new FormAttachment(hostnameText, 0, SWT.BOTTOM); + netmaskCombo.setLayoutData(formData); + netmaskCombo.setToolTipText(Labels.getLabel("feeder.range.netmask.tooltip")); + + // fill the IP text with local IP address + try { + startIPText.setText(InetAddressUtils.getAddressByName(hostnameText.getText())); + endIPText.setText(startIPText.getText()); + } + catch (UnknownHostException e) { + // don't report any errors on initialization + LOG.fine(e.toString()); + } + + pack(); + } + + public Feeder getFeeder() { + ((RangeFeeder)feeder).initialize(startIPText.getText(), endIPText.getText()); + return feeder; + } + + public String serialize() { + return startIPText.getText() + ":::" + endIPText.getText(); + } + + public void unserialize(String serialized) { + String[] parts = serialized.split(":::"); + startIPText.setText(parts[0]); + endIPText.setText(parts[1]); + // reset the netmask combo + netmaskCombo.setText(getStringLabel("netmask")); + } + + private final class EndIPKeyListener implements KeyListener { + public void keyPressed(KeyEvent e) { + isEndIPUnedited = false; + } + + public void keyReleased(KeyEvent e) { + } + } + + private final class StartIPModifyListener implements ModifyListener { + public void modifyText(ModifyEvent e) { + if (isEndIPUnedited) { + endIPText.setText(startIPText.getText()); + } + } + } + + private final class NetmaskSelectionListener implements SelectionListener, TraverseListener { + public void widgetDefaultSelected(SelectionEvent event) { + widgetSelected(event); + } + + public void widgetSelected(SelectionEvent event) { + try { + String netmaskString = netmaskCombo.getText(); + InetAddress netmask = InetAddressUtils.parseNetmask(netmaskString); + InetAddress startIP = InetAddress.getByName(startIPText.getText()); + + startIPText.setText(InetAddressUtils.startRangeByNetmask(startIP, netmask).getHostAddress()); + endIPText.setText(InetAddressUtils.endRangeByNetmask(startIP, netmask).getHostAddress()); + isEndIPUnedited = false; + } + catch (UnknownHostException e) { + throw new FeederException("invalidNetmask"); + } + } + + public void keyTraversed(TraverseEvent e) { + if (e.detail == SWT.TRAVERSE_RETURN) { + widgetSelected(null); + e.doit = false; + } + } + } + +} // @jve:decl-index=0:visual-constraint="10,10" diff --git a/ipscan/start.sh b/ipscan/start.sh new file mode 100755 index 00000000..821e962b --- /dev/null +++ b/ipscan/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +su -c 'java -Djava.library.path=../swt/lib:ext/rocksaw/lib -jar dist/ipscan.jar'