├── .gitignore ├── .travis.yml ├── Brownian ├── __init__.py ├── settings.py ├── urls.py ├── view │ ├── __init__.py │ ├── ajax.py │ ├── static │ │ ├── css │ │ │ ├── bootstrap-responsive.css │ │ │ ├── bootstrap-responsive.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.min.css │ │ │ └── site-customizations.css │ │ ├── dajaxice │ │ │ └── dajaxice.core.js │ │ ├── img │ │ │ ├── ajax-loader.gif │ │ │ ├── glyphicons-halflings-white.png │ │ │ ├── glyphicons-halflings.png │ │ │ └── gradient.png │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── d3.v2.min.js │ │ │ ├── graphs.js │ │ │ ├── jquery.min.js │ │ │ └── site.js │ ├── templates │ │ ├── alerts.html │ │ ├── health.html │ │ ├── home.html │ │ └── include │ │ │ ├── head.html │ │ │ └── table.html │ ├── templatetags │ │ ├── __init__.py │ │ └── es_extras.py │ ├── tests.py │ ├── utils │ │ ├── __init__.py │ │ ├── broLogTypes.py │ │ ├── es.py │ │ └── plugins.py │ └── views.py └── wsgi.py ├── COPYING ├── README.md ├── manage.py ├── requirements.txt ├── setup.py └── tests └── data.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | 6 | install: pip install -r requirements.txt --use-mirrors 7 | 8 | services: 9 | - elasticsearch 10 | 11 | before_script: 12 | - sed -ie 's/\/opt\/Brownian\//\/home\/travis\/build\/grigorescu\/Brownian\//' Brownian/settings.py 13 | - curl -s -XPOST localhost:9200/_bulk --data-binary @tests/data.json 14 | - DJANGO_SETTINGS_MODULE="Brownian.settings" python ./manage.py syncdb --noinput 15 | 16 | script: DJANGO_SETTINGS_MODULE="Brownian.settings" nosetests -------------------------------------------------------------------------------- /Brownian/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorescu/Brownian/f05a351728ff7bb753a179a6966e673fb096b53c/Brownian/__init__.py -------------------------------------------------------------------------------- /Brownian/settings.py: -------------------------------------------------------------------------------- 1 | # Common Application Settings 2 | 3 | # How many results per page. 4 | PAGE_SIZE=30 5 | 6 | # Default time range. Options are: "15m", "1h", "4h", "12h", "1d", "2d", "7d", "all" 7 | DEFAULT_TIME_RANGE="1h" 8 | 9 | # URL base for static files - trailing slash, please: 10 | STATIC_URL = '/static/' 11 | 12 | # ElasticSearch settings 13 | 14 | # Hostname and port of your ElasticSearch server 15 | ELASTICSEARCH_SERVER = "localhost:9200" 16 | 17 | # Index name prefix 18 | ELASTICSEARCH_INDEX_PREFIX = "bro" 19 | 20 | # Don't ever show results for these types. 21 | ELASTICSEARCH_IGNORE_TYPES = [ 22 | "communication", 23 | "loaded_scripts", 24 | "notice_alarm", 25 | "notice_policy", 26 | "ssn_exposure", 27 | ] 28 | 29 | # Hide these columns for these types. 30 | ELASTICSEARCH_IGNORE_COLUMNS = { 31 | "conn": ["missed_bytes", ], 32 | "ftp": ["mime_desc", ], 33 | "notice": ["actions", "dropped", "peer_descr", "policy_items", "suppress_for", ], 34 | "notice_alarm": ["actions", "dropped", "peer_descr", "policy_items", "suppress_for", ], 35 | "smtp_entities": ["excerpt", ], 36 | "weird": ["peer"], 37 | } 38 | 39 | # Date/Time stuff 40 | 41 | TIME_ZONE = 'US/Eastern' 42 | 43 | # Database config 44 | 45 | DATABASES = { 46 | 'default': { 47 | 'ENGINE': 'django.db.backends.sqlite3', 48 | # The full path to your SQLite database *file* 49 | 'NAME': '/opt/Brownian/Brownian_temp_data' 50 | }, 51 | } 52 | 53 | DEBUG = True 54 | TEMPLATE_DEBUG = DEBUG 55 | 56 | ADMINS = ( # ('Your Name', 'your_email@example.com'), 57 | ) 58 | 59 | # End of commonly modified settings 60 | # 61 | ################################### 62 | 63 | 64 | MANAGERS = ADMINS 65 | 66 | SESSION_COOKIE_AGE = 300 67 | 68 | LANGUAGE_CODE = 'en-us' 69 | SITE_ID = 1 70 | USE_I18N = False 71 | USE_L10N = False # This isn't used. 72 | USE_TZ = True 73 | 74 | MEDIA_ROOT = '' 75 | MEDIA_URL = '' 76 | STATIC_ROOT = '' 77 | 78 | STATICFILES_DIRS = ( ) 79 | STATICFILES_FINDERS = ( 80 | 'django.contrib.staticfiles.finders.FileSystemFinder', 81 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 82 | 'dajaxice.finders.DajaxiceFinder', 83 | ) 84 | 85 | SECRET_KEY = '62a=4)pj*u&*aj*1d4f+!tpq5uf@!82t2cx(pu7)_12=)afv6$' 86 | TEMPLATE_LOADERS = ( 87 | 'django.template.loaders.filesystem.Loader', 88 | 'django.template.loaders.app_directories.Loader', 89 | 'django.template.loaders.eggs.Loader', 90 | ) 91 | 92 | TEMPLATE_CONTEXT_PROCESSORS = ( 93 | "django.contrib.auth.context_processors.auth", 94 | "django.core.context_processors.debug", 95 | "django.core.context_processors.i18n", 96 | "django.core.context_processors.media", 97 | "django.core.context_processors.static", 98 | "django.contrib.messages.context_processors.messages", 99 | "django.core.context_processors.request", 100 | ) 101 | 102 | MIDDLEWARE_CLASSES = ( 103 | 'django.middleware.common.CommonMiddleware', 104 | 'django.contrib.sessions.middleware.SessionMiddleware', 105 | 'django.middleware.csrf.CsrfViewMiddleware', 106 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 107 | 'django.contrib.messages.middleware.MessageMiddleware', 108 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 109 | ) 110 | 111 | ROOT_URLCONF = 'Brownian.urls' 112 | WSGI_APPLICATION = 'Brownian.wsgi.application' 113 | 114 | INSTALLED_APPS = ( 115 | 'Brownian.view', 116 | 'django.contrib.auth', 117 | 'django.contrib.contenttypes', 118 | 'django.contrib.sessions', 119 | 'django.contrib.sites', 120 | 'django.contrib.messages', 121 | 'django.contrib.staticfiles', 122 | 'django.contrib.humanize', 123 | 'dajaxice', 124 | ) 125 | 126 | LOGGING = { 127 | 'version': 1, 128 | 'disable_existing_loggers': False, 129 | 'formatters': { 130 | 'verbose': { 131 | 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' 132 | }, 133 | 'simple': { 134 | 'format': '%(levelname)s %(message)s' 135 | }, 136 | }, 137 | 'handlers': { 138 | 'mail_admins': { 139 | 'level': 'ERROR', 140 | 'class': 'django.utils.log.AdminEmailHandler' 141 | }, 142 | 'console':{ 143 | 'level':'DEBUG', 144 | 'class':'logging.StreamHandler', 145 | 'formatter': 'simple' 146 | }, 147 | }, 148 | 'loggers': { 149 | 'django.request': { 150 | 'handlers': ['mail_admins'], 151 | 'level': 'ERROR', 152 | 'propagate': True, 153 | }, 154 | 'elasticsearch_requests': { 155 | 'handlers': ['console'], 156 | 'level': 'DEBUG', 157 | }, 158 | 'dajaxice': { 159 | 'handlers': ['console'], 160 | 'level': 'ERROR', 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Brownian/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url, include 2 | from dajaxice.core import dajaxice_autodiscover, dajaxice_config 3 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 4 | 5 | dajaxice_autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | url(dajaxice_config.dajaxice_url, include('dajaxice.urls')), 9 | url(r'^$', 'Brownian.view.views.query', name='query'), 10 | url(r'^notices/$', 'Brownian.view.views.alerts', name='alerts'), 11 | url(r'^health/$', 'Brownian.view.views.health', name='health'), 12 | ) 13 | 14 | urlpatterns += staticfiles_urlpatterns() -------------------------------------------------------------------------------- /Brownian/view/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorescu/Brownian/f05a351728ff7bb753a179a6966e673fb096b53c/Brownian/view/__init__.py -------------------------------------------------------------------------------- /Brownian/view/ajax.py: -------------------------------------------------------------------------------- 1 | from dajaxice.decorators import dajaxice_register 2 | from django.template.loader import render_to_string 3 | import utils.es 4 | import requests 5 | import ast 6 | import utils.plugins 7 | 8 | @dajaxice_register 9 | def getData(request, type, query, indices, sort, start=0): 10 | data = {} 11 | 12 | try: 13 | sort = ast.literal_eval(str(sort)) 14 | except ValueError: 15 | raise ValueError(sort) 16 | 17 | try: 18 | result = utils.es.doQuery(utils.es.queryEscape(query), index=indices, type=type, start=start, sort=sort) 19 | except requests.ConnectionError: 20 | return "Error - Could not connect to ElasticSearch server for AJAX query." 21 | data['took'] = result['took'] 22 | sortField, sortOrder = sort.items()[0] 23 | sortOrder = sortOrder['order'] 24 | data['sort'] = {"field": sortField, "order": sortOrder} 25 | data['start'] = start 26 | data['openTab'] = type 27 | data['query'] = query.replace('"', """) 28 | data['indices'] = indices 29 | data['plugin_mapping'] = utils.plugins.mapping 30 | data['total'] = result['hits']['total'] 31 | data['table'] = utils.es.resultToTable(result, type) 32 | return render_to_string("include/table.html", data) 33 | 34 | @dajaxice_register 35 | def updateIndices(request): 36 | try: 37 | indices = utils.es.getIndices() 38 | except requests.ConnectionError: 39 | raise requests.ConnectionError("Error - could not connect to ElasticSearch server to fetch indices.") 40 | request.session['indices'] = indices 41 | return True 42 | 43 | @dajaxice_register 44 | def runPlugin(request, displayName, args): 45 | for plugins in utils.plugins.mapping.values(): 46 | for plugin in plugins: 47 | if plugin["displayName"] == displayName: 48 | return "" + displayName + ": " + plugin["plugin"].run([args]) 49 | return "Error: Plugin not found." -------------------------------------------------------------------------------- /Brownian/view/static/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.0 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | .clearfix { 12 | *zoom: 1; 13 | } 14 | 15 | .clearfix:before, 16 | .clearfix:after { 17 | display: table; 18 | line-height: 0; 19 | content: ""; 20 | } 21 | 22 | .clearfix:after { 23 | clear: both; 24 | } 25 | 26 | .hide-text { 27 | font: 0/0 a; 28 | color: transparent; 29 | text-shadow: none; 30 | background-color: transparent; 31 | border: 0; 32 | } 33 | 34 | .input-block-level { 35 | display: block; 36 | width: 100%; 37 | min-height: 30px; 38 | -webkit-box-sizing: border-box; 39 | -moz-box-sizing: border-box; 40 | box-sizing: border-box; 41 | } 42 | 43 | .hidden { 44 | display: none; 45 | visibility: hidden; 46 | } 47 | 48 | .visible-phone { 49 | display: none !important; 50 | } 51 | 52 | .visible-tablet { 53 | display: none !important; 54 | } 55 | 56 | .hidden-desktop { 57 | display: none !important; 58 | } 59 | 60 | .visible-desktop { 61 | display: inherit !important; 62 | } 63 | 64 | @media (min-width: 768px) and (max-width: 979px) { 65 | .hidden-desktop { 66 | display: inherit !important; 67 | } 68 | .visible-desktop { 69 | display: none !important ; 70 | } 71 | .visible-tablet { 72 | display: inherit !important; 73 | } 74 | .hidden-tablet { 75 | display: none !important; 76 | } 77 | } 78 | 79 | @media (max-width: 767px) { 80 | .hidden-desktop { 81 | display: inherit !important; 82 | } 83 | .visible-desktop { 84 | display: none !important; 85 | } 86 | .visible-phone { 87 | display: inherit !important; 88 | } 89 | .hidden-phone { 90 | display: none !important; 91 | } 92 | } 93 | 94 | @media (min-width: 1200px) { 95 | .row { 96 | margin-left: -30px; 97 | *zoom: 1; 98 | } 99 | .row:before, 100 | .row:after { 101 | display: table; 102 | line-height: 0; 103 | content: ""; 104 | } 105 | .row:after { 106 | clear: both; 107 | } 108 | [class*="span"] { 109 | float: left; 110 | margin-left: 30px; 111 | } 112 | .container, 113 | .navbar-static-top .container, 114 | .navbar-fixed-top .container, 115 | .navbar-fixed-bottom .container { 116 | width: 1170px; 117 | } 118 | .span12 { 119 | width: 1170px; 120 | } 121 | .span11 { 122 | width: 1070px; 123 | } 124 | .span10 { 125 | width: 970px; 126 | } 127 | .span9 { 128 | width: 870px; 129 | } 130 | .span8 { 131 | width: 770px; 132 | } 133 | .span7 { 134 | width: 670px; 135 | } 136 | .span6 { 137 | width: 570px; 138 | } 139 | .span5 { 140 | width: 470px; 141 | } 142 | .span4 { 143 | width: 370px; 144 | } 145 | .span3 { 146 | width: 270px; 147 | } 148 | .span2 { 149 | width: 170px; 150 | } 151 | .span1 { 152 | width: 70px; 153 | } 154 | .offset12 { 155 | margin-left: 1230px; 156 | } 157 | .offset11 { 158 | margin-left: 1130px; 159 | } 160 | .offset10 { 161 | margin-left: 1030px; 162 | } 163 | .offset9 { 164 | margin-left: 930px; 165 | } 166 | .offset8 { 167 | margin-left: 830px; 168 | } 169 | .offset7 { 170 | margin-left: 730px; 171 | } 172 | .offset6 { 173 | margin-left: 630px; 174 | } 175 | .offset5 { 176 | margin-left: 530px; 177 | } 178 | .offset4 { 179 | margin-left: 430px; 180 | } 181 | .offset3 { 182 | margin-left: 330px; 183 | } 184 | .offset2 { 185 | margin-left: 230px; 186 | } 187 | .offset1 { 188 | margin-left: 130px; 189 | } 190 | .row-fluid { 191 | width: 100%; 192 | *zoom: 1; 193 | } 194 | .row-fluid:before, 195 | .row-fluid:after { 196 | display: table; 197 | line-height: 0; 198 | content: ""; 199 | } 200 | .row-fluid:after { 201 | clear: both; 202 | } 203 | .row-fluid [class*="span"] { 204 | display: block; 205 | float: left; 206 | width: 100%; 207 | min-height: 30px; 208 | margin-left: 2.564102564102564%; 209 | *margin-left: 2.5109110747408616%; 210 | -webkit-box-sizing: border-box; 211 | -moz-box-sizing: border-box; 212 | box-sizing: border-box; 213 | } 214 | .row-fluid [class*="span"]:first-child { 215 | margin-left: 0; 216 | } 217 | .row-fluid .span12 { 218 | width: 100%; 219 | *width: 99.94680851063829%; 220 | } 221 | .row-fluid .span11 { 222 | width: 91.45299145299145%; 223 | *width: 91.39979996362975%; 224 | } 225 | .row-fluid .span10 { 226 | width: 82.90598290598291%; 227 | *width: 82.8527914166212%; 228 | } 229 | .row-fluid .span9 { 230 | width: 74.35897435897436%; 231 | *width: 74.30578286961266%; 232 | } 233 | .row-fluid .span8 { 234 | width: 65.81196581196582%; 235 | *width: 65.75877432260411%; 236 | } 237 | .row-fluid .span7 { 238 | width: 57.26495726495726%; 239 | *width: 57.21176577559556%; 240 | } 241 | .row-fluid .span6 { 242 | width: 48.717948717948715%; 243 | *width: 48.664757228587014%; 244 | } 245 | .row-fluid .span5 { 246 | width: 40.17094017094017%; 247 | *width: 40.11774868157847%; 248 | } 249 | .row-fluid .span4 { 250 | width: 31.623931623931625%; 251 | *width: 31.570740134569924%; 252 | } 253 | .row-fluid .span3 { 254 | width: 23.076923076923077%; 255 | *width: 23.023731587561375%; 256 | } 257 | .row-fluid .span2 { 258 | width: 14.52991452991453%; 259 | *width: 14.476723040552828%; 260 | } 261 | .row-fluid .span1 { 262 | width: 5.982905982905983%; 263 | *width: 5.929714493544281%; 264 | } 265 | .row-fluid .offset12 { 266 | margin-left: 105.12820512820512%; 267 | *margin-left: 105.02182214948171%; 268 | } 269 | .row-fluid .offset12:first-child { 270 | margin-left: 102.56410256410257%; 271 | *margin-left: 102.45771958537915%; 272 | } 273 | .row-fluid .offset11 { 274 | margin-left: 96.58119658119658%; 275 | *margin-left: 96.47481360247316%; 276 | } 277 | .row-fluid .offset11:first-child { 278 | margin-left: 94.01709401709402%; 279 | *margin-left: 93.91071103837061%; 280 | } 281 | .row-fluid .offset10 { 282 | margin-left: 88.03418803418803%; 283 | *margin-left: 87.92780505546462%; 284 | } 285 | .row-fluid .offset10:first-child { 286 | margin-left: 85.47008547008548%; 287 | *margin-left: 85.36370249136206%; 288 | } 289 | .row-fluid .offset9 { 290 | margin-left: 79.48717948717949%; 291 | *margin-left: 79.38079650845607%; 292 | } 293 | .row-fluid .offset9:first-child { 294 | margin-left: 76.92307692307693%; 295 | *margin-left: 76.81669394435352%; 296 | } 297 | .row-fluid .offset8 { 298 | margin-left: 70.94017094017094%; 299 | *margin-left: 70.83378796144753%; 300 | } 301 | .row-fluid .offset8:first-child { 302 | margin-left: 68.37606837606839%; 303 | *margin-left: 68.26968539734497%; 304 | } 305 | .row-fluid .offset7 { 306 | margin-left: 62.393162393162385%; 307 | *margin-left: 62.28677941443899%; 308 | } 309 | .row-fluid .offset7:first-child { 310 | margin-left: 59.82905982905982%; 311 | *margin-left: 59.72267685033642%; 312 | } 313 | .row-fluid .offset6 { 314 | margin-left: 53.84615384615384%; 315 | *margin-left: 53.739770867430444%; 316 | } 317 | .row-fluid .offset6:first-child { 318 | margin-left: 51.28205128205128%; 319 | *margin-left: 51.175668303327875%; 320 | } 321 | .row-fluid .offset5 { 322 | margin-left: 45.299145299145295%; 323 | *margin-left: 45.1927623204219%; 324 | } 325 | .row-fluid .offset5:first-child { 326 | margin-left: 42.73504273504273%; 327 | *margin-left: 42.62865975631933%; 328 | } 329 | .row-fluid .offset4 { 330 | margin-left: 36.75213675213675%; 331 | *margin-left: 36.645753773413354%; 332 | } 333 | .row-fluid .offset4:first-child { 334 | margin-left: 34.18803418803419%; 335 | *margin-left: 34.081651209310785%; 336 | } 337 | .row-fluid .offset3 { 338 | margin-left: 28.205128205128204%; 339 | *margin-left: 28.0987452264048%; 340 | } 341 | .row-fluid .offset3:first-child { 342 | margin-left: 25.641025641025642%; 343 | *margin-left: 25.53464266230224%; 344 | } 345 | .row-fluid .offset2 { 346 | margin-left: 19.65811965811966%; 347 | *margin-left: 19.551736679396257%; 348 | } 349 | .row-fluid .offset2:first-child { 350 | margin-left: 17.094017094017094%; 351 | *margin-left: 16.98763411529369%; 352 | } 353 | .row-fluid .offset1 { 354 | margin-left: 11.11111111111111%; 355 | *margin-left: 11.004728132387708%; 356 | } 357 | .row-fluid .offset1:first-child { 358 | margin-left: 8.547008547008547%; 359 | *margin-left: 8.440625568285142%; 360 | } 361 | input, 362 | textarea, 363 | .uneditable-input { 364 | margin-left: 0; 365 | } 366 | .controls-row [class*="span"] + [class*="span"] { 367 | margin-left: 30px; 368 | } 369 | input.span12, 370 | textarea.span12, 371 | .uneditable-input.span12 { 372 | width: 1156px; 373 | } 374 | input.span11, 375 | textarea.span11, 376 | .uneditable-input.span11 { 377 | width: 1056px; 378 | } 379 | input.span10, 380 | textarea.span10, 381 | .uneditable-input.span10 { 382 | width: 956px; 383 | } 384 | input.span9, 385 | textarea.span9, 386 | .uneditable-input.span9 { 387 | width: 856px; 388 | } 389 | input.span8, 390 | textarea.span8, 391 | .uneditable-input.span8 { 392 | width: 756px; 393 | } 394 | input.span7, 395 | textarea.span7, 396 | .uneditable-input.span7 { 397 | width: 656px; 398 | } 399 | input.span6, 400 | textarea.span6, 401 | .uneditable-input.span6 { 402 | width: 556px; 403 | } 404 | input.span5, 405 | textarea.span5, 406 | .uneditable-input.span5 { 407 | width: 456px; 408 | } 409 | input.span4, 410 | textarea.span4, 411 | .uneditable-input.span4 { 412 | width: 356px; 413 | } 414 | input.span3, 415 | textarea.span3, 416 | .uneditable-input.span3 { 417 | width: 256px; 418 | } 419 | input.span2, 420 | textarea.span2, 421 | .uneditable-input.span2 { 422 | width: 156px; 423 | } 424 | input.span1, 425 | textarea.span1, 426 | .uneditable-input.span1 { 427 | width: 56px; 428 | } 429 | .thumbnails { 430 | margin-left: -30px; 431 | } 432 | .thumbnails > li { 433 | margin-left: 30px; 434 | } 435 | .row-fluid .thumbnails { 436 | margin-left: 0; 437 | } 438 | } 439 | 440 | @media (min-width: 768px) and (max-width: 979px) { 441 | .row { 442 | margin-left: -20px; 443 | *zoom: 1; 444 | } 445 | .row:before, 446 | .row:after { 447 | display: table; 448 | line-height: 0; 449 | content: ""; 450 | } 451 | .row:after { 452 | clear: both; 453 | } 454 | [class*="span"] { 455 | float: left; 456 | margin-left: 20px; 457 | } 458 | .container, 459 | .navbar-static-top .container, 460 | .navbar-fixed-top .container, 461 | .navbar-fixed-bottom .container { 462 | width: 724px; 463 | } 464 | .span12 { 465 | width: 724px; 466 | } 467 | .span11 { 468 | width: 662px; 469 | } 470 | .span10 { 471 | width: 600px; 472 | } 473 | .span9 { 474 | width: 538px; 475 | } 476 | .span8 { 477 | width: 476px; 478 | } 479 | .span7 { 480 | width: 414px; 481 | } 482 | .span6 { 483 | width: 352px; 484 | } 485 | .span5 { 486 | width: 290px; 487 | } 488 | .span4 { 489 | width: 228px; 490 | } 491 | .span3 { 492 | width: 166px; 493 | } 494 | .span2 { 495 | width: 104px; 496 | } 497 | .span1 { 498 | width: 42px; 499 | } 500 | .offset12 { 501 | margin-left: 764px; 502 | } 503 | .offset11 { 504 | margin-left: 702px; 505 | } 506 | .offset10 { 507 | margin-left: 640px; 508 | } 509 | .offset9 { 510 | margin-left: 578px; 511 | } 512 | .offset8 { 513 | margin-left: 516px; 514 | } 515 | .offset7 { 516 | margin-left: 454px; 517 | } 518 | .offset6 { 519 | margin-left: 392px; 520 | } 521 | .offset5 { 522 | margin-left: 330px; 523 | } 524 | .offset4 { 525 | margin-left: 268px; 526 | } 527 | .offset3 { 528 | margin-left: 206px; 529 | } 530 | .offset2 { 531 | margin-left: 144px; 532 | } 533 | .offset1 { 534 | margin-left: 82px; 535 | } 536 | .row-fluid { 537 | width: 100%; 538 | *zoom: 1; 539 | } 540 | .row-fluid:before, 541 | .row-fluid:after { 542 | display: table; 543 | line-height: 0; 544 | content: ""; 545 | } 546 | .row-fluid:after { 547 | clear: both; 548 | } 549 | .row-fluid [class*="span"] { 550 | display: block; 551 | float: left; 552 | width: 100%; 553 | min-height: 30px; 554 | margin-left: 2.7624309392265194%; 555 | *margin-left: 2.709239449864817%; 556 | -webkit-box-sizing: border-box; 557 | -moz-box-sizing: border-box; 558 | box-sizing: border-box; 559 | } 560 | .row-fluid [class*="span"]:first-child { 561 | margin-left: 0; 562 | } 563 | .row-fluid .span12 { 564 | width: 100%; 565 | *width: 99.94680851063829%; 566 | } 567 | .row-fluid .span11 { 568 | width: 91.43646408839778%; 569 | *width: 91.38327259903608%; 570 | } 571 | .row-fluid .span10 { 572 | width: 82.87292817679558%; 573 | *width: 82.81973668743387%; 574 | } 575 | .row-fluid .span9 { 576 | width: 74.30939226519337%; 577 | *width: 74.25620077583166%; 578 | } 579 | .row-fluid .span8 { 580 | width: 65.74585635359117%; 581 | *width: 65.69266486422946%; 582 | } 583 | .row-fluid .span7 { 584 | width: 57.18232044198895%; 585 | *width: 57.12912895262725%; 586 | } 587 | .row-fluid .span6 { 588 | width: 48.61878453038674%; 589 | *width: 48.56559304102504%; 590 | } 591 | .row-fluid .span5 { 592 | width: 40.05524861878453%; 593 | *width: 40.00205712942283%; 594 | } 595 | .row-fluid .span4 { 596 | width: 31.491712707182323%; 597 | *width: 31.43852121782062%; 598 | } 599 | .row-fluid .span3 { 600 | width: 22.92817679558011%; 601 | *width: 22.87498530621841%; 602 | } 603 | .row-fluid .span2 { 604 | width: 14.3646408839779%; 605 | *width: 14.311449394616199%; 606 | } 607 | .row-fluid .span1 { 608 | width: 5.801104972375691%; 609 | *width: 5.747913483013988%; 610 | } 611 | .row-fluid .offset12 { 612 | margin-left: 105.52486187845304%; 613 | *margin-left: 105.41847889972962%; 614 | } 615 | .row-fluid .offset12:first-child { 616 | margin-left: 102.76243093922652%; 617 | *margin-left: 102.6560479605031%; 618 | } 619 | .row-fluid .offset11 { 620 | margin-left: 96.96132596685082%; 621 | *margin-left: 96.8549429881274%; 622 | } 623 | .row-fluid .offset11:first-child { 624 | margin-left: 94.1988950276243%; 625 | *margin-left: 94.09251204890089%; 626 | } 627 | .row-fluid .offset10 { 628 | margin-left: 88.39779005524862%; 629 | *margin-left: 88.2914070765252%; 630 | } 631 | .row-fluid .offset10:first-child { 632 | margin-left: 85.6353591160221%; 633 | *margin-left: 85.52897613729868%; 634 | } 635 | .row-fluid .offset9 { 636 | margin-left: 79.8342541436464%; 637 | *margin-left: 79.72787116492299%; 638 | } 639 | .row-fluid .offset9:first-child { 640 | margin-left: 77.07182320441989%; 641 | *margin-left: 76.96544022569647%; 642 | } 643 | .row-fluid .offset8 { 644 | margin-left: 71.2707182320442%; 645 | *margin-left: 71.16433525332079%; 646 | } 647 | .row-fluid .offset8:first-child { 648 | margin-left: 68.50828729281768%; 649 | *margin-left: 68.40190431409427%; 650 | } 651 | .row-fluid .offset7 { 652 | margin-left: 62.70718232044199%; 653 | *margin-left: 62.600799341718584%; 654 | } 655 | .row-fluid .offset7:first-child { 656 | margin-left: 59.94475138121547%; 657 | *margin-left: 59.838368402492065%; 658 | } 659 | .row-fluid .offset6 { 660 | margin-left: 54.14364640883978%; 661 | *margin-left: 54.037263430116376%; 662 | } 663 | .row-fluid .offset6:first-child { 664 | margin-left: 51.38121546961326%; 665 | *margin-left: 51.27483249088986%; 666 | } 667 | .row-fluid .offset5 { 668 | margin-left: 45.58011049723757%; 669 | *margin-left: 45.47372751851417%; 670 | } 671 | .row-fluid .offset5:first-child { 672 | margin-left: 42.81767955801105%; 673 | *margin-left: 42.71129657928765%; 674 | } 675 | .row-fluid .offset4 { 676 | margin-left: 37.01657458563536%; 677 | *margin-left: 36.91019160691196%; 678 | } 679 | .row-fluid .offset4:first-child { 680 | margin-left: 34.25414364640884%; 681 | *margin-left: 34.14776066768544%; 682 | } 683 | .row-fluid .offset3 { 684 | margin-left: 28.45303867403315%; 685 | *margin-left: 28.346655695309746%; 686 | } 687 | .row-fluid .offset3:first-child { 688 | margin-left: 25.69060773480663%; 689 | *margin-left: 25.584224756083227%; 690 | } 691 | .row-fluid .offset2 { 692 | margin-left: 19.88950276243094%; 693 | *margin-left: 19.783119783707537%; 694 | } 695 | .row-fluid .offset2:first-child { 696 | margin-left: 17.12707182320442%; 697 | *margin-left: 17.02068884448102%; 698 | } 699 | .row-fluid .offset1 { 700 | margin-left: 11.32596685082873%; 701 | *margin-left: 11.219583872105325%; 702 | } 703 | .row-fluid .offset1:first-child { 704 | margin-left: 8.56353591160221%; 705 | *margin-left: 8.457152932878806%; 706 | } 707 | input, 708 | textarea, 709 | .uneditable-input { 710 | margin-left: 0; 711 | } 712 | .controls-row [class*="span"] + [class*="span"] { 713 | margin-left: 20px; 714 | } 715 | input.span12, 716 | textarea.span12, 717 | .uneditable-input.span12 { 718 | width: 710px; 719 | } 720 | input.span11, 721 | textarea.span11, 722 | .uneditable-input.span11 { 723 | width: 648px; 724 | } 725 | input.span10, 726 | textarea.span10, 727 | .uneditable-input.span10 { 728 | width: 586px; 729 | } 730 | input.span9, 731 | textarea.span9, 732 | .uneditable-input.span9 { 733 | width: 524px; 734 | } 735 | input.span8, 736 | textarea.span8, 737 | .uneditable-input.span8 { 738 | width: 462px; 739 | } 740 | input.span7, 741 | textarea.span7, 742 | .uneditable-input.span7 { 743 | width: 400px; 744 | } 745 | input.span6, 746 | textarea.span6, 747 | .uneditable-input.span6 { 748 | width: 338px; 749 | } 750 | input.span5, 751 | textarea.span5, 752 | .uneditable-input.span5 { 753 | width: 276px; 754 | } 755 | input.span4, 756 | textarea.span4, 757 | .uneditable-input.span4 { 758 | width: 214px; 759 | } 760 | input.span3, 761 | textarea.span3, 762 | .uneditable-input.span3 { 763 | width: 152px; 764 | } 765 | input.span2, 766 | textarea.span2, 767 | .uneditable-input.span2 { 768 | width: 90px; 769 | } 770 | input.span1, 771 | textarea.span1, 772 | .uneditable-input.span1 { 773 | width: 28px; 774 | } 775 | } 776 | 777 | @media (max-width: 767px) { 778 | body { 779 | padding-right: 20px; 780 | padding-left: 20px; 781 | } 782 | .navbar-fixed-top, 783 | .navbar-fixed-bottom { 784 | margin-right: -20px; 785 | margin-left: -20px; 786 | } 787 | .container-fluid { 788 | padding: 0; 789 | } 790 | .dl-horizontal dt { 791 | float: none; 792 | width: auto; 793 | clear: none; 794 | text-align: left; 795 | } 796 | .dl-horizontal dd { 797 | margin-left: 0; 798 | } 799 | .container { 800 | width: auto; 801 | } 802 | .row-fluid { 803 | width: 100%; 804 | } 805 | .row, 806 | .thumbnails { 807 | margin-left: 0; 808 | } 809 | .thumbnails > li { 810 | float: none; 811 | margin-left: 0; 812 | } 813 | [class*="span"], 814 | .row-fluid [class*="span"] { 815 | display: block; 816 | float: none; 817 | width: auto; 818 | margin-left: 0; 819 | } 820 | .span12, 821 | .row-fluid .span12 { 822 | width: 100%; 823 | -webkit-box-sizing: border-box; 824 | -moz-box-sizing: border-box; 825 | box-sizing: border-box; 826 | } 827 | .input-large, 828 | .input-xlarge, 829 | .input-xxlarge, 830 | input[class*="span"], 831 | select[class*="span"], 832 | textarea[class*="span"], 833 | .uneditable-input { 834 | display: block; 835 | width: 100%; 836 | min-height: 30px; 837 | -webkit-box-sizing: border-box; 838 | -moz-box-sizing: border-box; 839 | box-sizing: border-box; 840 | } 841 | .input-prepend input, 842 | .input-append input, 843 | .input-prepend input[class*="span"], 844 | .input-append input[class*="span"] { 845 | display: inline-block; 846 | width: auto; 847 | } 848 | .modal { 849 | position: fixed; 850 | top: 20px; 851 | right: 20px; 852 | left: 20px; 853 | width: auto; 854 | margin: 0; 855 | } 856 | .modal.fade.in { 857 | top: auto; 858 | } 859 | } 860 | 861 | @media (max-width: 480px) { 862 | .nav-collapse { 863 | -webkit-transform: translate3d(0, 0, 0); 864 | } 865 | .page-header h1 small { 866 | display: block; 867 | line-height: 20px; 868 | } 869 | input[type="checkbox"], 870 | input[type="radio"] { 871 | border: 1px solid #ccc; 872 | } 873 | .form-horizontal .control-group > label { 874 | float: none; 875 | width: auto; 876 | padding-top: 0; 877 | text-align: left; 878 | } 879 | .form-horizontal .controls { 880 | margin-left: 0; 881 | } 882 | .form-horizontal .control-list { 883 | padding-top: 0; 884 | } 885 | .form-horizontal .form-actions { 886 | padding-right: 10px; 887 | padding-left: 10px; 888 | } 889 | .modal { 890 | top: 10px; 891 | right: 10px; 892 | left: 10px; 893 | } 894 | .modal-header .close { 895 | padding: 10px; 896 | margin: -10px; 897 | } 898 | .carousel-caption { 899 | position: static; 900 | } 901 | } 902 | 903 | @media (max-width: 979px) { 904 | body { 905 | padding-top: 0; 906 | } 907 | .navbar-fixed-top, 908 | .navbar-fixed-bottom { 909 | position: static; 910 | } 911 | .navbar-fixed-top { 912 | margin-bottom: 20px; 913 | } 914 | .navbar-fixed-bottom { 915 | margin-top: 20px; 916 | } 917 | .navbar-fixed-top .navbar-inner, 918 | .navbar-fixed-bottom .navbar-inner { 919 | padding: 5px; 920 | } 921 | .navbar .container { 922 | width: auto; 923 | padding: 0; 924 | } 925 | .navbar .brand { 926 | padding-right: 10px; 927 | padding-left: 10px; 928 | margin: 0 0 0 -5px; 929 | } 930 | .nav-collapse { 931 | clear: both; 932 | } 933 | .nav-collapse .nav { 934 | float: none; 935 | margin: 0 0 10px; 936 | } 937 | .nav-collapse .nav > li { 938 | float: none; 939 | } 940 | .nav-collapse .nav > li > a { 941 | margin-bottom: 2px; 942 | } 943 | .nav-collapse .nav > .divider-vertical { 944 | display: none; 945 | } 946 | .nav-collapse .nav .nav-header { 947 | color: #555555; 948 | text-shadow: none; 949 | } 950 | .nav-collapse .nav > li > a, 951 | .nav-collapse .dropdown-menu a { 952 | padding: 9px 15px; 953 | font-weight: bold; 954 | color: #555555; 955 | -webkit-border-radius: 3px; 956 | -moz-border-radius: 3px; 957 | border-radius: 3px; 958 | } 959 | .nav-collapse .btn { 960 | padding: 4px 10px 4px; 961 | font-weight: normal; 962 | -webkit-border-radius: 4px; 963 | -moz-border-radius: 4px; 964 | border-radius: 4px; 965 | } 966 | .nav-collapse .dropdown-menu li + li a { 967 | margin-bottom: 2px; 968 | } 969 | .nav-collapse .nav > li > a:hover, 970 | .nav-collapse .dropdown-menu a:hover { 971 | background-color: #f2f2f2; 972 | } 973 | .navbar-inverse .nav-collapse .nav > li > a:hover, 974 | .navbar-inverse .nav-collapse .dropdown-menu a:hover { 975 | background-color: #111111; 976 | } 977 | .nav-collapse.in .btn-group { 978 | padding: 0; 979 | margin-top: 5px; 980 | } 981 | .nav-collapse .dropdown-menu { 982 | position: static; 983 | top: auto; 984 | left: auto; 985 | display: block; 986 | float: none; 987 | max-width: none; 988 | padding: 0; 989 | margin: 0 15px; 990 | background-color: transparent; 991 | border: none; 992 | -webkit-border-radius: 0; 993 | -moz-border-radius: 0; 994 | border-radius: 0; 995 | -webkit-box-shadow: none; 996 | -moz-box-shadow: none; 997 | box-shadow: none; 998 | } 999 | .nav-collapse .dropdown-menu:before, 1000 | .nav-collapse .dropdown-menu:after { 1001 | display: none; 1002 | } 1003 | .nav-collapse .dropdown-menu .divider { 1004 | display: none; 1005 | } 1006 | .nav-collapse .navbar-form, 1007 | .nav-collapse .navbar-search { 1008 | float: none; 1009 | padding: 10px 15px; 1010 | margin: 10px 0; 1011 | border-top: 1px solid #f2f2f2; 1012 | border-bottom: 1px solid #f2f2f2; 1013 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1014 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1015 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1016 | } 1017 | .navbar .nav-collapse .nav.pull-right { 1018 | float: none; 1019 | margin-left: 0; 1020 | } 1021 | .nav-collapse, 1022 | .nav-collapse.collapse { 1023 | height: 0; 1024 | overflow: hidden; 1025 | } 1026 | .navbar .btn-navbar { 1027 | display: block; 1028 | } 1029 | .navbar-static .navbar-inner { 1030 | padding-right: 10px; 1031 | padding-left: 10px; 1032 | } 1033 | } 1034 | 1035 | @media (min-width: 980px) { 1036 | .nav-collapse.collapse { 1037 | height: auto !important; 1038 | overflow: visible !important; 1039 | } 1040 | } 1041 | -------------------------------------------------------------------------------- /Brownian/view/static/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.0 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /Brownian/view/static/css/site-customizations.css: -------------------------------------------------------------------------------- 1 | /* This file gets loaded last, so add or override any bootstrap CSS settings here.*/ 2 | 3 | body{ 4 | background-attachment: fixed; 5 | } 6 | 7 | .input-xxxlarge { 8 | width: 730px; 9 | } 10 | 11 | #results td { 12 | color:#1E347B; 13 | cursor: pointer; 14 | } 15 | 16 | #results td:hover{ 17 | color:#D14; 18 | } 19 | 20 | .container { 21 | width: 90%; 22 | } 23 | 24 | .popover { 25 | width: 20%; 26 | } 27 | 28 | .popover td{ 29 | white-space: normal; 30 | } 31 | 32 | .modal { 33 | width: 900px; 34 | } 35 | 36 | .chart rect{ 37 | stroke: #555555; 38 | fill: #5bb75b; 39 | } 40 | .tooltip{ 41 | margin-top: 10px; 42 | margin-left: 2px; 43 | } 44 | 45 | tr, td, table{ 46 | white-space: nowrap; 47 | padding: 0; 48 | border-collapse:collapse; 49 | } 50 | 51 | .loader{ 52 | margin-left: 40%; 53 | margin-top: 30%; 54 | } 55 | 56 | .dropdown-menu .sub-menu { 57 | left: 100%; 58 | position: absolute; 59 | top: 0; 60 | visibility: hidden; 61 | margin-top: -1px; 62 | } 63 | 64 | .dropdown-menu li:hover .sub-menu { 65 | visibility: visible; 66 | display: block; 67 | } 68 | 69 | .navbar .sub-menu:before { 70 | border-bottom: 7px solid transparent; 71 | border-left: none; 72 | border-right: 7px solid rgba(0, 0, 0, 0.2); 73 | border-top: 7px solid transparent; 74 | left: -7px; 75 | top: 10px; 76 | } 77 | .navbar .sub-menu:after { 78 | border-top: 6px solid transparent; 79 | border-left: none; 80 | border-right: 6px solid #fff; 81 | border-bottom: 6px solid transparent; 82 | left: 10px; 83 | top: 11px; 84 | left: -6px; 85 | } 86 | 87 | [class^="icon-"], 88 | [class*=" icon-"] { 89 | background-image: url("../img/glyphicons-halflings.png"); 90 | } 91 | 92 | .icon-white, 93 | .nav > .active > a > [class^="icon-"], 94 | .nav > .active > a > [class*=" icon-"], 95 | .dropdown-menu > li > a:hover > [class^="icon-"], 96 | .dropdown-menu > li > a:hover > [class*=" icon-"], 97 | .dropdown-menu > .active > a > [class^="icon-"], 98 | .dropdown-menu > .active > a > [class*=" icon-"] { 99 | background-image: url("../img/glyphicons-halflings-white.png"); 100 | } -------------------------------------------------------------------------------- /Brownian/view/static/dajaxice/dajaxice.core.js: -------------------------------------------------------------------------------- 1 | var Dajaxice = { 2 | Brownian: { 3 | view: { 4 | getData: function(callback_function, argv, custom_settings){ 5 | Dajaxice.call('Brownian.view.getData', 'POST', callback_function, argv, custom_settings); 6 | }, 7 | updateIndices: function(callback_function, argv, custom_settings){ 8 | Dajaxice.call('Brownian.view.updateIndices', 'POST', callback_function, argv, custom_settings); 9 | }, 10 | runPlugin: function(callback_function, argv, custom_settings){ 11 | Dajaxice.call('Brownian.view.runPlugin', 'POST', callback_function, argv, custom_settings); 12 | } 13 | } 14 | }, 15 | 16 | get_cookie: function(name) 17 | { 18 | var cookieValue = null; 19 | if (document.cookie && document.cookie != '') { 20 | var cookies = document.cookie.split(';'); 21 | for (var i = 0; i < cookies.length; i++) { 22 | var cookie = cookies[i].toString().replace(/^\s+/, "").replace(/\s+$/, ""); 23 | // Does this cookie string begin with the name we want? 24 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 25 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 26 | break; 27 | } 28 | } 29 | } 30 | return cookieValue; 31 | }, 32 | 33 | call: function(dajaxice_function, method, dajaxice_callback, argv, custom_settings) 34 | { 35 | var custom_settings = custom_settings || {}, 36 | error_callback = Dajaxice.get_setting('default_exception_callback'); 37 | 38 | if('error_callback' in custom_settings && typeof(custom_settings['error_callback']) == 'function'){ 39 | error_callback = custom_settings['error_callback']; 40 | } 41 | 42 | var send_data = 'argv='+encodeURIComponent(JSON.stringify(argv)); 43 | var oXMLHttpRequest = new XMLHttpRequest; 44 | 45 | oXMLHttpRequest.open(method, applicationPath + 'dajaxice/'+dajaxice_function+'/'); 46 | oXMLHttpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 47 | oXMLHttpRequest.setRequestHeader("X-CSRFToken", Dajaxice.get_cookie('csrftoken')); 48 | oXMLHttpRequest.onreadystatechange = function() { 49 | if (this.readyState == XMLHttpRequest.DONE) { 50 | if(this.responseText == Dajaxice.EXCEPTION || !(this.status in Dajaxice.valid_http_responses())){ 51 | error_callback(); 52 | } 53 | else{ 54 | var response; 55 | try { 56 | response = JSON.parse(this.responseText); 57 | } 58 | catch (exception) { 59 | response = this.responseText; 60 | } 61 | dajaxice_callback(response); 62 | } 63 | } 64 | } 65 | oXMLHttpRequest.send(send_data); 66 | return oXMLHttpRequest; 67 | }, 68 | 69 | setup: function(settings) 70 | { 71 | this.settings = settings; 72 | }, 73 | 74 | get_setting: function(key){ 75 | if(this.settings == undefined || this.settings[key] == undefined){ 76 | return Dajaxice.default_settings[key]; 77 | } 78 | return this.settings[key]; 79 | }, 80 | 81 | valid_http_responses: function(){ 82 | return {200: null, 301: null, 302: null, 304: null} 83 | }, 84 | 85 | EXCEPTION: 'DAJAXICE_EXCEPTION', 86 | default_settings: {'default_exception_callback': function(){ console.log('Dajaxice: Something went wrong.')}} 87 | }; 88 | 89 | window['Dajaxice'] = Dajaxice; 90 | 91 | 92 | 93 | (function(){function n(){this._object=h&&!p?new h:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function a(){return new n}function j(b){a.onreadystatechange&&a.onreadystatechange.apply(b);b.dispatchEvent({type:"readystatechange",bubbles:!1,cancelable:!1,timeStamp:new Date+0})}function o(b){try{b.responseText=b._object.responseText}catch(a){}try{var d;var g=b._object,c=g.responseXML,f=g.responseText;i&&(f&&c&&!c.documentElement&&g.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/))&& 94 | (c=new window.ActiveXObject("Microsoft.XMLDOM"),c.async=!1,c.validateOnParse=!1,c.loadXML(f));d=c&&(i&&0!==c.parseError||!c.documentElement||c.documentElement&&"parsererror"==c.documentElement.tagName)?null:c;b.responseXML=d}catch(h){}try{b.status=b._object.status}catch(k){}try{b.statusText=b._object.statusText}catch(j){}}function l(b){b._object.onreadystatechange=new window.Function}var h=window.XMLHttpRequest,m=!!window.controllers,i=window.document.all&&!window.opera,p=i&&window.navigator.userAgent.match(/MSIE 7.0/); 95 | a.prototype=n.prototype;m&&h.wrapped&&(a.wrapped=h.wrapped);a.UNSENT=0;a.OPENED=1;a.HEADERS_RECEIVED=2;a.LOADING=3;a.DONE=4;a.prototype.readyState=a.UNSENT;a.prototype.responseText="";a.prototype.responseXML=null;a.prototype.status=0;a.prototype.statusText="";a.prototype.priority="NORMAL";a.prototype.onreadystatechange=null;a.onreadystatechange=null;a.onopen=null;a.onsend=null;a.onabort=null;a.prototype.open=function(b,e,d,g,c){delete this._headers;arguments.length<3&&(d=true);this._async=d;var f= 96 | this,h=this.readyState,k=null;if(i&&d){k=function(){if(h!=a.DONE){l(f);f.abort()}};window.attachEvent("onunload",k)}a.onopen&&a.onopen.apply(this,arguments);arguments.length>4?this._object.open(b,e,d,g,c):arguments.length>3?this._object.open(b,e,d,g):this._object.open(b,e,d);this.readyState=a.OPENED;j(this);this._object.onreadystatechange=function(){if(!m||d){f.readyState=f._object.readyState;o(f);if(f._aborted)f.readyState=a.UNSENT;else if(f.readyState==a.DONE){delete f._data;l(f);i&&d&&window.detachEvent("onunload", 97 | k);h!=f.readyState&&j(f);h=f.readyState}}}};a.prototype.send=function(b){a.onsend&&a.onsend.apply(this,arguments);arguments.length||(b=null);if(b&&b.nodeType){b=window.XMLSerializer?(new window.XMLSerializer).serializeToString(b):b.xml;this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml")}this._data=b;a:{this._object.send(this._data);if(m&&!this._async){this.readyState=a.OPENED;for(o(this);this.readyStatea.UNSENT)this._aborted=true;this._object.abort();l(this);this.readyState=a.UNSENT;delete this._data};a.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};a.prototype.getResponseHeader=function(b){return this._object.getResponseHeader(b)};a.prototype.setRequestHeader=function(b,a){if(!this._headers)this._headers={};this._headers[b]=a;return this._object.setRequestHeader(b, 99 | a)};a.prototype.addEventListener=function(a,e,d){for(var g=0,c;c=this._listeners[g];g++)if(c[0]==a&&c[1]==e&&c[2]==d)return;this._listeners.push([a,e,d])};a.prototype.removeEventListener=function(a,e,d){for(var g=0,c;c=this._listeners[g];g++)if(c[0]==a&&c[1]==e&&c[2]==d)break;c&&this._listeners.splice(g,1)};a.prototype.dispatchEvent=function(a){a={type:a.type,target:this,currentTarget:this,eventPhase:2,bubbles:a.bubbles,cancelable:a.cancelable,timeStamp:a.timeStamp,stopPropagation:function(){},preventDefault:function(){}, 100 | initEvent:function(){}};a.type=="readystatechange"&&this.onreadystatechange&&(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[a]);for(var e=0,d;d=this._listeners[e];e++)d[0]==a.type&&!d[2]&&(d[1].handleEvent||d[1]).apply(this,[a])};a.prototype.toString=function(){return"[object XMLHttpRequest]"};a.toString=function(){return"[XMLHttpRequest]"};window.Function.prototype.apply||(window.Function.prototype.apply=function(a,e){e||(e=[]);a.__func=this;a.__func(e[0],e[1],e[2],e[3], 101 | e[4]);delete a.__func});window.XMLHttpRequest=a})(); 102 | 103 | 104 | 105 | 106 | var JSON;JSON||(JSON={}); 107 | (function(){function k(a){return 10>a?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return"string"===typeof c?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function m(a,j){var c,d,h,n,g=e,f,b=j[a];b&&("object"===typeof b&&"function"===typeof b.toJSON)&&(b=b.toJSON(a));"function"===typeof i&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null"; 108 | e+=l;f=[];if("[object Array]"===Object.prototype.toString.apply(b)){n=b.length;for(c=0;cr.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){s.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(r[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f=e.Event("slide",{relatedTarget:i[0]});this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u]();if(i.hasClass("active"))return;if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}},e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e(function(){e("body").on("click.carousel.data-api","[data-slide]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=!i.data("modal")&&e.extend({},i.data(),n.data());i.carousel(s),t.preventDefault()})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning)return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning)return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=typeof n=="object"&&n;i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e(function(){e("body").on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})})}(window.jQuery),!function(e){"use strict";function r(){i(e(t)).removeClass("open")}function i(t){var n=t.attr("data-target"),r;return n||(n=t.attr("href"),n=n&&n.replace(/.*(?=#[^\s]*$)/,"")),r=e(n),r.length||(r=t.parent()),r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||(s.toggleClass("open"),n.focus()),!1},keydown:function(t){var n,r,s,o,u,a;if(!/(38|40|27)/.test(t.keyCode))return;n=e(this),t.preventDefault(),t.stopPropagation();if(n.is(".disabled, :disabled"))return;o=i(n),u=o.hasClass("open");if(!u||u&&t.keyCode==27)return n.click();r=e("[role=menu] li:not(.divider) a",o);if(!r.length)return;a=r.index(r.filter(":focus")),t.keyCode==38&&a>0&&a--,t.keyCode==40&&a').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,e.proxy(this.removeBackdrop,this)):this.removeBackdrop()):t&&t()}},e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e(function(){e("body").on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,this.options.trigger=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):this.options.trigger!="manual"&&(i=this.options.trigger=="hover"?"mouseenter":"focus",s=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this))),this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,t,this.$element.data()),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var e,t,n,r,i,s,o;if(this.hasContent()&&this.enabled){e=this.tip(),this.setContent(),this.options.animation&&e.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,t=/in/.test(s),e.remove().css({top:0,left:0,display:"block"}).appendTo(t?this.$element:document.body),n=this.getPosition(t),r=e[0].offsetWidth,i=e[0].offsetHeight;switch(t?s.split(" ")[1]:s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}e.css(o).addClass(s).addClass("in")}},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function r(){var t=setTimeout(function(){n.off(e.support.transition.end).remove()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.remove()})}var t=this,n=this.tip();return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?r():n.remove(),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(t){return e.extend({},t?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}},e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
',trigger:"hover",title:"",delay:0,html:!0}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content > *")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-content")||(typeof n.content=="function"?n.content.call(t[0]):n.content),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}}),e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

'})}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var t=e(this),n=t.data("target")||t.attr("href"),r=/^#\w/.test(n)&&e(n);return r&&r.length&&[[r.position().top,n]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}},e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active a").last()[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}},e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e(function(){e("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))},e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); -------------------------------------------------------------------------------- /Brownian/view/static/js/graphs.js: -------------------------------------------------------------------------------- 1 | function displayNumber(x) { 2 | // Simple function to denote millions (M) and thousands (K). 3 | // TODO: Add a decimal point or two to M/K? 4 | 5 | if (x > 1000000) {return Math.floor(x/1000000) + "M";} 6 | if (x > 1000) {return Math.floor(x/1000) + "K";} 7 | return x; 8 | } 9 | 10 | function createHistogram(orig, name, title) 11 | { 12 | // Creates a histogram style SVG graph at object with id name with data from orig and title. 13 | 14 | var width = 900; // Graph width 15 | var height = 400; // Graph height 16 | 17 | var data = []; // Orig is a JSON object, and is split up into 18 | var labels = []; // these arrays by key/value. 19 | d3.map(orig).forEach(function (d, i) { data.push(i["count"]); labels.push(i["time"]);}); 20 | 21 | var chart = d3.select("#" + name) // Select the right object, 22 | .append("svg") // add an SVG to it, 23 | .attr("class", "chart").attr("width", width).attr("height", height); // and create a chart. 24 | 25 | var x = d3.scale.ordinal() 26 | .domain(labels) 27 | .rangeBands([0, width]); // Split the keys up into distinct bands. 28 | 29 | var y = d3.scale.linear() 30 | .domain([0, d3.max(data)]) 31 | .range([height, 25]); // y = 0 is at the top of the graph, so we scale and flip the value. 32 | 33 | chart.append("line") // Create a line 34 | .attr("x1", 0).attr("x2", width) // going across the graph 35 | .attr("y1", height).attr("y2", height) // at the bottom 36 | .style("stroke", "#aaa"); 37 | 38 | chart.selectAll("rect").data(data).enter() // Create the bars 39 | .append("a") // with links 40 | .attr("xlink:href", function(d, i) {return "/query";}) // that link to /query. TODO 41 | .append("rect").attr("x", x).attr("y", height) // The bars start at the bottom 42 | .attr("height", 0) // with no height for now 43 | .attr("width", x.rangeBand() - 3) // leave 3px of padding between them 44 | .attr("rel", "tooltip_top") // and add a tooltip with the value. 45 | .attr("data-original-title", function(d, i) {return displayNumber(data[i]);}); 46 | 47 | chart.append("svg:text") // Give us a title 48 | .attr("x", width/3) 49 | .attr("y", 15) 50 | .attr("font-size", 16) 51 | .text(title); 52 | 53 | chart.selectAll("rect").data(data) 54 | .transition().duration(1000) // Finally, create a 1-second transition 55 | .attr("height", height).attr("y", y); // of the bars rising up to their real height. 56 | } 57 | -------------------------------------------------------------------------------- /Brownian/view/static/js/site.js: -------------------------------------------------------------------------------- 1 | /** Local JS functions **/ 2 | 3 | function appendToQuery(filter, negated, query, operator){ 4 | $('.dropdown.open .dropdown-toggle').dropdown('toggle'); 5 | 6 | if (operator == undefined){ 7 | operator = "AND" 8 | } 9 | if (negated == undefined){ 10 | negated = false; 11 | } 12 | 13 | if (query == undefined){ 14 | query = "#querytext"; 15 | } 16 | 17 | if ($(query) == undefined){ 18 | return false; 19 | } 20 | 21 | var currentQuery = $(query).val(); 22 | var newQuery = ''; 23 | if (negated){ 24 | newQuery = '!'; 25 | } 26 | newQuery += filter; 27 | if (currentQuery != "*" && currentQuery != ""){ 28 | newQuery = currentQuery + ' ' + operator + ' ' + newQuery; 29 | } 30 | $(query).val(newQuery); 31 | return true; 32 | } 33 | 34 | function replaceQuery(query, filter, negated){ 35 | $('.dropdown.open .dropdown-toggle').dropdown('toggle'); 36 | 37 | if ($(query) == undefined){ 38 | return false; 39 | } 40 | if (negated == undefined){ 41 | negated = false; 42 | } 43 | var newQuery = filter; 44 | if (negated){ 45 | $(query).val('!' + newQuery); 46 | } 47 | else { 48 | $(query).val(newQuery); 49 | } 50 | return true; 51 | } 52 | 53 | function ipanywhere(ip){ 54 | return '(bound:"' + ip + '" OR dst:"' + ip + '" OR dst_addr:"' + ip + '" OR host:"' + ip + '" OR id.orig_h:"' + ip + '" OR id.resp_h:"' + ip + '" OR request:"' + ip + '" OR src:"' + ip + '" OR src_addr:"' + ip + '" OR x_originating_ip:"' + ip + '")' 55 | } 56 | 57 | function exportRow(rowNumber){ 58 | var keys = new Array(0); 59 | var values = new Array(0); 60 | var count = 0; 61 | 62 | $('th > a[rel="popover"]').each(function(index, value) { keys.push($(this).html());} ); 63 | $('#results > table > tbody > tr:eq(' + rowNumber + ') > td[class="fieldval"] > ul > li > a').each(function(index, value) { 64 | var value = $(this).html(); 65 | if ( $(this).attr("title") ) 66 | value = $(this).attr("title"); 67 | values.push(value.replace('', '').replace(/(^\s*)|(\s*$)/gi,"")); 68 | } ); 69 | 70 | result = ''; 71 | for (var i = 0; i < keys.length; i++) { 72 | if (i < values.length){ 73 | if (/([0-9]|[A-Z]|[a-z])/.test(values[i])){ 74 | result += keys[i] + ": " + values[i] + "\n"; 75 | count += 1; 76 | } 77 | } 78 | } 79 | 80 | result = ''; 83 | return result; 84 | } 85 | 86 | function displayPluginOutput(output){ 87 | $('#mainDiv').prepend('
    ' + output + '
    '); 88 | } 89 | 90 | function runPlugin(displayName, args){ 91 | $('.dropdown.open .dropdown-toggle').dropdown('toggle'); 92 | Dajaxice.Brownian.view.runPlugin(displayPluginOutput, {'displayName': displayName, 'args': args}); 93 | } 94 | 95 | function replaceSort(tab, value, direction){ 96 | var replacement = '{"' + value + '": {"order": "' + direction + "\"}}'});"; 97 | var action = $(tab).attr('onclick').replace(/'sort': .*/, "'sort': '" + replacement); 98 | eval(action); 99 | 100 | return true; 101 | } 102 | -------------------------------------------------------------------------------- /Brownian/view/templates/alerts.html: -------------------------------------------------------------------------------- 1 | {% extends "include/head.html" %} 2 | {% load humanize %} 3 | {% block title %}Alerted IPs{% endblock %} 4 | {% block container %} 5 | {% load staticfiles %} 6 |
    7 |
     
    8 | {% if error %} 9 |
    10 | 11 | Error! {{ error }} 12 |
    13 | {% else %} 14 |
    15 | 29 |
    30 |
    31 |
    32 |

    Top Notice IP Addresses

    33 | 34 | 35 | 36 | {% url query as url_query %} 37 | {% for ip in facets.ips.terms %} 38 | 39 | {% endfor %} 40 | 41 |
    IPCount
    {{ ip.term }}{{ ip.count }}
    42 |
    43 | 44 |
    45 |

    Top Notice Ports

    46 | 47 | 48 | 49 | {% url query as url_query %} 50 | {% for port in facets.ports.terms %} 51 | 52 | {% endfor %} 53 | 54 |
    PortCount
    {{ port.term }}{{ port.count }}
    55 |
    56 | {% endif %} 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /Brownian/view/templates/health.html: -------------------------------------------------------------------------------- 1 | {% extends "include/head.html" %} 2 | {% load humanize %} 3 | {% load es_extras %} 4 | {% block title %}Health{% endblock %} 5 | {% block container %} 6 | {% load staticfiles %} 7 |
    8 | {% if error %} 9 |
    10 | 11 | Error! {{ error }} 12 |
    13 | {% else %} 14 |
    15 |
    16 |

    Cluster Health

    17 | 18 | 19 | {% for key, value in health.items %} 20 | 21 | {% endfor %} 22 | 23 |
    {{ key }}{{ value }}
    24 |
    25 | 26 |
    27 |

    Node Health

    28 | 29 | 30 | 31 | 32 | 33 | {% for node_name, node in nodes.items %} 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | {% endfor %} 44 | 45 |
    NodeUptimeLoadFree MemUsed SwapAvailable Disk
    {{ node.name }}{{ node.os.uptime|truncatewords:2 }}{{ node.os.load_average.0|floatformat:2 }}, {{ node.os.load_average.1|floatformat:2 }}, {{ node.os.load_average.2|floatformat:2 }}{{ node.os.mem.free_percent }}%{{ node.os.swap.used_in_bytes|filesizeformat }} 41 | {{ node.fs.items.1.1|sumAvailable|filesizeformat }} 42 |
    46 |
    47 | 48 |
    49 |

    Shard Failures

    50 | {% if shards.es_shards.failures %} 51 | 52 | 53 | 54 | 55 | 56 | {% for failure in shards.es_shards.failures %} 57 | 58 | {% endfor %} 59 | 60 |
    Index (Shard)Reason
    {{ failure.index }} ({{ failure.shard }}){{ failure.reason }}
    61 | {% else %} 62 | No shard failures. 63 | {% endif %} 64 |
    65 | {% endif %} 66 | {% endblock %} 67 | -------------------------------------------------------------------------------- /Brownian/view/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "include/head.html" %} 2 | {% load humanize %} 3 | {% block title %}Query{% endblock %} 4 | {% block container %} 5 | {% load staticfiles %} 6 |
    7 | 27 |
    28 | {% if error %} 29 |
    30 | 31 | Error! {{ error }} 32 |
    33 | {% else %} 34 | 47 | 65 | 72 | {% endif %} 73 | {% endblock %} -------------------------------------------------------------------------------- /Brownian/view/templates/include/head.html: -------------------------------------------------------------------------------- 1 | {% load dajaxice_templatetags %} 2 | 3 | 4 | 5 | {% load staticfiles %} 6 | 7 | 8 | 9 | 10 | 11 | {% dajaxice_js_import %} 12 | Brownian - {% block title %}{% endblock %} 13 | 14 | 15 | 42 |
    43 | {% block container %} 44 | {% endblock %} 45 |
    46 | 47 | -------------------------------------------------------------------------------- /Brownian/view/templates/include/table.html: -------------------------------------------------------------------------------- 1 | {% load es_extras %} 2 | {% load humanize %} 3 | {% if error %} 4 |
    5 | 6 | Error! {{ error }} 7 |
    8 | {% endif %} 9 | 20 | 21 | 22 | {% for attr, type, desc in table.header %} 23 | 45 | {% endfor %} 46 | 47 | {% for row in table.content %} 48 | 49 | {% for key, type, val in row %} 50 | 67 | {% endfor %}{% endfor %}
    {{ attr }}
    24 | {% if type == "time" or type == "port" or type == "transport_proto" or type == "count"%} 25 | 32 | 33 | 40 | 41 | {% else %} 42 |   43 | {% endif %} 44 |
    51 |
    68 | 69 | {% paginate start total openTab query indices sort.field sort.order %} 70 | 74 |

    {{ took }}ms.

    -------------------------------------------------------------------------------- /Brownian/view/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorescu/Brownian/f05a351728ff7bb753a179a6966e673fb096b53c/Brownian/view/templatetags/__init__.py -------------------------------------------------------------------------------- /Brownian/view/templatetags/es_extras.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.conf import settings 3 | import datetime 4 | import pytz 5 | 6 | register = template.Library() 7 | 8 | @register.filter(name='dateToDatetimeWithoutYear') 9 | def dateToDatetimeWithoutYear(value): 10 | """Don't include the year - useful for timestamps and other situations where the year is implied.""" 11 | result = dateToDatetime(value) 12 | if not result: 13 | return "" 14 | else: 15 | return result.strftime('%a %b %d %H:%M:%S.%f')[:-3] 16 | 17 | @register.filter(name='dateToDatetimeWithYear') 18 | def dateToDatetimeWithYear(value): 19 | """Include the year - useful for SSL cert before/after dates.""" 20 | result = dateToDatetime(value) 21 | if not result: 22 | return "" 23 | else: 24 | return result.strftime('%a %b %d %Y %H:%M:%S.%f')[:-3] 25 | 26 | def dateToDatetime(value): 27 | """Converts milliseconds since epoch that ElasticSearch uses to printable string .""" 28 | if not value: 29 | return "" 30 | date = datetime.datetime.utcfromtimestamp(float(str(value))/1000) 31 | return pytz.utc.localize(date).astimezone(pytz.timezone(settings.TIME_ZONE)) 32 | 33 | @register.filter(name='sumAvailable') 34 | def sumAvailable(value): 35 | """Sum available_in_bytes over all partitions.""" 36 | result = [x['available_in_bytes'] for x in value] 37 | return sum(result) 38 | 39 | @register.filter(name='hexEncode') 40 | def hexEncode(value): 41 | """Some replaces.""" 42 | if isinstance(value, unicode): 43 | value = value.encode('ascii', 'backslashreplace') 44 | return value 45 | 46 | @register.filter(name='tsRange') 47 | def tsRange(ts, value): 48 | """Converts timestamp to range[ts - value TO ts + value] with value in millis.""" 49 | if not value or not ts: 50 | return "" 51 | 52 | time = int(ts) 53 | val = int(value) 54 | 55 | return "[%d TO %d]" % (time - val, time + val) 56 | 57 | def genPagination(parser, token): 58 | """Generates pagination given the current location, and the total number of items.""" 59 | 60 | try: 61 | tokens = token.split_contents() 62 | tag_name = tokens[0] 63 | start = tokens[1] 64 | total = tokens[2] 65 | openTab = tokens[3] 66 | query = tokens[4] 67 | indices = tokens[5] 68 | sortField = tokens[6] 69 | sortOrder = tokens[7] 70 | except ValueError: 71 | raise template.TemplateSyntaxError("%r tag requires arguments (location, total, openTab, query, indices, sortField, sortOrder)." % tag_name) 72 | 73 | return Paginate(start, total, openTab, query, indices, sortField, sortOrder) 74 | 75 | class Paginate(template.Node): 76 | def __init__(self, start, total, openTab, query, indices, sortField, sortOrder): 77 | self.start = template.Variable(start) 78 | self.total = template.Variable(total) 79 | self.openTab = template.Variable(openTab) 80 | self.query = template.Variable(query) 81 | self.indices = template.Variable(indices) 82 | self.sortField = template.Variable(sortField) 83 | self.sortOrder = template.Variable(sortOrder) 84 | 85 | def render(self, context): 86 | result = '' 116 | 117 | return result 118 | 119 | register.tag('paginate', genPagination) -------------------------------------------------------------------------------- /Brownian/view/tests.py: -------------------------------------------------------------------------------- 1 | from django.utils import unittest 2 | from django.test.client import Client, RequestFactory 3 | from django.shortcuts import render 4 | import utils.es 5 | 6 | class nonElasticSearchTests(unittest.TestCase): 7 | def setUp(self): 8 | self.client = Client() 9 | 10 | def testStatusCodes(self): 11 | resp1 = self.client.get('/idontexist') 12 | self.assertNotEqual(resp1.status_code, 200) 13 | 14 | def testQueryQuote(self): 15 | query = """ts:[* TO 1340647651797] AND !uid:"lkaub98ab" AND (host:"google.com" OR host:yahoo.com") AND notice:"SSL::Invalid_Server_Cert"""" 16 | expectedResult = 'ts:[* TO 1340647651797] AND !uid:"lkaub98ab" AND (host:"google.com" OR host:yahoo.com") AND notice:"SSL::Invalid_Server_Cert"' 17 | self.assertEqual(utils.es.queryEscape(query), expectedResult) 18 | 19 | class elasticSearchTests(unittest.TestCase): 20 | def setUp(self): 21 | self.client = Client() 22 | 23 | def testStatusCodes(self): 24 | resp1 = self.client.get('/') 25 | resp2 = self.client.get('/?query=*') 26 | resp3 = self.client.get('/?query=uid:GjR1jckW1y6') 27 | resp4 = self.client.get('/?query=uid:GjR1jckW1y6%20AND%20status:failed') 28 | resp5 = self.client.get('/nope') 29 | self.assertEqual(resp1.status_code, 200) 30 | self.assertEqual(resp2.status_code, 200) 31 | self.assertEqual(resp3.status_code, 200) 32 | self.assertEqual(resp4.status_code, 200) 33 | self.assertNotEqual(resp5.status_code, 200) 34 | 35 | class JSONTests(unittest.TestCase): 36 | def setUp(self): 37 | self.result = { 38 | u'responses': 39 | [{u'hits': 40 | {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 3369, u'timed_out': False}, 41 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2986, u'timed_out': False}, 42 | {u'hits': {u'hits': [ 43 | {u'es_id': u'j7QEXwZWTUa3G0prgCKaCQ', u'es_score': 1.0, u'es_type': u'communication', u'es_index': u'bro-06251400', u'es_source': {u'peer': u'worker-1', u'src_name': u'child', u'message': u'selects=3000000 canwrites=0 timeouts=2986503', u'ts': 1340647604358, u'level': u'info'}}, 44 | {u'es_id': u'O_sTSoIXRhmbT1mkJ_WaAw', u'es_score': 1.0, u'es_type': u'communication', u'es_index': u'bro-06251400', u'es_source': {u'peer': u'worker-2', u'src_name': u'child', u'message': u'selects=2900000 canwrites=0 timeouts=2886357', u'ts': 1340647615143, u'level': u'info'}}, 45 | ], u'total': 407, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4349, u'timed_out': False}, 46 | {u'hits': {u'hits': [ 47 | {u'es_id': u'rWIR82xHRjyjDnsBFcEkqQ', u'es_score': 1.0, u'es_type': u'conn', u'es_index': u'bro-06251400', u'es_source': {u'resp_bytes': 45, u'uid': u'SpoGdOarGy3', u'conn_state': u'SF', u'proto': u'udp', u'id.orig_p': 20961, u'id.resp_h': u'128.123.140.21', u'orig_pkts': 1, u'orig_ip_bytes': 70, u'ts': 1340647618510, u'id.orig_h': u'192.92.82.251', u'id.resp_p': 62011, u'tunnel_parents': [], u'resp_pkts': 1, u'local_orig': 0, u'missed_bytes': 0, u'duration': 0.075358, u'orig_bytes': 42, u'resp_ip_bytes': 73, u'history': u'Dd'}}, 48 | {u'es_id': u'Q9PyFb8aTTy2mnn-lWfwmA', u'es_score': 1.0, u'es_type': u'conn', u'es_index': u'bro-06251400', u'es_source': {u'resp_bytes': 178, u'uid': u'Kv8BEzH3L7d', u'conn_state': u'SF', u'proto': u'udp', u'id.orig_p': 22821, u'id.resp_h': u'128.0.100.9', u'orig_pkts': 4, u'orig_ip_bytes': 788, u'ts': 1340647617494, u'id.orig_h': u'12.113.6.0', u'id.resp_p': 53890, u'tunnel_parents': [], u'resp_pkts': 5, u'local_orig': 0, u'missed_bytes': 0, u'duration': 0.876488, u'orig_bytes': 676, u'resp_ip_bytes': 318, u'history': u'Dd'}}, 49 | ], u'total': 371817, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4572, u'timed_out': False}, 50 | {u'hits': {u'hits': [ 51 | {u'es_id': u'b1oxRcZVT9aeDFbMbDCw5g', u'es_score': 1.0, u'es_type': u'dns', u'es_index': u'bro-06251400', u'es_source': {u'AA': 0, u'RD': 1, u'rcode': 0, u'qclass_name': u'C_INTERNET', u'uid': u'OgG6MWp32o1', u'proto': u'udp', u'id.orig_p': 1087, u'id.resp_h': u'128.2.0.0', u'rcode_name': u'NOERROR', u'ts': 1340647607992, u'id.orig_h': u'23.123.21.19', u'id.resp_p': 53, u'qclass': 1, u'RA': 0, u'qtype_name': u'A', u'query': u'bro-ids.org', u'Z': 0, u'qtype': 1, u'TC': 0, u'trans_id': 1536}}, 52 | {u'es_id': u'giL8QVdMT-O6IbDNjLSGKA', u'es_score': 1.0, u'es_type': u'dns', u'es_index': u'bro-06251400', u'es_source': {u'AA': 0, u'RD': 1, u'rcode': 0, u'qclass_name': u'C_INTERNET', u'uid': u'OgG6MWp32o1', u'proto': u'udp', u'id.orig_p': 1087, u'id.resp_h': u'128.2.0.0', u'rcode_name': u'NOERROR', u'ts': 1340647637696, u'id.orig_h': u'8.8.35.8', u'id.resp_p': 53, u'qclass': 1, u'RA': 0, u'qtype_name': u'A', u'query': u'a1158.b.akamai.net', u'Z': 0, u'qtype': 1, u'TC': 0, u'trans_id': 13688}}, 53 | ], u'total': 76715, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4600, u'timed_out': False}, 54 | {u'hits': {u'hits': [ 55 | {u'es_id': u'3aCWgiH4QpioEAJZQ6achg', u'es_score': 1.0, u'es_type': u'dpd', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'L1NUOOOptp2', u'proto': u'tcp', u'id.orig_p': 52162, u'id.resp_h': u'17.0.6.4', u'ts': 1340647598519, u'analyzer': u'SSL', u'failure_reason': u'unexpected Handshake message SERVER_HELLO from responder in state INITIAL', u'id.orig_h': u'128.255.255.16', u'id.resp_p': 443}}, 56 | {u'es_id': u'hJSrHUgFQI6ngNAU8QSImw', u'es_score': 1.0, u'es_type': u'dpd', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'ZYbazGdmJc9', u'proto': u'tcp', u'id.orig_p': 56574, u'id.resp_h': u'128.2.3.4', u'ts': 1340647599095, u'analyzer': u'SSL', u'failure_reason': u'unexpected Handshake message SERVER_HELLO from responder in state INITIAL', u'id.orig_h': u'9.8.7.6', u'id.resp_p': 443}}, 57 | ], u'total': 896, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4309, u'timed_out': False}, 58 | {u'hits': {u'hits': [ 59 | {u'es_id': u'Ceps5reQRkmnNL0dOJ9p8g', u'es_score': 1.0, u'es_type': u'ftp', u'es_index': u'bro-06251400', u'es_source': {u'reply_msg': u'Transfer complete.', u'uid': u'J2Z55eweLj6', u'id.orig_p': 47491, u'id.resp_h': u'2.1.155.1', u'file_size': 4, u'ts': 1340647523506, u'id.orig_h': u'128.5.130.21', u'id.resp_p': 21, u'reply_code': 226, u'command': u'RETR', u'user': u'anonymous', u'arg': u'ftp://2.1.155.1/archlinux/ftpfull/extra/os/x86_64/libxfce4ui-4.10.0-1-x86_64.pkg.tar.xz', u'password': u'ftp@example.com'}}, 60 | {u'es_id': u'PlWSvWewSsmi-bDx3HQQ_Q', u'es_score': 1.0, u'es_type': u'ftp', u'es_index': u'bro-06251400', u'es_source': {u'reply_msg': u'Transfer complete.', u'uid': u'J2Z55eweLj6', u'id.orig_p': 47491, u'id.resp_h': u'2.1.155.2', u'file_size': 0, u'ts': 1340647526224, u'id.orig_h': u'128.5.130.21', u'id.resp_p': 21, u'reply_code': 226, u'command': u'RETR', u'user': u'anonymous', u'arg': u'ftp://2.1.155.2/archlinux/ftpfull/extra/os/x86_64/garcon-0.2.0-1-x86_64.pkg.tar.xz', u'password': u'ftp@example.com'}}, 61 | ], u'total': 38, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4424, u'timed_out': False}, 62 | {u'hits': {u'hits': [ 63 | {u'es_id': u'BSAn4rBpQnWtoZ7_oJ2aSg', u'es_score': 1.0, u'es_type': u'http', u'es_index': u'bro-06251400', u'es_source': {u'trans_depth': 1, u'status_code': 200, u'uid': u'dbuYW3FQVa8', u'request_body_len': 0, u'response_body_len': 73773, u'id.orig_p': 51622, u'id.resp_h': u'128.2.7.192', u'status_msg': u'OK', u'tags': [], u'ts': 1340647560439, u'uri': u'/images/detail-sprite.png', u'id.orig_h': u'16.193.137.16', u'id.resp_p': 80, u'host': u'gigapan.com', u'user_agent': u'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)', u'referrer': u'http://gigapan.com/galleries/5998/gigapans/93336', u'cookie_vars': [u'es__utmb', u'es__utma', u'es__utmc', u'es_gigapan_session', u'es__utmz'], u'uri_vars': [u'/images/detail-sprite.png'], u'method': u'GET', u'mime_type': u'image/png', u'client_header_names': [u'ACCEPT', u'REFERER', u'ACCEPT-LANGUAGE', u'USER-AGENT', u'ACCEPT-ENCODING', u'HOST', u'CONNECTION', u'COOKIE']}}, 64 | {u'es_id': u'TKvkppiqTyyjfPtY_7e6Jg', u'es_score': 1.0, u'es_type': u'http', u'es_index': u'bro-06251400', u'es_source': {u'trans_depth': 3, u'uid': u'shriLS4fZa9', u'request_body_len': 0, u'response_body_len': 245207, u'id.orig_p': 53860, u'id.resp_h': u'130.64.126.25', u'status_msg': u'Partial Content', u'tags': [], u'ts': 1340647561145, u'uri': u'/pdf/menus/Dinner.pdf', u'id.orig_h': u'128.237.124.18', u'id.resp_p': 80, u'host': u'www.dining.com', u'user_agent': u'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1', u'status_code': 206, u'cookie_vars': [u'es__utmc', u's_sq', u'es__utma', u's_cmrun', u'es__utmb', u's_cc', u's_nr', u's_evar5', u'es__utmz', u'ASPSESSIONIDSABACRQR'], u'uri_vars': [u'/pdf/menus/Dinner.pdf'], u'method': u'GET', u'client_header_names': [u'HOST', u'USER-AGENT', u'ACCEPT', u'ACCEPT-LANGUAGE', u'ACCEPT-ENCODING', u'DNT', u'CONNECTION', u'RANGE', u'COOKIE']}}, 65 | ], u'total': 150255, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4595, u'timed_out': False}, 66 | {u'hits': {u'hits': [ 67 | {u'es_id': u'zblyDe_wQwuQFAUrIdCvZw', u'es_score': 1.0, u'es_type': u'irc', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'dcqnFZeA4x6', u'id.orig_p': 40206, u'id.resp_h': u'128.237.112.64', u'ts': 1340647291296, u'value': u'#Cyanogenmod', u'id.orig_h': u'123.9.144.4', u'id.resp_p': 6667, u'command': u'JOIN', u'addl': u''}}, 68 | {u'es_id': u'KgE_2ZMNTUKUu7YCygQy2Q', u'es_score': 1.0, u'es_type': u'irc', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'dcqnFZeA4x6', u'id.orig_p': 40206, u'id.resp_h': u'128.237.112.64', u'ts': 1340647321396, u'value': u'#cyanogenmod-dev', u'id.orig_h': u'123.9.144.4', u'id.resp_p': 6667, u'command': u'JOIN', u'addl': u''}}, 69 | ], u'total': 91, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4451, u'timed_out': False}, 70 | {u'hits': {u'hits': [ 71 | {u'es_id': u'Af_PFqc8R5CndEOMdT0Mjw', u'es_score': 1.0, u'es_type': u'known_certs', u'es_index': u'bro-06251400', u'es_source': {u'issuer_subject': u'CN=COMODO High-Assurance Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB', u'port_num': 443, u'ts': 1340647603095, u'host': u'128.2.105.87', u'serial': u'1BBEB37A021343B91E1DA231CCFE4126', u'subject': u'CN=calendar.andrew.cmu.edu,OU=PlatinumSSL,OU=Hosted by Carnegie Mellon University,OU=Computing Services,O=Carnegie Mellon University,streetAddress=5000 Forbes Ave,L=Pittsburgh,ST=PA,postalCode=15213,C=US'}}, 72 | {u'es_id': u'fw_q48I1QQ25RKJb1_ae1w', u'es_score': 1.0, u'es_type': u'known_certs', u'es_index': u'bro-06251400', u'es_source': {u'issuer_subject': u'CN=COMODO High-Assurance Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB', u'port_num': 443, u'ts': 1340647610354, u'host': u'128.2.229.61', u'serial': u'170031A4782B972E1ECE57371A12510A', u'subject': u'CN=hpp.web.cmu.edu,OU=PlatinumSSL,OU=Hosted by Carnegie Mellon University,OU=Health Professions Program,O=Carnegie Mellon University,streetAddress=5000 Forbes Ave,L=Pittsburgh,ST=PA,postalCode=15213,C=US'}}, 73 | ], u'total': 101, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4451, u'timed_out': False}, 74 | {u'hits': {u'hits': [ 75 | {u'es_id': u'0-L6DW-lRXiPi7j1vS2rFg', u'es_score': 1.0, u'es_type': u'known_hosts', u'es_index': u'bro-06251400', u'es_source': {u'host': u'128.2.5.6', u'ts': 1340647598892}}, 76 | {u'es_id': u'OFNta4uxR2GrRoWqVDr7HQ', u'es_score': 1.0, u'es_type': u'known_hosts', u'es_index': u'bro-06251400', u'es_source': {u'host': u'128.2.6.5', u'ts': 1340647599402}}, 77 | ], u'total': 5539, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4308, u'timed_out': False}, 78 | {u'hits': {u'hits': [ 79 | {u'es_id': u'2pUFZ_cBTKWTUIT0OMcyoQ', u'es_score': 1.0, u'es_type': u'known_services', u'es_index': u'bro-06251400', u'es_source': {u'port_proto': u'tcp', u'host': u'128.2.46.19', u'port_num': 3389, u'ts': 1340647299382, u'service': []}}, 80 | {u'es_id': u'kcJJJU_URmi0LIJqKqmR6Q', u'es_score': 1.0, u'es_type': u'known_services', u'es_index': u'bro-06251400', u'es_source': {u'port_proto': u'tcp', u'host': u'128.237.20.16', u'port_num': 46657, u'ts': 1340647300365, u'service': []}}, 81 | ], u'total': 1156, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4307, u'timed_out': False}, 82 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2982, u'timed_out': False}, 83 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 3665, u'timed_out': False}, 84 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2981, u'timed_out': False}, 85 | {u'hits': {u'hits': [ 86 | {u'es_id': u'DqY183JqTfGFzEMgLs0nhg', u'es_score': 1.0, u'es_type': u'notice', u'es_index': u'bro-06251400', u'es_source': {u'note': u'HTTP::Incorrect_File_Type', u'dropped': 0, u'uid': u'jFvD488oPPk', u'proto': u'tcp', u'id.orig_p': 2899, u'id.resp_h': u'128.2.8.13', u'dst': u'128.2.8.13', u'policy_items': [7, 6], u'ts': 1340647599222, u'p': 50308, u'id.orig_h': u'15.8.33.147', u'id.resp_p': 50308, u'peer_descr': u'worker-3', u'actions': [u'Notice::ACTION_ALARM', u'Notice::ACTION_LOG'], u'msg': u'application/x-dosexec GET http://128.2.8.13:50308/tcp/8679844E004FA5E5A28B1C15EF2839B6', u'src': u'15.8.33.147', u'suppress_for': 3600.0}}, 87 | {u'es_id': u'yhcrO8-6Sky8npaERDDf5g', u'es_score': 1.0, u'es_type': u'notice', u'es_index': u'bro-06251400', u'es_source': {u'note': u'DNS::External_Name', u'dropped': 0, u'uid': u'Fm5zi7Yngvj', u'proto': u'tcp', u'id.orig_p': 51250, u'id.resp_h': u'15.8.33.147', u'dst': u'15.8.33.147', u'policy_items': [7, 6], u'ts': 1340647604356, u'p': 53, u'id.orig_h': u'128.2.2.14', u'id.resp_p': 53, u'peer_descr': u'worker-1', u'actions': [u'Notice::ACTION_ALARM', u'Notice::ACTION_LOG'], u'msg': u'plab.planetlab.org is pointing to a local host - 128.2.5.5.', u'src': u'128.2.2.14', u'suppress_for': 3600.0}}, 88 | ], u'total': 241, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4112, u'timed_out': False}, 89 | {u'hits': {u'hits': [ 90 | {u'es_id': u'DqY183JqTfGFzEMgLs0nhg', u'es_score': 1.0, u'es_type': u'notice_alarm', u'es_index': u'bro-06251400', u'es_source': {u'note': u'HTTP::Incorrect_File_Type', u'dropped': 0, u'uid': u'jFvD488oPPk', u'proto': u'tcp', u'id.orig_p': 2899, u'id.resp_h': u'128.2.8.13', u'dst': u'128.2.8.13', u'policy_items': [7, 6], u'ts': 1340647599222, u'p': 50308, u'id.orig_h': u'15.8.33.147', u'id.resp_p': 50308, u'peer_descr': u'worker-3', u'actions': [u'Notice::ACTION_ALARM', u'Notice::ACTION_LOG'], u'msg': u'application/x-dosexec GET http://128.2.8.13:50308/tcp/8679844E004FA5E5A28B1C15EF2839B6', u'src': u'15.8.33.147', u'suppress_for': 3600.0}}, 91 | {u'es_id': u'yhcrO8-6Sky8npaERDDf5g', u'es_score': 1.0, u'es_type': u'notice_alarm', u'es_index': u'bro-06251400', u'es_source': {u'note': u'DNS::External_Name', u'dropped': 0, u'uid': u'Fm5zi7Yngvj', u'proto': u'tcp', u'id.orig_p': 51250, u'id.resp_h': u'15.8.33.147', u'dst': u'15.8.33.147', u'policy_items': [7, 6], u'ts': 1340647604356, u'p': 53, u'id.orig_h': u'128.2.2.14', u'id.resp_p': 53, u'peer_descr': u'worker-1', u'actions': [u'Notice::ACTION_ALARM', u'Notice::ACTION_LOG'], u'msg': u'plab.planetlab.org is pointing to a local host - 128.2.5.5.', u'src': u'128.2.2.14', u'suppress_for': 3600.0}}, 92 | ], u'total': 241, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4309, u'timed_out': False}, 93 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 3519, u'timed_out': False}, 94 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2835, u'timed_out': False}, 95 | {u'hits': {u'hits': [ 96 | {u'es_id': u'b5JqQtxcQjmb3EPJdQhszg', u'es_score': 1.0, u'es_type': u'reporter', u'es_index': u'bro-06251400', u'es_source': {u'message': u'processing suspended', u'location': u'', u'ts': 1340647282484, u'level': u'Reporter::INFO'}}, {u'es_id': u'cWt1H-MuTYmGkHqhLla4zA', u'es_score': 1.0, u'es_type': u'reporter', u'es_index': u'bro-06251400', u'es_source': {u'message': u'Failed to open GeoIP database: /usr/share/GeoIP/GeoIPCity.dat', u'location': u'', u'ts': 1340647439536, u'level': u'Reporter::WARNING'}}, 97 | {u'es_id': u'SQm2tHbPQ9ijRCVcD26Tkw', u'es_score': 1.0, u'es_type': u'reporter', u'es_index': u'bro-06251400', u'es_source': {u'message': u'Fell back to GeoIP Country database', u'location': u'', u'ts': 1340647439536, u'level': u'Reporter::WARNING'}}, 98 | ], u'total': 11, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 3885, u'timed_out': False}, 99 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2834, u'timed_out': False}, 100 | {u'hits': {u'hits': [ 101 | {u'es_id': u'TS-aiV6_TJGSfbVzY4cxiQ', u'es_score': 1.0, u'es_type': u'smtp', u'es_index': u'bro-06251400', u'es_source': {u'mailfrom': u'', u'trans_depth': 1, u'from': u'"A robot" ', u'uid': u'bJ80fNuYd4i', u'to': [u'anotherbot@google.net'], u'id.orig_p': 46212, u'id.resp_h': u'176.46.24.119', u'first_received': u'from 128.2.1.1 (proxying for 192.168.24.13) (SquirrelMail authenticated user bot@andrew.cmu.edu) by webmail.andrew.cmu.edu with HTTP; Mon, 25 Jun 2012 14:06:38 -0400', u'msg_id': u'<50170e817247841935e688ee39a357b8.squirrel@webmail.andrew.cmu.edu>', u'ts': 1340647599579, u'second_received': u'from webmail.andrew.cmu.edu (WEBMAIL-03.ANDREW.CMU.EDU [128.2.105.111])\t(user=bot mech=GSSAPI (56 bits))\tby smtp.andrew.cmu.edu (8.14.4/8.14.4) with ESMTP id q5PI6cYu024152\tfor ; Mon, 25 Jun 2012 14:06:38 -0400', u'id.orig_h': u'128.2.11.95', u'id.resp_p': 25, u'is_webmail': 1, u'rcptto': [u''], u'user_agent': u'SquirrelMail/1.4.22', u'date': u'Mon, 25 Jun 2012 14:06:38 -0400', u'path': [u'192.168.172.18', u'12.2.65.73', u'128.2.103.12', u'128.2.4.4'], u'helo': u'smtp.andrew.cmu.edu', u'last_reply': u'250 2.0.0 Si6f1j00d232CWw06i6fYH mail accepted for delivery', u'subject': u'[Fwd: Some Spam!]'}}, 102 | {u'es_id': u'tvbXEWoVTlWgnYqBVaxiOg', u'es_score': 1.0, u'es_type': u'smtp', u'es_index': u'bro-06251400', u'es_source': {u'mailfrom': u'', u'trans_depth': 1, u'from': u'"Rudolph" ', u'uid': u'XdFptTlDHEa', u'to': [u'"\'Santa\'" '], u'id.orig_p': 58555, u'id.resp_h': u'23.167.15.33', u'first_received': u'from Blitzen (mail.aol.com [6.4.4.6])\t(user=rudolph mech=LOGIN (0 bits))\tby smtp.mail.edu (8.14.4/8.14.4) with ESMTP id q5PI6b2O014333\t(version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT)\tfor ; Mon, 25 Jun 2012 14:06:38 -0400', u'msg_id': u'<001c01cd52fd$425395b0$c6fac110$@cmu.edu>', u'ts': 1340647600640, u'last_reply': u'250 ok: Message 1796213216 accepted', u'id.orig_h': u'17.5.231.224', u'id.resp_p': 25, u'is_webmail': 0, u'rcptto': [u''], u'user_agent': u'Microsoft Outlook 14.0', u'date': u'Mon, 25 Jun 2012 14:06:34 -0400', u'path': [u'172.43.243.2', u'128.2.123.2', u'27.8.13.224'], u'helo': u'smtp.mail.edu', u'in_reply_to': u'<020801cd52fb$9b1b20e0$d151f2a0$@com>', u'subject': u'RE: About...'}}, 103 | ], u'total': 1484, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4159, u'timed_out': False}, 104 | {u'hits': {u'hits': [ 105 | {u'es_id': u'Q3yvzguwToaRIwuntQWlaQ', u'es_score': 1.0, u'es_type': u'smtp_entities', u'es_index': u'bro-06251400', u'es_source': {u'excerpt': u'', u'trans_depth': 1, u'uid': u'XHtqpmt34X5', u'id.orig_p': 35862, u'id.resp_h': u'128.2.67.132', u'content_len': 39750, u'ts': 1340647597467, u'id.orig_h': u'154.33.127.21', u'id.resp_p': 25, u'mime_type': u'text/html'}}, 106 | {u'es_id': u'sunNH3NgQ4yJndenj7FI_w', u'es_score': 1.0, u'es_type': u'smtp_entities', u'es_index': u'bro-06251400', u'es_source': {u'excerpt': u'', u'trans_depth': 1, u'uid': u'FYYqOdAqtR8', u'id.orig_p': 58902, u'id.resp_h': u'193.54.168.226', u'content_len': 411, u'ts': 1340647598641, u'id.orig_h': u'128.236.98', u'id.resp_p': 25, u'mime_type': u'text/plain'}}, 107 | ], u'total': 1809, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4158, u'timed_out': False}, 108 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2833, u'timed_out': False}, 109 | {u'hits': {u'hits': [ 110 | {u'es_id': u'IRQMZJ5WT_-RqjsEXL-7TQ', u'es_score': 1.0, u'es_type': u'software', u'es_index': u'bro-06251400', u'es_source': {u'name': u'Firefox', u'unparsed_version': u'Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2', u'version.minor': 0, u'ts': 1340647282525, u'host': u'128.2.123.22', u'version.minor2': 2, u'software_type': u'HTTP::BROWSER', u'version.major': 10}}, 111 | {u'es_id': u'61GFYU28S5CD8hI9rJcYSw', u'es_score': 1.0, u'es_type': u'software', u'es_index': u'bro-06251400', u'es_source': {u'name': u'Safari', u'unparsed_version': u'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/534.56.5 (KHTML, like Gecko) Version/5.1.6 Safari/534.56.5', u'version.minor': 1, u'ts': 1340647282525, u'host': u'128.53.122.196', u'version.minor2': 6, u'software_type': u'HTTP::BROWSER', u'version.major': 5}}, 112 | ], u'total': 7495, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4215, u'timed_out': False}, 113 | {u'hits': {u'hits': [ 114 | {u'es_id': u'2e5V_u7rT9Cayy6aZ9dgcA', u'es_score': 1.0, u'es_type': u'ssh', u'es_index': u'bro-06251400', u'es_source': {u'status': u'failure', u'direction': u'INBOUND', u'uid': u'GjR1jckW1y6', u'id.orig_p': 57971, u'id.resp_h': u'123.69.87.17', u'ts': 1340647594375, u'server': u'SSH-2.0-OpenSSH_5.5p1 Debian-4ubuntu6', u'id.orig_h': u'122.75.87.119', u'id.resp_p': 22, u'client': u'SSH-2.0-libssh-0.1', u'resp_size': 1671}}, 115 | {u'es_id': u'EKnt03nwSw6NsE6n7u833A', u'es_score': 1.0, u'es_type': u'ssh', u'es_index': u'bro-06251400', u'es_source': {u'status': u'failure', u'direction': u'INBOUND', u'uid': u'jMH9eIUdLe', u'id.orig_p': 47751, u'id.resp_h': u'24.134.211.182', u'ts': 1340647598344, u'server': u'SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu7', u'id.orig_h': u'210.17.148.14', u'id.resp_p': 22, u'client': u'SSH-2.0-libssh-0.1', u'resp_size': 1671}}, 116 | ], u'total': 385, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4199, u'timed_out': False}, 117 | {u'hits': {u'hits': [ 118 | {u'es_id': u'1ObFkGroTl6XdJ6OLKyyiQ', u'es_score': 1.0, u'es_type': u'ssl', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'PLYYVXtxoS7', u'server_name': u'mail.google.com', u'id.orig_p': 44929, u'id.resp_h': u'17.145.28.193', u'ts': 1340647651797, u'session_id': u'c32fe4de2d28fc55c20cdc1693a41d9595feaf1f941c82537cbb25b89ca0267b', u'id.orig_h': u'128.2.99.138', u'id.resp_p': 443, u'version': u'TLSv10', u'cipher': u'TLS_ECDHE_RSA_WITH_RC4_128_SHA'}}, 119 | {u'es_id': u'EB-Jj0avRw2a46wbhyoAoA', u'es_score': 1.0, u'es_type': u'ssl', u'es_index': u'bro-06251400', u'es_source': {u'not_valid_after': 1391057999000, u'issuer_subject': u'CN=Thawte SSL CA,O=Thawte\\, Inc.,C=US', u'uid': u'HBSDvWDLWSa', u'server_name': u'photos-5.dropbox.com', u'id.orig_p': 57865, u'id.resp_h': u'123.121.12.17', u'ts': 1340647651599, u'id.orig_h': u'128.2.237.18', u'id.resp_p': 443, u'version': u'TLSv10', u'cert_hash': u'd7bc4836e22e4e6ece99996bf05a4638', u'not_valid_before': 1322715600000, u'validation_status': u'ok', u'cipher': u'TLS_DHE_RSA_WITH_AES_256_CBC_SHA', u'subject': u'CN=*.dropbox.com,O=Dropbox\\, Inc.,L=San Francisco,ST=California,C=US'}}, 120 | ], u'total': 20017, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4313, u'timed_out': False}, 121 | {u'hits': {u'hits': [], u'total': 0, u'max_score': None}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 2831, u'timed_out': False}, 122 | {u'hits': {u'hits': [ 123 | {u'es_id': u'QqGX-5qPR6uRQr4nq0MHRg', u'es_score': 1.0, u'es_type': u'syslog', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'5g5xqQAmdh2', u'proto': u'udp', u'id.orig_p': 40629, u'id.resp_h': u'128.2.12.0', u'facility': u'LOCAL0', u'ts': 1340647493276, u'id.orig_h': u'66.93.128.15', u'id.resp_p': 514, u'message': u' IP: entry duplicated 2 times @2012-06-25-13:09:53', u'severity': u'WARNING'}}, 124 | {u'es_id': u'mZuYoDNYTVSQF04HYMGTxQ', u'es_score': 1.0, u'es_type': u'syslog', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'lhsZfvPM2s5', u'proto': u'udp', u'id.orig_p': 40631, u'id.resp_h': u'128.2.12.0', u'facility': u'LOCAL0', u'ts': 1340647551462, u'id.orig_h': u'66.93.128.15', u'id.resp_p': 514, u'message': u' IP: discard from 12.181.172.12 port 55556 to 66.93.182.15 port 54 TCP SYN (default) @2012-06-25-13:12:21', u'severity': u'WARNING'}} 125 | ], u'total': 2, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 3450, u'timed_out': False}, 126 | {u'hits': {u'hits': [ 127 | {u'es_id': u'askIegRiTZOpcWKmGNn3rQ', u'es_score': 1.0, u'es_type': u'tunnel', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'ltygZNzxov', u'tunnel_type': u'Tunnel::IP', u'id.orig_p': 0, u'id.resp_h': u'128.2.15.155', u'ts': 1340647599658, u'id.orig_h': u'94.25.201.137', u'id.resp_p': 0, u'action': u'Tunnel::DISCOVER'}}, 128 | {u'es_id': u'XQdf2DnIQvWqi6FoM2uV-Q', u'es_score': 1.0, u'es_type': u'tunnel', u'es_index': u'bro-06251400', u'es_source': {u'uid': u'fy89Hx63iid', u'tunnel_type': u'Tunnel::TEREDO', u'id.orig_p': 64611, u'id.resp_h': u'65.123.18.128', u'ts': 1340647602701, u'id.orig_h': u'128.2.195.21', u'id.resp_p': 3544, u'action': u'Tunnel::DISCOVER'}}, 129 | ], u'total': 466, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4214, u'timed_out': False}, 130 | {u'hits': {u'hits': [ 131 | {u'es_id': u'5VfseO8aQU-OQqkhuTVohA', u'es_score': 1.0, u'es_type': u'weird', u'es_index': u'bro-06251400', u'es_source': {u'notice': 0, u'uid': u'42FJ0XejeT9', u'id.orig_p': 4850, u'id.resp_h': u'69.123.24.83', u'ts': 1340647598696, u'id.orig_h': u'128.2.18.19', u'id.resp_p': 80, u'peer': u'worker-3', u'name': u'unescaped_special_URI_char'}}, 132 | {u'es_id': u'4HFM97ukTEeIcmjs4aDhtg', u'es_score': 1.0, u'es_type': u'weird', u'es_index': u'bro-06251400', u'es_source': {u'notice': 0, u'uid': u'9v5DdeLTzwd', u'id.orig_p': 4378, u'id.resp_h': u'8.27.18.23', u'ts': 1340647598924, u'id.orig_h': u'128.2.17.52', u'id.resp_p': 80, u'peer': u'worker-3', u'name': u'inflate_failed'}}, 133 | ], u'total': 4977, u'max_score': 1.0}, u'es_shards': {u'successful': 4, u'failed': 0, u'total': 4}, u'took': 4205, u'timed_out': False} 134 | ] 135 | } 136 | self.factory = RequestFactory() 137 | 138 | 139 | def testStatusCode(self): 140 | data = {"query": "*", "openTab": "conn", "hits": self.result} 141 | request = self.factory.get("/") 142 | self.assertEqual(render(request, "home.html", data).status_code, 200) 143 | -------------------------------------------------------------------------------- /Brownian/view/utils/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'vladg' 2 | -------------------------------------------------------------------------------- /Brownian/view/utils/broLogTypes.py: -------------------------------------------------------------------------------- 1 | """This file describes the Bro logs and the various field types. 2 | 3 | TODO: This needs to be auto-generated and sent to ES by Bro, but currently the field descriptions are just comments.""" 4 | 5 | class Field(object): 6 | def __init__(self, name, type, description): 7 | self.name = name 8 | self.type = type 9 | self.description = description 10 | 11 | broLogs = { 12 | "app_stats": [ 13 | Field("ts", "time", "Timestamp when the log line was finished and written."), 14 | Field("ts_delta", "interval", "Time interval that the log line covers"), 15 | Field("app", "string", "The name of the \"app\", like \"facebook\" or \"netflix\"."), 16 | Field("uniq_hosts", "count", "The number of unique local hosts using the app."), 17 | Field("hits", "count", "The total number of hits to the app."), 18 | Field("bytes", "count", "The total number of bytes received by users of the app."), 19 | ], 20 | "capture_loss": [ 21 | Field("ts", "time", "Timestamp for when the measurement occurred."), 22 | Field("ts_delta", "interval", "The time delay between this measurement and the last."), 23 | Field("peer", "string", "In the event that there are multiple Bro instances logging to the same host, this distinguishes each peer with its individual name."), 24 | Field("gaps", "count", "Number of missed ACKs from the previous measurement interval."), 25 | Field("acks", "count", "Total number of ACKs seen in the previous measurement interval."), 26 | Field("percent_lost", "string", "Percentage of ACKs seen where the data being ACKed wasn't seen."), 27 | ], 28 | "cluster": [ 29 | Field("ts", "time", "The time at which a cluster message was generated."), 30 | Field("message", "string", "A message indicating information about the cluster's operation."), 31 | ], 32 | "communication": [ 33 | Field("ts", "time", "The network time at which a communication event occurred."), 34 | Field("peer", "string", "The peer name (if any) for which a communication event is concerned."), 35 | Field("src_name", "string", "Where the communication event message originated from, that is, either from the scripting layer or inside the Bro process."), 36 | Field("connected_peer_desc", "string", "TODO: currently unused."), 37 | Field("connected_peer_addr", "addr", "TODO: currently unused."), 38 | Field("connected_peer_port", "port", "TODO: currently unused."), 39 | Field("level", "string", "The severity of the communication event message."), 40 | Field("message", "string", "A message describing the communication event between Bro or Broccoli instances."), 41 | ], 42 | "conn": [ 43 | Field("ts", "time", "This is the time of the first packet."), 44 | Field("uid", "string", "A unique identifier of the connection."), 45 | Field("id.orig_h", "addr", "The originating endpoint's address."), 46 | Field("id.orig_p", "port", "The originating endpoint's port."), 47 | Field("id.resp_h", "addr", "The responding endpoint's address."), 48 | Field("id.resp_p", "port", "The responding endpoint's port."), 49 | Field("proto", "transport_proto", "The transport layer protocol of the connection."), 50 | Field("service", "string", "An identification of an application protocol being sent over the the connection."), 51 | Field("duration", "interval", "How long the connection lasted. For 3-way or 4-way connection tear-downs, this will not include the final ACK."), 52 | Field("orig_bytes", "count", "The number of payload bytes the originator sent. For TCP this is taken from sequence numbers and might be inaccurate (e.g., due to large connections)"), 53 | Field("resp_bytes", "count", "The number of payload bytes the responder sent. See orig_bytes."), 54 | Field("conn_state", "string", "
    conn_stateMeaning
    S0Connection attempt seen, no reply.
    S1Connection established, not terminated.
    SFNormal establishment and termination. Note that this is the same symbol as for state S1. You can tell the two apart because for S1 there will not be any byte counts in the summary, while for SF there will be.
    REJConnection attempt rejected.
    S2Connection established and close attempt by originator seen (but no reply from responder).
    S3Connection established and close attempt by responder seen (but no reply from originator).
    RSTOConnection established, originator aborted (sent a RST).
    RSTREstablished, responder aborted.
    RSTOS0Originator sent a SYN followed by a RST, we never saw a SYN-ACK from the responder.
    RSTRHResponder sent a SYN ACK followed by a RST, we never saw a SYN from the (purported) originator.
    SHOriginator sent a SYN followed by a FIN, we never saw a SYN ACK from the responder (hence the connection was \"half\" open).
    SHRResponder sent a SYN ACK followed by a FIN, we never saw a SYN from the originator.
    OTHNo SYN seen, just midstream traffic (a \"partial connection\" that was not later closed).
    LetterMeaning
    sa SYN w/o the ACK bit set
    ha SYN+ACK (\"handshake\")
    aa pure ACK
    dpacket with payload (\"data\")
    fpacket with FIN bit set
    rpacket with RST bit set
    cpacket with a bad checksum
    iinconsistent packet (e.g. SYN+RST bits both set)
    If the letter is in upper case it means the event comes from the originator and lower case then means the responder. Also, there is compression. We only record one \"d\" in each direction, for instance. I.e., we just record that data went in that direction. This history is not meant to encode how much data that happened to be."), 58 | Field("orig_pkts", "count", "Number of packets the originator sent. Only set if use_conn_size_analyzer = T"), 59 | Field("orig_ip_bytes", "count", "Number IP level bytes the originator sent (as seen on the wire, taken from IP total_length header field). Only set if use_conn_size_analyzer = T"), 60 | Field("resp_pkts", "count", "Number of packets the responder sent. See orig_pkts."), 61 | Field("resp_ip_bytes", "count", "Number IP level bytes the responder sent. See orig_pkts."), 62 | Field("tunnel_parents", "set", "If this connection was over a tunnel, indicate the uid values for any encapsulating parent connections used over the lifetime of this inner connection."), 63 | Field("orig_cc", "string", "The originating endpoint's GeoIP country code."), 64 | Field("resp_cc", "string", "The responding endpoint's GeoIP country code."), 65 | ], 66 | "dhcp": [ 67 | Field("ts", "time", "The earliest time at which a DHCP message over the associated connection is observed."), 68 | Field("uid", "string", "A unique identifier of the connection over which DHCP is occuring."), 69 | Field("id.orig_h", "addr", "The originating endpoint's address."), 70 | Field("id.orig_p", "port", "The originating endpoint's port."), 71 | Field("id.resp_h", "addr", "The responding endpoint's address."), 72 | Field("id.resp_p", "port", "The responding endpoint's port."), 73 | Field("mac", "string", "Client's hardware address."), 74 | Field("assigned_ip", "addr", "Client's actual assigned IP address."), 75 | Field("lease_time", "interval", "IP address lease time."), 76 | Field("trans_id", "count", "A random number chosen by the client of this transaction."), 77 | ], 78 | "dnp3": [ 79 | Field("ts", "time", "Timestamp of the connection."), 80 | Field("uid", "string", "Connection unique ID."), 81 | Field("id.orig_h", "addr", "The originating endpoint's address."), 82 | Field("id.orig_p", "port", "The originating endpoint's port."), 83 | Field("id.resp_h", "addr", "The responding endpoint's address."), 84 | Field("id.resp_p", "port", "The responding endpoint's port."), 85 | Field("fc_request", "string", "The name of the function message in the request."), 86 | Field("fc_reply", "string", "The name of the function message in the reply."), 87 | Field("iin", "count", "The response's \"internal indication number\"."), 88 | ], 89 | "dns": [ 90 | Field("ts", "time", "The earliest time at which a DNS protocol message over the associated connection is observed."), 91 | Field("uid", "string", "A unique identifier of the connection over which DNS messages are being transferred."), 92 | Field("id.orig_h", "addr", "The originating endpoint's address."), 93 | Field("id.orig_p", "port", "The originating endpoint's port."), 94 | Field("id.resp_h", "addr", "The responding endpoint's address."), 95 | Field("id.resp_p", "port", "The responding endpoint's port."), 96 | Field("proto", "transport_proto", "The transport layer protocol of the connection."), 97 | Field("trans_id", "count", "A 16 bit identifier assigned by the program that generated the DNS query. Also used in responses to match up replies to outstanding queries."), 98 | Field("query", "string", "The domain name that is the subject of the DNS query."), 99 | Field("qclass", "count", "The QCLASS value specifying the class of the query."), 100 | Field("qclass_name", "string", "A descriptive name for the class of the query."), 101 | Field("qtype", "count", "A QTYPE value specifying the type of the query."), 102 | Field("qtype_name", "string", "A descriptive name for the type of the query."), 103 | Field("rcode", "count", "The response code value in DNS response messages."), 104 | Field("rcode_name", "string", "A descriptive name for the response code value."), 105 | Field("QR", "bool", "Whether the message is a query (F) or response (T)."), 106 | Field("AA", "bool", "The Authoritative Answer bit for response messages specifies that the responding name server is an authority for the domain name in the question section."), 107 | Field("TC", "bool", "The Truncation bit specifies that the message was truncated."), 108 | Field("RD", "bool", "The Recursion Desired bit indicates to a name server to recursively purse the query."), 109 | Field("RA", "bool", "The Recursion Available bit in a response message indicates if the name server supports recursive queries."), 110 | Field("Z", "count", "A reserved field that is currently supposed to be zero in all queries and responses."), 111 | Field("answers", "vector", "The set of resource descriptions in answer of the query."), 112 | Field("TTLs", "vector", "The caching intervals of the associated RRs described by the answers field."), 113 | Field("rejected", "bool", "Whether the DNS query was rejected by the server."), 114 | ], 115 | "dpd": [ 116 | Field("ts", "time", "Timestamp for when protocol analysis failed."), 117 | Field("uid", "string", "Connection unique ID."), 118 | Field("id.orig_h", "addr", "The originating endpoint's address."), 119 | Field("id.orig_p", "port", "The originating endpoint's port."), 120 | Field("id.resp_h", "addr", "The responding endpoint's address."), 121 | Field("id.resp_p", "port", "The responding endpoint's port."), 122 | Field("proto", "transport_proto", "Transport protocol for the violation."), 123 | Field("analyzer", "string", "The analyzer that generated the violation."), 124 | Field("failure_reason", "string", "The textual reason for the analysis failure."), 125 | ], 126 | "files": [ 127 | Field("ts", "time", "The time when the file was first seen."), 128 | Field("fuid", "string", "An identifier associated with a single file."), 129 | Field("tx_hosts", "set", "If this file was transferred over a network connection this should show the host or hosts that the data sourced from."), 130 | Field("rx_hosts", "set", "If this file was transferred over a network connection this should show the host or hosts that the data traveled to."), 131 | Field("conn_uids", "set", "Connection UIDs over which the file was transferred"), 132 | Field("source", "string", "An identification of the source of the file data. e.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source."), 133 | Field("depth", "count", "A value to repesent the depth of this file in relation to its source. In SMTP, it is the depth of the MIME attachment on the message. In HTTP, it is the depth of the request within the TCP connection."), 134 | Field("analyzers", "set", "A set of analysis types done during the file analysis."), 135 | Field("mime_type", "string", "A mime type provided by libmagic against the bof_buffer, or in the cases where no buffering of the beginning of the file occurs, an initial guess of the mime type based on the first data seen."), 136 | Field("filename", "string", "A filename for the file if one is available from the source for the file. These will frequently come from \"Content-Disposition\" headers in network protocols."), 137 | Field("duration", "interval", "The duration the file was analyzed for."), 138 | Field("local_orig", "bool", "If the source of this file is a network connection, this field indicates if the data originated from the local network or not as determined by the configured Site::local_nets."), 139 | Field("is_orig", "bool", "If the source of this file is a network conneciton, this field indicates if the file is being sent by the originator of the connection or the responder."), 140 | Field("seen_bytes", "count", "Number of bytes provided to the file analysis engine for the file."), 141 | Field("total_bytes", "count", "Total number of bytes that are supposed to comprise the full file."), 142 | Field("missing_bytes", "count", "The number of bytes in the file stream that were completely missed during the process of analysis e.g. due to dropped packets."), 143 | Field("overflow_bytes", "count", "The number of not all-in-sequence bytes in the file stream that were delivered to file analyzers due to reassembly buffer overflow."), 144 | Field("timedout", "bool", "Whether the file analysis timed out at least once for the file."), 145 | Field("parent_fuid", "string", "Identifier associated with a container file from which this one was extracted as part of the file analysis."), 146 | Field("md5", "string", "An MD5 digest of the file contents."), 147 | Field("sha1", "string", "A SHA1 digest of the file contents."), 148 | Field("sha256", "string", "A SHA256 digest of the file contents."), 149 | Field("extracted", "string", "Local filename of extracted file."), 150 | ], 151 | "ftp": [ 152 | Field("ts", "time", "Timestamp for when the command was sent."), 153 | Field("uid", "string", "Connection unique ID."), 154 | Field("id.orig_h", "addr", "The originating endpoint's address."), 155 | Field("id.orig_p", "port", "The originating endpoint's port."), 156 | Field("id.resp_h", "addr", "The responding endpoint's address."), 157 | Field("id.resp_p", "port", "The responding endpoint's port."), 158 | Field("user", "string", "User name for the current FTP session."), 159 | Field("password", "string", "Password for the current FTP session if captured."), 160 | Field("command", "string", "Command given by the client."), 161 | Field("arg", "string", "Argument for the command if one is given."), 162 | Field("mime_type", "string", "Libmagic \"sniffed\" file type if the command indicates a file transfer."), 163 | Field("file_size", "count", "Size of the file if the command indicates a file transfer."), 164 | Field("reply_code", "count", "Reply code from the server in response to the command."), 165 | Field("reply_msg", "string", "Reply message from the server in response to the command."), 166 | Field("data_channel.passive", "bool", "Whether PASV mode is toggled for the control channel."), 167 | Field("data_channel.orig_h", "addr", "The host that will be initiating the data connection."), 168 | Field("data_channel.resp_h", "addr", "The host that will be accepting the data connection."), 169 | Field("data_channel.resp_p", "port", "The port at which the acceptor is listening for the data connection."), 170 | Field("fuid", "string", "File unique ID."), 171 | ], 172 | "http": [ 173 | Field("ts", "time", "Timestamp for when the request happened."), 174 | Field("uid", "string", "Connection unique ID."), 175 | Field("id.orig_h", "addr", "The originating endpoint's address."), 176 | Field("id.orig_p", "port", "The originating endpoint's port."), 177 | Field("id.resp_h", "addr", "The responding endpoint's address."), 178 | Field("id.resp_p", "port", "The responding endpoint's port."), 179 | Field("trans_depth", "count", "Represents the pipelined depth into the connection of this request/response transaction."), 180 | Field("method", "string", "Verb used in the HTTP request (GET, POST, HEAD, etc.)."), 181 | Field("host", "string", "Value of the HOST header."), 182 | Field("uri", "string", "URI used in the request."), 183 | Field("referrer", "string", "Value of the \"referer\" header. The comment is deliberately misspelled like the standard declares, but the name used here is \"referrer\" spelled correctly."), 184 | Field("user_agent", "string", "Value of the User-Agent header from the client."), 185 | Field("request_body_len", "count", "Actual uncompressed content size of the data transferred from the client."), 186 | Field("response_body_len", "count", "Actual uncompressed content size of the data transferred from the server."), 187 | Field("status_code", "count", "Status code returned by the server."), 188 | Field("status_msg", "string", "Status message returned by the server."), 189 | Field("info_code", "count", "Last seen 1xx informational reply code returned by the server."), 190 | Field("info_msg", "string", "Last seen 1xx informational reply message returned by the server."), 191 | Field("filename", "string", "Filename given in the Content-Disposition header sent by the server."), 192 | Field("tags", "set", "A set of indicators of various attributes discovered and related to a particular request/response pair."), 193 | Field("username", "string", "Username if basic-auth is performed for the request."), 194 | Field("password", "string", "Password if basic-auth is performed for the request."), 195 | Field("proxied", "set", "All of the headers that may indicate if the request was proxied."), 196 | Field("orig_fuids", "vector", "An ordered vector of file unique IDs."), 197 | Field("orig_mime_types", "vector", "An ordered vector of mime types."), 198 | Field("resp_fuids", "vector", "An ordered vector of file unique IDs."), 199 | Field("resp_mime_types", "vector", "An ordered vector of mime types."), 200 | Field("client_header_names", "vector", "The vector of HTTP header names sent by the client. No header values are included here, just the header names."), 201 | Field("server_header_names", "vector", "The vector of HTTP header names sent by the server. No header values are included here, just the header names."), 202 | Field("cookie_vars", "vector", "Variable names extracted from all cookies."), 203 | Field("uri_vars", "vector", "Variable names from the URI."), 204 | ], 205 | "intel": [ 206 | Field("ts", "time", "Timestamp for when the data was discovered."), 207 | Field("uid", "string", "Connection unique ID."), 208 | Field("id.orig_h", "addr", "The originating endpoint's address."), 209 | Field("id.orig_p", "port", "The originating endpoint's port."), 210 | Field("id.resp_h", "addr", "The responding endpoint's address."), 211 | Field("id.resp_p", "port", "The responding endpoint's port."), 212 | Field("fuid", "string", "If a file was associated with this intelligence hit, this is the uid for that file."), 213 | Field("file_mime_type", "string", "A mime type if the intelligence hit is related to a file."), 214 | Field("file_desc", "string", "Frequently files can be \"described\" to give a bit more context."), 215 | Field("seen.indicator", "string", "The intelligence indicator."), 216 | Field("seen.indicator_type", "string", "The type of data that the indicator represents."), 217 | Field("seen.where", "string", "Where the data was discovered."), 218 | Field("sources", "set", "Sources which supplied data that resulted in this match."), 219 | ], 220 | "irc": [ 221 | Field("ts", "time", "Timestamp for when the command was seen."), 222 | Field("uid", "string", "Connection unique ID."), 223 | Field("id.orig_h", "addr", "The originating endpoint's address."), 224 | Field("id.orig_p", "port", "The originating endpoint's port."), 225 | Field("id.resp_h", "addr", "The responding endpoint's address."), 226 | Field("id.resp_p", "port", "The responding endpoint's port."), 227 | Field("nick", "string", "Nick name given for the connection."), 228 | Field("user", "string", "User name given for the connection."), 229 | Field("command", "string", "Command given by the client."), 230 | Field("value", "string", "Value for the command given by the client."), 231 | Field("addl", "string", "Any additional data for the command."), 232 | Field("dcc_file_name", "string", "DCC filename requested."), 233 | Field("dcc_file_size", "count", "Size of the DCC transfer as indicated by the sender."), 234 | Field("dcc_mime_type", "string", "Sniffed mime type of the file."), 235 | Field("fuid", "string", "File unique ID."), 236 | ], 237 | "known_certs": [ 238 | Field("ts", "time", "The timestamp when the certificate was detected."), 239 | Field("host", "addr", "The address that offered the certificate."), 240 | Field("port_num", "port", "If the certificate was handed out by a server, this is the port that the server waslistening on."), 241 | Field("subject", "string", "Certificate subject."), 242 | Field("issuer_subject", "string", "Certificate issuer subject."), 243 | Field("serial", "string", "Serial number for the certificate."), 244 | ], 245 | "known_devices": [ 246 | Field("ts", "time", "The timestamp at which the host was detected."), 247 | Field("mac", "string", "The MAC address that was detected."), 248 | Field("dhcp_host_name", "string", "The value of the DHCP host name option, if seen."), 249 | ], 250 | "known_hosts": [ 251 | Field("ts", "time", "The timestamp at which the host was detected."), 252 | Field("host", "addr", "The address that was detected originating or responding to a TCP connection."), 253 | ], 254 | "known_services": [ 255 | Field("ts", "time", "The time at which the service was detected."), 256 | Field("host", "addr", "The host address on which the service is running."), 257 | Field("port_num", "port", "The port number on which the service is running."), 258 | Field("port_proto", "transport_proto", "The transport-layer protocol which the service uses."), 259 | Field("service", "set", "A set of protocols that match the service's connection payloads."), 260 | ], 261 | "loaded_scripts": [ 262 | Field("name", "string", "Name of the script loaded potentially with spaces included before the file name to indicate load depth. The convention is two spaces per level of depth."), 263 | ], 264 | "modbus": [ 265 | Field("ts", "time", "Timestamp of the request."), 266 | Field("uid", "string", "Connection unique ID."), 267 | Field("id.orig_h", "addr", "The originating endpoint's address."), 268 | Field("id.orig_p", "port", "The originating endpoint's port."), 269 | Field("id.resp_h", "addr", "The responding endpoint's address."), 270 | Field("id.resp_p", "port", "The responding endpoint's port."), 271 | Field("func", "string", "The name of the function message that was sent."), 272 | Field("exception", "string", "The exception if the response was a failure."), 273 | ], 274 | "notice": [ 275 | Field("ts", "time", "An absolute time indicating when the notice occurred, defaults to the current network time."), 276 | Field("uid", "string", "A connection UID which uniquely identifies the endpoints concerned with the notice."), 277 | Field("id.orig_h", "addr", "The originating endpoint's address."), 278 | Field("id.orig_p", "port", "The originating endpoint's port."), 279 | Field("id.resp_h", "addr", "The responding endpoint's address."), 280 | Field("id.resp_p", "port", "The responding endpoint's port."), 281 | Field("fuid", "string", "A file unique ID if this notice is related to a file."), 282 | Field("file_mime_type", "string", "A mime type if the notice is related to a file."), 283 | Field("file_desc", "string", "Frequently files can be \"described\" to give a bit more context."), 284 | Field("proto", "transport_proto", "The transport protocol. Filled automatically when either conn, iconn or p is specified."), 285 | Field("note", "Notice", "The Notice::Type of the notice."), 286 | Field("msg", "string", "The human readable message for the notice."), 287 | Field("sub", "string", "The human readable sub-message."), 288 | Field("src", "addr", "Source address, if we don't have a conn_id."), 289 | Field("dst", "addr", "Destination address."), 290 | Field("p", "port", "Associated port, if we don't have a conn_id."), 291 | Field("n", "count", "Associated count, or perhaps a status code."), 292 | Field("peer_descr", "string", "Textual description for the peer that raised this notice."), 293 | Field("actions", "set", "The actions which have been applied to this notice."), 294 | Field("suppress_for", "interval", "This field indicates the length of time that this unique notice should be suppressed. This field is automatically filled out and should not be written to by any other script."), 295 | Field("dropped", "bool", "Indicates if the $src IP address was dropped and denied network access."), 296 | Field("remote_location.country_code", "string", "The country code of the remote endpoint."), 297 | Field("remote_location.region", "string", "The region of the remote endpoint."), 298 | Field("remote_location.city", "string", "The city of the remote endpoint."), 299 | Field("remote_location.latitude", "string", "The latitude of the remote endpoint."), 300 | Field("remote_location.longitude", "string", "The longitude of the remote endpoint."), 301 | ], 302 | "notice_policy": [ 303 | Field("position", "count", "This is the exact positional order in which the Notice::PolicyItem records are checked. This is set internally by the notice framework."), 304 | Field("priority", "count", "Define the priority for this check. Items are checked in ordered from highest value (10) to lowest value (0)."), 305 | Field("action", "Notice", "An action given to the notice if the predicate return true."), 306 | Field("pred", "function", "The pred (predicate) field is a function that returns a boolean T or F value. If the predicate function return true, the action in this record is applied to the notice that is given as an argument to the predicate function. If no predicate is supplied, it's assumed that the PolicyItem always applies."), 307 | Field("halt", "bool", "Indicates this item should terminate policy processing if the predicate returns T."), 308 | Field("suppress_for", "interval", "This defines the length of time that this particular notice should be suppressed."), 309 | ], 310 | "packet_filter": [ 311 | Field("ts", "time", "The time at which the packet filter installation attempt was made."), 312 | Field("node", "string", "This is a string representation of the node that applied this packet filter. It's mostly useful in the context of dynamically changing filters on clusters."), 313 | Field("filter", "string", "The packet filter that is being set."), 314 | Field("init", "bool", "Indicate if this is the filter set during initialization."), 315 | Field("success", "bool", "Indicate if the filter was applied successfully."), 316 | ], 317 | "reporter": [ 318 | Field("ts", "time", "The network time at which the reporter event was generated."), 319 | Field("level", "Reporter", "The severity of the reporter message."), 320 | Field("message", "string", "An info/warning/error message that could have either been generated from the internal Bro core or at the scripting-layer."), 321 | Field("location", "string", "This is the location in a Bro script where the message originated. Not all reporter messages will have locations in them though."), 322 | ], 323 | "signatures": [ 324 | Field("ts", "time", "The network time at which a signature matching type of event to be logged has occurred."), 325 | Field("src_addr", "addr", "The host which triggered the signature match event."), 326 | Field("src_port", "port", "The host port on which the signature-matching activity occurred."), 327 | Field("dst_addr", "addr", "The destination host which was sent the payload that triggered the signature match."), 328 | Field("dst_port", "port", "The destination host port which was sent the payload that triggered the signature match."), 329 | Field("note", "Notice", "Notice associated with signature event"), 330 | Field("sig_id", "string", "The name of the signature that matched."), 331 | Field("event_msg", "string", "A more descriptive message of the signature-matching event."), 332 | Field("sub_msg", "string", "Extracted payload data or extra message."), 333 | Field("sig_count", "count", "Number of sigs, usually from summary count."), 334 | Field("host_count", "count", "Number of hosts, from a summary count."), 335 | ], 336 | "smtp": [ 337 | Field("ts", "time", "Timestamp when the message was first seen."), 338 | Field("uid", "string", "Connection unique ID."), 339 | Field("id.orig_h", "addr", "The originating endpoint's address."), 340 | Field("id.orig_p", "port", "The originating endpoint's port."), 341 | Field("id.resp_h", "addr", "The responding endpoint's address."), 342 | Field("id.resp_p", "port", "The responding endpoint's port."), 343 | Field("trans_depth", "count", "A count to represent the depth of this message transaction in a single connection where multiple messages were transferred."), 344 | Field("helo", "string", "Contents of the Helo header."), 345 | Field("mailfrom", "string", "Contents of the From header."), 346 | Field("rcptto", "set", "Contents of the Rcpt header."), 347 | Field("date", "string", "Contents of the Date header."), 348 | Field("from", "string", "Contents of the From header."), 349 | Field("to", "set", "Contents of the To header."), 350 | Field("reply_to", "string", "Contents of the ReplyTo header."), 351 | Field("msg_id", "string", "Contents of the MsgID header."), 352 | Field("in_reply_to", "string", "Contents of the In-Reply-To header."), 353 | Field("subject", "string", "Contents of the Subject header."), 354 | Field("x_originating_ip", "addr", "Contents of the X-Originating-IP header."), 355 | Field("first_received", "string", "Contents of the first Received header."), 356 | Field("second_received", "string", "Contents of the second Received header."), 357 | Field("last_reply", "string", "The last message the server sent to the client."), 358 | Field("path", "vector", "The message transmission path, as extracted from the headers."), 359 | Field("user_agent", "string", "Value of the User-Agent header from the client."), 360 | Field("fuids", "vector", "An ordered vector of file unique IDs seen attached to the message."), 361 | Field("is_webmail", "bool", "Boolean indicator of if the message was sent through a webmail interface."), 362 | ], 363 | "socks": [ 364 | Field("ts", "time", "Timestamp when the proxy connection was first detected."), 365 | Field("uid", "string", "Connection unique ID."), 366 | Field("id.orig_h", "addr", "The originating endpoint's address."), 367 | Field("id.orig_p", "port", "The originating endpoint's port."), 368 | Field("id.resp_h", "addr", "The responding endpoint's address."), 369 | Field("id.resp_p", "port", "The responding endpoint's port."), 370 | Field("version", "count", "Protocol version of SOCKS."), 371 | Field("user", "string", "Username for the proxy if extracted from the network."), 372 | Field("status", "string", "Server status for the attempt at using the proxy."), 373 | Field("request.host", "addr", "Client requested address."), 374 | Field("request.name", "string", "Client requested name."), 375 | Field("request_p", "port", "Client requested port."), 376 | Field("bound.host", "addr", "Server bound address."), 377 | Field("bound.name", "string", "Server bound name."), 378 | Field("bound_p", "port", "Server bound port."), 379 | ], 380 | "software": [ 381 | Field("ts", "time", "Timestamp when the software was first detected."), 382 | Field("host", "addr", "The IP address detected running the software."), 383 | Field("host_p", "port", "The port detected running the software."), 384 | Field("software_type", "Software", "The type of software detected (e.g. HTTP::SERVER)."), 385 | Field("name", "string", "Name of the software (e.g. Apache)."), 386 | Field("version.major", "count", "Major version number."), 387 | Field("version.minor", "count", "Minor version number."), 388 | Field("version.minor2", "count", "Minor subversion number."), 389 | Field("version.minor3", "count", "Minor updates number."), 390 | Field("version.addl", "string", "Additional version string (e.g. \"beta42\")."), 391 | Field("unparsed_version", "string", "The full unparsed version string found because the version parsing doesn't always work reliably in all cases and this acts as a fallback in the logs."), 392 | ], 393 | "ssh": [ 394 | Field("ts", "time", "Timestamp when the SSH connection was first detected."), 395 | Field("uid", "string", "Connection unique ID."), 396 | Field("id.orig_h", "addr", "The originating endpoint's address."), 397 | Field("id.orig_p", "port", "The originating endpoint's port."), 398 | Field("id.resp_h", "addr", "The responding endpoint's address."), 399 | Field("id.resp_p", "port", "The responding endpoint's port."), 400 | Field("status", "string", "Indicates if the login was heuristically guessed to be \"success\" or \"failure\"."), 401 | Field("direction", "Direction", "Direction of the connection. If the client was a local host logging into an external host, this would be OUTBOUND. INBOUND would be set for the opposite situation."), 402 | Field("client", "string", "Software string given by the client."), 403 | Field("server", "string", "Software string given by the server."), 404 | Field("resp_size", "count", "Amount of data returned from the server. This is currently the only measure of the success heuristic and it is logged to assist analysts looking at the logs to make their own determination about the success on a case-by-case basis."), 405 | Field("remote_location.country_code", "string", "The country code of the remote endpoint."), 406 | Field("remote_location.region", "string", "The region of the remote endpoint."), 407 | Field("remote_location.city", "string", "The city of the remote endpoint."), 408 | Field("remote_location.latitude", "string", "The latitude of the remote endpoint."), 409 | Field("remote_location.longitude", "string", "The longitude of the remote endpoint."), 410 | ], 411 | "ssl": [ 412 | Field("ts", "time", "Timestamp when the SSL connection was first detected."), 413 | Field("uid", "string", "Connection unique ID."), 414 | Field("id.orig_h", "addr", "The originating endpoint's address."), 415 | Field("id.orig_p", "port", "The originating endpoint's port."), 416 | Field("id.resp_h", "addr", "The responding endpoint's address."), 417 | Field("id.resp_p", "port", "The responding endpoint's port."), 418 | Field("version", "string", "SSL/TLS version the server offered."), 419 | Field("cipher", "string", "SSL/TLS cipher suite the server chose."), 420 | Field("server_name", "string", "Value of the Server Name Indicator SSL/TLS extension. It indicates the server name that the client was requesting."), 421 | Field("session_id", "string", "Session ID offered by the client for session resumption."), 422 | Field("subject", "string", "Subject of the X.509 certificate offered by the server."), 423 | Field("issuer_subject", "string", "Subject of the signer of the X.509 certificate offered by the server."), 424 | Field("not_valid_before", "time", "NotValidBefore field value from the server certificate."), 425 | Field("not_valid_after", "time", "NotValidAfter field value from the serve certificate."), 426 | Field("last_alert", "string", "Last alert that was seen during the connection."), 427 | Field("client_subject", "string", "Subject of the X.509 certificate offered by the client."), 428 | Field("client_issuer_subject", "string", "Subject of the signer of the X.509 certificate offered by the client."), 429 | Field("cert_hash", "string", "MD5 sum of the raw server certificate."), 430 | Field("validation_status", "vector", "Result of certificate validation for this connection."), 431 | ], 432 | "stats": [ 433 | Field("ts", "time", "Timestamp for the measurement."), 434 | Field("peer", "string", "Peer that generated this log. Mostly for clusters."), 435 | Field("mem", "count", "Amount of memory currently in use in MB."), 436 | Field("pkts_proc", "count", "Number of packets processed since the last stats interval."), 437 | Field("events_proc", "count", "Number of events that been processed since the last stats interval."), 438 | Field("events_queued", "count", "Number of events that have been queued since the last stats interval."), 439 | Field("lag", "interval", "Lag between the wall clock and packet timestamps if reading live traffic."), 440 | Field("pkts_recv", "count", "Number of packets received since the last stats interval if reading live traffic."), 441 | Field("pkts_dropped", "count", "Number of packets dropped since the last stats interval if reading live traffic."), 442 | Field("pkts_link", "count", "Number of packets seen on the link since the last stats interval if reading live traffic."), 443 | ], 444 | "syslog": [ 445 | Field("ts", "time", "Timestamp when the syslog message was seen."), 446 | Field("uid", "string", "Connection unique ID."), 447 | Field("id.orig_h", "addr", "The originating endpoint's address."), 448 | Field("id.orig_p", "port", "The originating endpoint's port."), 449 | Field("id.resp_h", "addr", "The responding endpoint's address."), 450 | Field("id.resp_p", "port", "The responding endpoint's port."), 451 | Field("proto", "transport_proto", "Protocol over which the message was seen."), 452 | Field("facility", "string", "Syslog facility for the message."), 453 | Field("severity", "string", "Syslog severity for the message."), 454 | Field("message", "string", "The plain text message."), 455 | ], 456 | "tunnel": [ 457 | Field("ts", "time", "Timestamp when some tunnel activity occurred."), 458 | Field("uid", "string", "Unique ID for the tunnel - may correspond to connection uid or be non-existant"), 459 | Field("id.orig_h", "addr", "The originating endpoint's address."), 460 | Field("id.orig_p", "port", "The originating endpoint's port - 0 in the case of an IP tunnel."), 461 | Field("id.resp_h", "addr", "The responding endpoint's address."), 462 | Field("id.resp_p", "port", "The responding endpoint's port - 0 in the case of an IP tunnel."), 463 | Field("tunnel_type", "Tunnel::Type", "The type of tunnel."), 464 | Field("action", "Action", "The type of activity that occured."), 465 | ], 466 | "weird": [ 467 | Field("ts", "time", "Timestamp when the weird occurred."), 468 | Field("uid", "string", "If a connection is associated with this weird, this will be the connection's unique ID."), 469 | Field("id.orig_h", "addr", "The originating endpoint's address - optional."), 470 | Field("id.orig_p", "port", "The originating endpoint's port - optional."), 471 | Field("id.resp_h", "addr", "The responding endpoint's address - optional."), 472 | Field("id.resp_p", "port", "The responding endpoint's port - optional."), 473 | Field("name", "string", "The name of the weird that occurred."), 474 | Field("addl", "string", "Additional information accompanying the weird if any."), 475 | Field("notice", "bool", "Indicate if this weird was also turned into a notice."), 476 | Field("peer", "string", "The peer that originated this weird. This is helpful in cluster deployments if a particular cluster node is having trouble to help identify which node is having trouble."), 477 | ], 478 | } 479 | -------------------------------------------------------------------------------- /Brownian/view/utils/es.py: -------------------------------------------------------------------------------- 1 | import requests, json, datetime, string, pytz 2 | from django.conf import settings 3 | from broLogTypes import broLogs 4 | import logging 5 | 6 | logger = logging.getLogger('elasticsearch_requests') 7 | 8 | def getIndices(): 9 | """Get a list of all bro indices 10 | """ 11 | 12 | result = Request(index="@bro-meta")._doRequest({"size": 65535}) 13 | indices = [] 14 | for hit in result["hits"]["hits"]: 15 | if hit["es_source"]["name"].startswith(settings.ELASTICSEARCH_INDEX_PREFIX): 16 | indices.append(hit["es_source"]) 17 | 18 | return indices 19 | 20 | def indexNameToDatetime(indexName): 21 | """Convert a bro-201208121900 style-name to a datetime object. 22 | """ 23 | if indexName.startswith(settings.ELASTICSEARCH_INDEX_PREFIX) and not indexName.startswith(settings.ELASTICSEARCH_INDEX_PREFIX + "-"): 24 | return pytz.timezone(settings.TIME_ZONE).localize(datetime.datetime.now()) 25 | 26 | indexTime = datetime.datetime.strptime(indexName.replace(settings.ELASTICSEARCH_INDEX_PREFIX + "-", ""), "%Y%m%d%H%M") 27 | return pytz.timezone(settings.TIME_ZONE).localize(indexTime) 28 | 29 | def indicesFromTime(startTime, indices): 30 | """Create a comma-separated list of the indices one needs to query for the given time window. 31 | """ 32 | endTime=pytz.timezone(settings.TIME_ZONE).localize(datetime.datetime.now()) 33 | 34 | if startTime == "all": 35 | return [index["name"] for index in indices] 36 | else: 37 | number = "" 38 | unit = "" 39 | for i in range(len(startTime)): 40 | if startTime[i] in string.ascii_letters: 41 | unit = startTime[i:] 42 | try: 43 | number = int(number) 44 | except: 45 | raise ValueError("Format of time: 1m, 2days, etc.") 46 | break 47 | elif startTime[i] in string.whitespace: 48 | continue 49 | elif startTime[i] in string.digits: 50 | number += startTime[i] 51 | else: 52 | raise ValueError("Format of time: 1m, 2days, etc.") 53 | 54 | if not number or not unit or number < 1: 55 | raise ValueError("Format of time: 1m, 2days, etc.") 56 | 57 | units = {"day": ["day", "days", "d"], 58 | "hour": ["hour", "hours", "h"], 59 | "minute": ["minute", "minutes", "m"], 60 | "second": ["second", "seconds", "s"]} 61 | 62 | if unit in units["day"]: 63 | then = endTime - datetime.timedelta(days=number) 64 | elif unit in units["hour"]: 65 | then = endTime - datetime.timedelta(hours=number) 66 | elif unit in units["minute"]: 67 | then = endTime - datetime.timedelta(minutes=number) 68 | elif unit in units["second"]: 69 | then = endTime - datetime.timedelta(seconds=number) 70 | else: 71 | raise ValueError("Possible time units: " + units.keys()) 72 | 73 | chosenIndices = [] 74 | for index in indices: 75 | indexStart = pytz.utc.localize(datetime.datetime.utcfromtimestamp(index["start"])) 76 | indexEnd = pytz.utc.localize(datetime.datetime.utcfromtimestamp(index["end"])) 77 | 78 | if ( ( indexStart >= endTime ) ^ ( indexEnd >= then ) ): 79 | chosenIndices.append(index["name"]) 80 | 81 | return chosenIndices 82 | 83 | def queryEscape(query): 84 | """Certain chars need to be escaped 85 | """ 86 | bad_chars = [ (""", '"') 87 | ] 88 | for char, replacement in bad_chars: 89 | query = query.replace(char, replacement) 90 | 91 | return query 92 | 93 | def getCounts(query, index="_all", type=None): 94 | """Using a facet of types, return dict of type and count. 95 | """ 96 | hits = [] 97 | 98 | data = {"query": 99 | {"constant_score": 100 | {"filter": 101 | {"query": 102 | {"query_string": {"query": query}}}}}, 103 | "facets": {"term": {"terms": {"field": "_type", "size": 50, "order": "term"}}}, 104 | "size": 0 105 | } 106 | result = Request(index=index, type=type)._doRequest(data=data) 107 | 108 | for i in result["facets"]["term"]["terms"]: 109 | count, type = i.itervalues() 110 | if type not in settings.ELASTICSEARCH_IGNORE_TYPES: 111 | hits.append({"type": type, "total": count}) 112 | 113 | return hits 114 | 115 | def doQuery(query, index="_all", sort=None, type=None, start=0, facets={}, size=settings.PAGE_SIZE): 116 | """Short wrapper for simple queries. 117 | """ 118 | if not sort: 119 | sort = {"ts": {"order": "DESC"}} 120 | 121 | data = {"query": 122 | {"constant_score": 123 | {"filter": 124 | {"query": 125 | {"query_string": {"query": query}}}}}, 126 | "size": size, 127 | "from": start, 128 | "sort": sort, 129 | "facets": facets, 130 | } 131 | result = Request(index=index, type=type)._doRequest(data=data) 132 | return result 133 | 134 | def resultToTable(result, type): 135 | """Convert JSON result to a dict for use in HTML table template. 136 | """ 137 | 138 | header = [(field.name, field.type, field.description) for field in broLogs[type] if field.name not in settings.ELASTICSEARCH_IGNORE_COLUMNS.get(type, [])] 139 | content = [] 140 | 141 | if type in settings.ELASTICSEARCH_IGNORE_TYPES: 142 | return {} 143 | if "hits" not in result.keys(): 144 | return {} 145 | if "hits" not in result["hits"].keys(): 146 | return {} 147 | if len(result["hits"]["hits"]) == 0: 148 | return {} 149 | 150 | for hit in result["hits"]["hits"]: 151 | row = [] 152 | for column, fType, desc in header: 153 | row.append((column, fType, hit["es_source"].get(column, ""))) 154 | content.append(row) 155 | 156 | if len(hit["es_source"].keys()) > len(row): 157 | assert "WARNING: Some fields weren't properly accounted for." 158 | assert "Type: %s;\nKnown fields: %s.\nRecvd fields: %s." % (type, hit["es_source"].keys(), [x[0] for x in row]) 159 | 160 | logger.debug(content) 161 | return {"header": header, "content": content, "took": result["took"]} 162 | 163 | def getHealth(): 164 | """Return cluster health information. 165 | """ 166 | 167 | health = Request(index="_cluster")._doRequest(operation="health", verb="GET") 168 | return health 169 | 170 | def getShardInfo(): 171 | """Return shard health information. 172 | """ 173 | shards = Request()._doRequest(operation="_stats", verb="GET", search_opts="clear=true") 174 | return shards 175 | 176 | def getNodeInfo(): 177 | """Return node health information. 178 | """ 179 | nodes = Request(index="_nodes")._doRequest(operation="stats", verb="GET", search_opts="clear=true&os=true&fs=true") 180 | return nodes['nodes'] 181 | 182 | class Request(object): 183 | """A single request to ElasticSearch 184 | """ 185 | def __init__(self, index="_all", type=None, url=settings.ELASTICSEARCH_SERVER): 186 | path = "http://%s/" % url 187 | if index: 188 | path += index + "/" 189 | if type: 190 | path += type + "/" 191 | self.path = path 192 | self.data = {} 193 | self.requests_config = {"max_retries": 0} 194 | 195 | def _doRequest(self, data=None, operation="_search", search_opts="", verb="POST"): 196 | if data: 197 | self.data = dict(self.data.items() + data.items()) 198 | 199 | if verb == "POST": 200 | logger.debug("POST " + self.path + operation + "?" + search_opts) 201 | logger.debug(" " + json.dumps(self.data)) 202 | result = requests.post(self.path + operation + "?" + search_opts, data=json.dumps(self.data), config=self.requests_config).text 203 | 204 | else: 205 | logger.debug("GET " + self.path + operation + "?" + search_opts) 206 | result = requests.get(self.path + operation + "?" + search_opts, config=self.requests_config).text 207 | 208 | # ElasticSearch internal fields are prefixed with _. This causes some issues w/ Django, so we prefix with es_ instead. 209 | self.result = json.loads(result.replace('"_', '"es_')) 210 | if "error" in self.result.keys(): 211 | raise IOError(self.result["error"]) 212 | 213 | return self.result 214 | 215 | queryAll = lambda self: self._doRequest({"size": settings.PAGE_SIZE}) 216 | query = lambda self, query: self._doRequest({"query": query, "size": settings.PAGE_SIZE}) 217 | 218 | -------------------------------------------------------------------------------- /Brownian/view/utils/plugins.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import string 3 | import shlex 4 | 5 | class Plugin: 6 | def __init__(self, command, allowedChars, insertInitialNewline=False): 7 | # We replace the characters we do allow with empty strings, to get a string of all the characters we don't allow. 8 | self.notAllowedCharMap = str(string.maketrans(allowedChars, " "*len(allowedChars))) 9 | self.command = shlex.split(command) 10 | self.insertInitialNewline = insertInitialNewline 11 | 12 | def run(self, values): 13 | sanitizedValues = [] 14 | for value in values: 15 | sanitizedValues.append(str(value).translate(None, self.notAllowedCharMap)) 16 | result = subprocess.Popen(self.command + sanitizedValues, stdout=subprocess.PIPE) 17 | stdout, stderr = result.communicate() 18 | if self.insertInitialNewline: 19 | stdout = "\n" + stdout 20 | return stdout.replace("\n", "
    ") 21 | 22 | whois = {"displayName": "Whois Lookup", 23 | "plugin": Plugin("whois -h whois.cymru.com \" -p -u\"", string.letters + string.digits + ".:-_", insertInitialNewline=True)} 24 | 25 | dns_lookup = {"displayName": "DNS Lookup", 26 | "plugin": Plugin("host", string.letters + string.digits + ".:-_")} 27 | 28 | mapping = {"addr": [whois, dns_lookup], 29 | "string": [dns_lookup]} -------------------------------------------------------------------------------- /Brownian/view/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | import utils.es 3 | from django.conf import settings 4 | 5 | def query(request): 6 | """ This page is the main query interface. 7 | """ 8 | data = {} 9 | 10 | params = request.GET 11 | 12 | # If we have a blank query, just return everything. 13 | query = params.get("query", "") 14 | if query == "": query = "*" 15 | data["query"] = query 16 | 17 | # If we have a blank time window, just return the past 15 minutes. 18 | time = params.get("time", "") 19 | if time == "": time = settings.DEFAULT_TIME_RANGE 20 | data["time"] = time 21 | if request.session.get('indices', False): 22 | indices = request.session.get('indices') 23 | else: 24 | try: 25 | indices = utils.es.getIndices() 26 | except: 27 | data["error"] = "Could not connect to server - please check ELASTICSEARCH_SERVER in settings.py" 28 | indices = [] 29 | return render(request, "home.html", data) 30 | request.session['indices'] = indices 31 | 32 | data["health"]= utils.es.getHealth() 33 | result = utils.es.indicesFromTime(time, indices) 34 | selectedIndices = ",".join(result) 35 | data["indices"] = selectedIndices 36 | data["query"] = query 37 | data["start"] = 0 38 | data["root"] = request.path 39 | 40 | if not selectedIndices: 41 | data["error"] = "No indices found in that time range - please adjust your time range." 42 | return render(request, "home.html", data) 43 | 44 | try: 45 | data["hits"] = utils.es.getCounts(utils.es.queryEscape(query), index=selectedIndices) 46 | except: 47 | data["error"] = "Could not connect to ElasticSearch server for query - please check ElasticSearch cluster health." 48 | return render(request, "home.html", data) 49 | if not data["hits"]: 50 | data["error"] = "Query returned no hits." 51 | return render(request, "home.html", data) 52 | # To make the Javascript easier, we strip off the # from the currently open tab. 53 | # If we don't have an open tab, default to conn. 54 | openTab = params.get("openTab", "#conn").replace("#", "") 55 | 56 | if openTab in [result["type"] for result in data["hits"]]: data["openTab"] = openTab 57 | else: 58 | if data["hits"]: data["openTab"] = data["hits"][0]["type"] 59 | else: data["openTab"] = "conn" 60 | 61 | return render(request, "home.html", data) 62 | 63 | def alerts(request): 64 | 65 | data = {} 66 | 67 | params = request.GET 68 | 69 | # If we have a blank time window, just return the past 15 minutes. 70 | time = params.get("time", "") 71 | if time == "": time = settings.DEFAULT_TIME_RANGE 72 | data["time"] = time 73 | if request.session.get('indices', False): 74 | indices = request.session.get('indices') 75 | else: 76 | try: 77 | indices = utils.es.getIndices() 78 | except: 79 | data["error"] = "Could not connect to server - please check ELASTICSEARCH_SERVER in settings.py" 80 | indices = [] 81 | return render(request, "alerts.html", data) 82 | request.session['indices'] = indices 83 | 84 | data['health'] = utils.es.getHealth() 85 | result = utils.es.indicesFromTime(time, indices) 86 | selectedIndices = ",".join(result) 87 | data["indices"] = selectedIndices 88 | data["query"] = query 89 | data["start"] = 0 90 | data["root"] = request.path 91 | 92 | if not selectedIndices: 93 | data["error"] = "No indices found in that time range - please adjust your time range." 94 | return render(request, "alerts.html", data) 95 | facets = {"ips": {"terms":[{"field": "src", "size": 25}, {"field": "dst", "size": 25}]}, 96 | "ports": {"terms": {"field": "p", "size": 25}}, 97 | "notices": {"terms": {"field": "note", "size": 25}}, 98 | } 99 | data['facets'] = utils.es.doQuery("*", index=selectedIndices, size=0, type="notice", facets=facets)['facets'] 100 | 101 | return render(request, "alerts.html", data) 102 | 103 | def health(request): 104 | data = {} 105 | 106 | try: 107 | data['health'] = utils.es.getHealth() 108 | data['shards'] = utils.es.getShardInfo() 109 | data['nodes'] = utils.es.getNodeInfo() 110 | except: 111 | data["error"] = "Could not connect to server - please check ELASTICSEARCH_SERVER in settings.py" 112 | return render(request, "health.html", data) 113 | 114 | return render(request, "health.html", data) -------------------------------------------------------------------------------- /Brownian/wsgi.py: -------------------------------------------------------------------------------- 1 | BROWNIAN_PATH = '/opt/Brownian' 2 | 3 | import sys 4 | version = sys.version_info 5 | PYTHON_VER = "%d.%d" % (version[0], version[1]) 6 | 7 | sys.path.insert(0, BROWNIAN_PATH + '/lib/python' + PYTHON_VER + '/site-packages') 8 | 9 | import site, os 10 | 11 | site.addsitedir(BROWNIAN_PATH + '/lib/python' + PYTHON_VER + '/site-packages') 12 | 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Brownian.settings") 14 | 15 | from django.core.wsgi import get_wsgi_application 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Vlad Grigorescu 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 8 | in the documentation and/or other materials provided with the distribution. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 10 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 11 | SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 14 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Brownian [![Build Status](https://secure.travis-ci.org/grigorescu/Brownian.png?branch=master)](http://travis-ci.org/grigorescu/Brownian) 2 | ================================ 3 | 4 | Brownian is a web interface for viewing and interacting with [Bro IDS](http://bro.org/) logs. Try it out on a [live demo](http://brownian.bro.org/?time=all). 5 | 6 | Why Brownian? 7 | ------------- 8 | 9 | Brownian motion relates to the elastic collisions and random motion of particles. Brownian aims to help you leverage Bro and ElasticSearch to make sense of a massive amount of seemingly random data. 10 | 11 | Prerequisites 12 | ------------- 13 | 14 | This interface only works with Bro if you're using the new [ElasticSearch Logging](http://bro.org/sphinx/frameworks/logging-elasticsearch.html) plugin. 15 | 16 | Please refer to that documentation for getting ElasticSearch setup, and receiving logs. 17 | 18 | It's also *highly* recommended to review the [ElasticSearch configuration tips](https://github.com/grigorescu/Brownian/wiki/ElasticSearch-Configuration). 19 | 20 | Requirements 21 | ------------ 22 | 23 | * Python version 2.6 or 2.7. 24 | * Brownian comes with it's own webserver, for testing purposes. 25 | * For production use, Apache with mod_wsgi is recommended. 26 | 27 | Virtualenv Setup 28 | ---------------- 29 | 30 | It is advised to run Brownian in a [virtualenv](http://www.virtualenv.org/en/latest/index.html) - an isolated Python environment with its own set of libraries. 31 | This will prevent system upgrades from modifying the globally installed libraries and potentially breaking Brownian. 32 | 33 | 1. Download the latest [virtualenv.py](https://raw.github.com/pypa/virtualenv/master/virtualenv.py). 34 | + Create and switch to your environment: 35 | 36 | ```bash 37 | $ python ./virtualenv.py Brownian 38 | $ cd Brownian 39 | $ source ./bin/activate 40 | ``` 41 | 42 | Installation 43 | ------------ 44 | 45 | ```bash 46 | $ pip install git+https://github.com/grigorescu/Brownian.git 47 | ``` 48 | 49 | The files are installed in ./lib/python2.X/site-packages/Brownian. 50 | 51 | Configuration 52 | ------------- 53 | 54 | 1. Change ```ELASTICSEARCH_SERVER``` in Brownian/lib/python2.X/site-packages/Brownian/settings.py to your server's hostname and port. 55 | + Change ```TIME_ZONE``` in settings.py to your desired timezone. 56 | + Review the other settings at the top of settings.py and configure them as desired. 57 | 58 | Running the Development Server 59 | ------------------------------ 60 | ```bash 61 | $ export DJANGO_SETTINGS_MODULE=Brownian.settings 62 | ``` 63 | In settings.py, modify the ```DATABASES``` setting to the path you'd like a small SQLite database created (your user will need write permissions to both the file and the parent directory). 64 | ```bash 65 | $ python ./bin/django-admin.py syncdb 66 | $ python ./bin/django-admin.py runserver 67 | ``` 68 | 69 | Running the Production Server with Apache 70 | ----------------------------------------- 71 | 1. Install mod_wsgi 72 | + Edit ```BROWNIAN_PATH``` at the top of Brownian/lib/python2.X/site-packages/Brownian/wsgi.py to the location of your virtualenv directory. 73 | + In settings.py, modify the ```DATABASES``` setting to the path you'd like a small SQLite database created (your Apache user will need write permissions to both the file and the parent directory). 74 | + To create the database, in your virtualenv, run ```DJANGO_SETTINGS_MODULE=Brownian.settings ./bin/django-admin.py syncdb```. You don't need to create any users. 75 | + Edit your Apache config to include: 76 | 77 | ```conf 78 | WSGIPassAuthorization on 79 | WSGIScriptAlias "/Brownian" "/opt/Brownian/lib/python2.X/site-packages/Brownian/wsgi.py" 80 | 81 | # Static content - CSS, Javascript, images, etc. 82 | Alias /static/ /opt/Brownian/lib/python2.X/site-packages/Brownian/view/static/ 83 | 84 | Order allow,deny 85 | Allow from all 86 | 87 | 88 | # Optional - Permissions 89 | 90 | Allow from ... 91 | ... Blah blah ... 92 | 93 | ``` 94 | 95 | Finally, restart Apache, and you should be good to go. 96 | 97 | If you'd like to have your static files somewhere other than ```/static```, change ```STATIC_URL``` in settings.py. Please make sure to leave a trailing slash. 98 | 99 | For more information, see: https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/modwsgi/ 100 | 101 | Issues 102 | ------ 103 | 104 | If you see something that's broken, or something that you'd like added, please create an issue. 105 | 106 | As always, fork, patch, and push away! 107 | 108 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Brownian.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.4.1 2 | django-dajax==0.9.1 3 | django-dajaxice==0.5 4 | nose==1.1.2 5 | pytz==2013b 6 | requests==0.13.6 7 | wsgiref==0.1.2 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup( 3 | name = "Brownian", 4 | version = "0.5-r108", 5 | packages = ["Brownian", "Brownian.view", "Brownian.view.templatetags", "Brownian.view.utils"], 6 | install_requires = ["Django==1.4.1", "django-dajax==0.9.1", "django-dajaxice==0.5", "requests==0.13.6", "nose", "pytz"], 7 | package_data = {'Brownian.view': 8 | ['static/css/*.css', 9 | 'static/img/*.png', 10 | 'static/img/*.gif', 11 | 'static/js/*.js', 12 | 'static/dajaxice/*.js', 13 | 'templates/*.html', 14 | 'templates/include/*.html', 15 | ]}, 16 | include_package_data = True, 17 | zip_safe = False, 18 | test_suite = "Brownian.view.tests", 19 | ) 20 | -------------------------------------------------------------------------------- /tests/data.json: -------------------------------------------------------------------------------- 1 | {"index": {"_index": "@bro-meta", "_type": "index", "_id": "bro-06241900-0.0-10800.0"} } 2 | {"name": "bro-06241900", "start": 1340578800.0, "end": 1340589600.0} 3 | {"index": {"_index": "bro-06241900", "_type": "communication"} } 4 | {"peer": "worker-1", "src_name": "child", "message": "selects=3000000 canwrites=0 timeouts=2986503", "ts": 1340647604358, "level": "info"} 5 | {"index": {"_index": "bro-06241900", "_type": "communication"} } 6 | {"peer": "worker-2", "src_name": "child", "message": "selects=2900000 canwrites=0 timeouts=2886357", "ts": 1340647615143, "level": "info"} 7 | {"index": {"_index": "bro-06241900", "_type": "conn"} } 8 | {"resp_bytes": 45, "uid": "SpoGdOarGy3", "conn_state": "SF", "proto": "udp", "id.orig_p": 20961, "id.resp_h": "128.123.140.21", "orig_pkts": 1, "orig_ip_bytes": 70, "ts": 1340647618510, "id.orig_h": "192.92.82.251", "id.resp_p": 62011, "tunnel_parents": [], "resp_pkts": 1, "local_orig": 0, "missed_bytes": 0, "duration": 0.075358, "orig_bytes": 42, "resp_ip_bytes": 73, "history": "Dd"} 9 | {"index": {"_index": "bro-06241900", "_type": "conn"} } 10 | {"resp_bytes": 178, "uid": "Kv8BEzH3L7d", "conn_state": "SF", "proto": "udp", "id.orig_p": 22821, "id.resp_h": "128.0.100.9", "orig_pkts": 4, "orig_ip_bytes": 788, "ts": 1340647617494, "id.orig_h": "12.113.6.0", "id.resp_p": 53890, "tunnel_parents": [], "resp_pkts": 5, "local_orig": 0, "missed_bytes": 0, "duration": 0.876488, "orig_bytes": 676, "resp_ip_bytes": 318, "history": "Dd"} 11 | {"index": {"_index": "bro-06241900", "_type": "dns"} } 12 | {"AA": 0, "RD": 1, "rcode": 0, "qclass_name": "C_INTERNET", "uid": "OgG6MWp32o1", "proto": "udp", "id.orig_p": 1087, "id.resp_h": "128.2.0.0", "rcode_name": "NOERROR", "ts": 1340647607992, "id.orig_h": "23.123.21.19", "id.resp_p": 53, "qclass": 1, "RA": 0, "qtype_name": "A", "query": "bro-ids.org", "Z": 0, "qtype": 1, "TC": 0, "trans_id": 1536} 13 | {"index": {"_index": "bro-06241900", "_type": "dns"} } 14 | {"AA": 0, "RD": 1, "rcode": 0, "qclass_name": "C_INTERNET", "uid": "OgG6MWp32o1", "proto": "udp", "id.orig_p": 1087, "id.resp_h": "128.2.0.0", "rcode_name": "NOERROR", "ts": 1340647637696, "id.orig_h": "8.8.35.8", "id.resp_p": 53, "qclass": 1, "RA": 0, "qtype_name": "A", "query": "a1158.b.akamai.net", "Z": 0, "qtype": 1, "TC": 0, "trans_id": 13688} 15 | {"index": {"_index": "bro-06241900", "_type": "dpd"} } 16 | {"uid": "L1NUOOOptp2", "proto": "tcp", "id.orig_p": 52162, "id.resp_h": "17.0.6.4", "ts": 1340647598519, "analyzer": "SSL", "failure_reason": "unexpected Handshake message SERVER_HELLO from responder in state INITIAL", "id.orig_h": "128.255.255.16", "id.resp_p": 443} 17 | {"index": {"_index": "bro-06241900", "_type": "dpd"} } 18 | {"uid": "ZYbazGdmJc9", "proto": "tcp", "id.orig_p": 56574, "id.resp_h": "128.2.3.4", "ts": 1340647599095, "analyzer": "SSL", "failure_reason": "unexpected Handshake message SERVER_HELLO from responder in state INITIAL", "id.orig_h": "9.8.7.6", "id.resp_p": 443} 19 | {"index": {"_index": "bro-06241900", "_type": "ftp"} } 20 | {"reply_msg": "Transfer complete.", "uid": "J2Z55eweLj6", "id.orig_p": 47491, "id.resp_h": "2.1.155.1", "file_size": 4, "ts": 1340647523506, "id.orig_h": "128.5.130.21", "id.resp_p": 21, "reply_code": 226, "command": "RETR", "user": "anonymous", "arg": "ftp://2.1.155.1/archlinux/ftpfull/extra/os/x86_64/libxfce4ui-4.10.0-1-x86_64.pkg.tar.xz", "password": "ftp@example.com"} 21 | {"index": {"_index": "bro-06241900", "_type": "ftp"} } 22 | {"reply_msg": "Transfer complete.", "uid": "J2Z55eweLj6", "id.orig_p": 47491, "id.resp_h": "2.1.155.2", "file_size": 0, "ts": 1340647526224, "id.orig_h": "128.5.130.21", "id.resp_p": 21, "reply_code": 226, "command": "RETR", "user": "anonymous", "arg": "ftp://2.1.155.2/archlinux/ftpfull/extra/os/x86_64/garcon-0.2.0-1-x86_64.pkg.tar.xz", "password": "ftp@example.com"} 23 | {"index": {"_index": "bro-06241900", "_type": "http"} } 24 | {"trans_depth": 1, "status_code": 200, "uid": "dbuYW3FQVa8", "request_body_len": 0, "response_body_len": 73773, "id.orig_p": 51622, "id.resp_h": "128.2.7.192", "status_msg": "OK", "tags": [], "ts": 1340647560439, "uri": "/images/detail-sprite.png", "id.orig_h": "16.193.137.16", "id.resp_p": 80, "host": "gigapan.com", "user_agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", "referrer": "http://gigapan.com/galleries/5998/gigapans/93336", "cookie_vars": ["es__utmb", "es__utma", "es__utmc", "es_gigapan_session", "es__utmz"], "uri_vars": ["/images/detail-sprite.png"], "method": "GET", "mime_type": "image/png", "client_header_names": ["ACCEPT", "REFERER", "ACCEPT-LANGUAGE", "USER-AGENT", "ACCEPT-ENCODING", "HOST", "CONNECTION", "COOKIE"]} 25 | {"index": {"_index": "bro-06241900", "_type": "http"} } 26 | {"trans_depth": 3, "uid": "shriLS4fZa9", "request_body_len": 0, "response_body_len": 245207, "id.orig_p": 53860, "id.resp_h": "130.64.126.25", "status_msg": "Partial Content", "tags": [], "ts": 1340647561145, "uri": "/pdf/menus/Dinner.pdf", "id.orig_h": "128.237.124.18", "id.resp_p": 80, "host": "www.dining.com", "user_agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1", "status_code": 206, "cookie_vars": ["es__utmc", "s_sq", "es__utma", "s_cmrun", "es__utmb", "s_cc", "s_nr", "s_evar5", "es__utmz", "ASPSESSIONIDSABACRQR"], "uri_vars": ["/pdf/menus/Dinner.pdf"], "method": "GET", "client_header_names": ["HOST", "USER-AGENT", "ACCEPT", "ACCEPT-LANGUAGE", "ACCEPT-ENCODING", "DNT", "CONNECTION", "RANGE", "COOKIE"]} 27 | {"index": {"_index": "bro-06241900", "_type": "irc"} } 28 | {"uid": "dcqnFZeA4x6", "id.orig_p": 40206, "id.resp_h": "128.237.112.64", "ts": 1340647291296, "value": "#Cyanogenmod", "id.orig_h": "123.9.144.4", "id.resp_p": 6667, "command": "JOIN", "addl": ""} 29 | {"index": {"_index": "bro-06241900", "_type": "irc"} } 30 | {"uid": "dcqnFZeA4x6", "id.orig_p": 40206, "id.resp_h": "128.237.112.64", "ts": 1340647321396, "value": "#cyanogenmod-dev", "id.orig_h": "123.9.144.4", "id.resp_p": 6667, "command": "JOIN", "addl": ""} 31 | {"index": {"_index": "bro-06241900", "_type": "known_certs"} } 32 | {"issuer_subject": "CN=COMODO High-Assurance Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB", "port_num": 443, "ts": 1340647603095, "host": "128.2.105.87", "serial": "1BBEB37A021343B91E1DA231CCFE4126", "subject": "CN=calendar.andrew.cmu.edu,OU=PlatinumSSL,OU=Hosted by Carnegie Mellon University,OU=Computing Services,O=Carnegie Mellon University,streetAddress=5000 Forbes Ave,L=Pittsburgh,ST=PA,postalCode=15213,C=US"} 33 | {"index": {"_index": "bro-06241900", "_type": "known_certs"} } 34 | {"issuer_subject": "CN=COMODO High-Assurance Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB", "port_num": 443, "ts": 1340647610354, "host": "128.2.229.61", "serial": "170031A4782B972E1ECE57371A12510A", "subject": "CN=hpp.web.cmu.edu,OU=PlatinumSSL,OU=Hosted by Carnegie Mellon University,OU=Health Professions Program,O=Carnegie Mellon University,streetAddress=5000 Forbes Ave,L=Pittsburgh,ST=PA,postalCode=15213,C=US"} 35 | {"index": {"_index": "bro-06241900", "_type": "known_hosts"} } 36 | {"host": "128.2.5.6", "ts": 1340647598892} 37 | {"index": {"_index": "bro-06241900", "_type": "known_hosts"} } 38 | {"host": "128.2.6.5", "ts": 1340647599402} 39 | {"index": {"_index": "bro-06241900", "_type": "known_services"} } 40 | {"port_proto": "tcp", "host": "128.2.46.19", "port_num": 3389, "ts": 1340647299382, "service": []} 41 | {"index": {"_index": "bro-06241900", "_type": "known_services"} } 42 | {"port_proto": "tcp", "host": "128.237.20.16", "port_num": 46657, "ts": 1340647300365, "service": []} 43 | {"index": {"_index": "bro-06241900", "_type": "notice"} } 44 | {"note": "HTTP::Incorrect_File_Type", "dropped": 0, "uid": "jFvD488oPPk", "proto": "tcp", "id.orig_p": 2899, "id.resp_h": "128.2.8.13", "dst": "128.2.8.13", "policy_items": [7, 6], "ts": 1340647599222, "p": 50308, "id.orig_h": "15.8.33.147", "id.resp_p": 50308, "peer_descr": "worker-3", "actions": ["Notice::ACTION_ALARM", "Notice::ACTION_LOG"], "msg": "application/x-dosexec GET http://128.2.8.13:50308/tcp/8679844E004FA5E5A28B1C15EF2839B6", "src": "15.8.33.147", "suppress_for": 3600.0} 45 | {"index": {"_index": "bro-06241900", "_type": "notice"} } 46 | {"note": "DNS::External_Name", "dropped": 0, "uid": "Fm5zi7Yngvj", "proto": "tcp", "id.orig_p": 51250, "id.resp_h": "15.8.33.147", "dst": "15.8.33.147", "policy_items": [7, 6], "ts": 1340647604356, "p": 53, "id.orig_h": "128.2.2.14", "id.resp_p": 53, "peer_descr": "worker-1", "actions": ["Notice::ACTION_ALARM", "Notice::ACTION_LOG"], "msg": "plab.planetlab.org is pointing to a local host - 128.2.5.5.", "src": "128.2.2.14", "suppress_for": 3600.0} 47 | {"index": {"_index": "bro-06241900", "_type": "notice_alarm"} } 48 | {"note": "HTTP::Incorrect_File_Type", "dropped": 0, "uid": "jFvD488oPPk", "proto": "tcp", "id.orig_p": 2899, "id.resp_h": "128.2.8.13", "dst": "128.2.8.13", "policy_items": [7, 6], "ts": 1340647599222, "p": 50308, "id.orig_h": "15.8.33.147", "id.resp_p": 50308, "peer_descr": "worker-3", "actions": ["Notice::ACTION_ALARM", "Notice::ACTION_LOG"], "msg": "application/x-dosexec GET http://128.2.8.13:50308/tcp/8679844E004FA5E5A28B1C15EF2839B6", "src": "15.8.33.147", "suppress_for": 3600.0} 49 | {"index": {"_index": "bro-06241900", "_type": "notice_alarm"} } 50 | {"note": "DNS::External_Name", "dropped": 0, "uid": "Fm5zi7Yngvj", "proto": "tcp", "id.orig_p": 51250, "id.resp_h": "15.8.33.147", "dst": "15.8.33.147", "policy_items": [7, 6], "ts": 1340647604356, "p": 53, "id.orig_h": "128.2.2.14", "id.resp_p": 53, "peer_descr": "worker-1", "actions": ["Notice::ACTION_ALARM", "Notice::ACTION_LOG"], "msg": "plab.planetlab.org is pointing to a local host - 128.2.5.5.", "src": "128.2.2.14", "suppress_for": 3600.0} 51 | {"index": {"_index": "bro-06241900", "_type": "reporter"} } 52 | {"message": "processing suspended", "location": "", "ts": 1340647282484, "level": "Reporter::INFO"} 53 | {"index": {"_index": "bro-06241900", "_type": "reporter"} } 54 | {"message": "Fell back to GeoIP Country database", "location": "", "ts": 1340647439536, "level": "Reporter::WARNING"} 55 | {"index": {"_index": "bro-06241900", "_type": "smtp"} } 56 | {"mailfrom": "", "trans_depth": 1, "from": "\"A robot\" ", "uid": "bJ80fNuYd4i", "to": ["anotherbot@google.net"], "id.orig_p": 46212, "id.resp_h": "176.46.24.119", "first_received": "from 128.2.1.1 (proxying for 192.168.24.13) (SquirrelMail authenticated user bot@andrew.cmu.edu) by webmail.andrew.cmu.edu with HTTP; Mon, 25 Jun 2012 14:06:38 -0400", "msg_id": "<50170e817247841935e688ee39a357b8.squirrel@webmail.andrew.cmu.edu>", "ts": 1340647599579, "second_received": "from webmail.andrew.cmu.edu (WEBMAIL-03.ANDREW.CMU.EDU [128.2.105.111])\t(user=bot mech=GSSAPI (56 bits))\tby smtp.andrew.cmu.edu (8.14.4/8.14.4) with ESMTP id q5PI6cYu024152\tfor ; Mon, 25 Jun 2012 14:06:38 -0400", "id.orig_h": "128.2.11.95", "id.resp_p": 25, "is_webmail": 1, "rcptto": [""], "user_agent": "SquirrelMail/1.4.22", "date": "Mon, 25 Jun 2012 14:06:38 -0400", "path": ["192.168.172.18", "12.2.65.73", "128.2.103.12", "128.2.4.4"], "helo": "smtp.andrew.cmu.ed", "last_reply": "250 2.0.0 Si6f1j00d232CWw06i6fYH mail accepted for delivery", "subject": "[Fwd: Some Spam!]"} 57 | {"index": {"_index": "bro-06241900", "_type": "smtp"} } 58 | {"mailfrom": "", "trans_depth": 1, "from": "\"Rudolph\" ", "uid": "XdFptTlDHEa", "to": ["\"Santa\" "], "id.orig_p": 58555, "id.resp_h": "23.167.15.33", "first_received": "from Blitzen (mail.aol.com [6.4.4.6])\t(user=rudolph mech=LOGIN (0 bits))\tby smtp.mail.edu (8.14.4/8.14.4) with ESMTP id q5PI6b2O014333\t(version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT)\tfor ; Mon, 25 Jun 2012 14:06:38 -0400", "msg_id": "<001c01cd52fd$425395b0$c6fac110$@cmu.edu>", "ts": 1340647600640, "last_reply": "250 ok: Message 1796213216 accepted", "id.orig_h": "17.5.231.224", "id.resp_p": 25, "is_webmail": 0, "rcptto": [""], "user_agent": "Microsoft Outlook 14.0", "date": "Mon, 25 Jun 2012 14:06:34 -0400", "path": ["172.43.243.2", "128.2.123.2", "27.8.13.224"], "helo": "smtp.mail.ed", "in_reply_to": "<020801cd52fb$9b1b20e0$d151f2a0$@com>", "subject": "RE: About..."} 59 | {"index": {"_index": "bro-06241900", "_type": "smtp_entities"} } 60 | {"excerpt": "", "trans_depth": 1, "uid": "XHtqpmt34X5", "id.orig_p": 35862, "id.resp_h": "128.2.67.132", "content_len": 39750, "ts": 1340647597467, "id.orig_h": "154.33.127.21", "id.resp_p": 25, "mime_type": "text/html"} 61 | {"index": {"_index": "bro-06241900", "_type": "smtp_entities"} } 62 | {"excerpt": "", "trans_depth": 1, "uid": "FYYqOdAqtR8", "id.orig_p": 58902, "id.resp_h": "193.54.168.226", "content_len": 411, "ts": 1340647598641, "id.orig_h": "128.236.98", "id.resp_p": 25, "mime_type": "text/plain"} 63 | {"index": {"_index": "bro-06241900", "_type": "software"} } 64 | {"name": "Firefox", "unparsed_version": "Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2", "version.minor": 0, "ts": 1340647282525, "host": "128.2.123.22", "version.minor2": 2, "software_type": "HTTP::BROWSER", "version.major": 10} 65 | {"index": {"_index": "bro-06241900", "_type": "software"} } 66 | {"name": "Safari", "unparsed_version": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/534.56.5 (KHTML, like Gecko) Version/5.1.6 Safari/534.56.5", "version.minor": 1, "ts": 1340647282525, "host": "128.53.122.196", "version.minor2": 6, "software_type": "HTTP::BROWSER", "version.major": 5} 67 | {"index": {"_index": "bro-06241900", "_type": "ssh"} } 68 | {"status": "failure", "direction": "INBOUND", "uid": "GjR1jckW1y6", "id.orig_p": 57971, "id.resp_h": "123.69.87.17", "ts": 1340647594375, "server": "SSH-2.0-OpenSSH_5.5p1 Debian-4ubuntu6", "id.orig_h": "122.75.87.119", "id.resp_p": 22, "client": "SSH-2.0-libssh-0.1", "resp_size": 1671} 69 | {"index": {"_index": "bro-06241900", "_type": "ssh"} } 70 | {"status": "failure", "direction": "INBOUND", "uid": "jMH9eIUdLe", "id.orig_p": 47751, "id.resp_h": "24.134.211.182", "ts": 1340647598344, "server": "SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu7", "id.orig_h": "210.17.148.14", "id.resp_p": 22, "client": "SSH-2.0-libssh-0.1", "resp_size": 1671} 71 | {"index": {"_index": "bro-06241900", "_type": "ssl"} } 72 | {"uid": "PLYYVXtxoS7", "server_name": "mail.google.com", "id.orig_p": 44929, "id.resp_h": "17.145.28.193", "ts": 1340647651797, "session_id": "c32fe4de2d28fc55c20cdc1693a41d9595feaf1f941c82537cbb25b89ca0267b", "id.orig_h": "128.2.99.138", "id.resp_p": 443, "version": "TLSv10", "cipher": "TLS_ECDHE_RSA_WITH_RC4_128_SHA"} 73 | {"index": {"_index": "bro-06241900", "_type": "ssl"} } 74 | {"not_valid_after": 1391057999000, "issuer_subject": "CN=Thawte SSL CA,O=Thawte\\, Inc.,C=US", "uid": "HBSDvWDLWSa", "server_name": "photos-5.dropbox.com", "id.orig_p": 57865, "id.resp_h": "123.121.12.17", "ts": 1340647651599, "id.orig_h": "128.2.237.18", "id.resp_p": 443, "version": "TLSv10", "cert_hash": "d7bc4836e22e4e6ece99996bf05a4638", "not_valid_before": 1322715600000, "validation_status": "ok", "cipher": "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "subject": "CN=*.dropbox.com,O=Dropbox\\, Inc.,L=San Francisco,ST=California,C=US"} 75 | {"index": {"_index": "bro-06241900", "_type": "syslog"} } 76 | {"uid": "5g5xqQAmdh2", "proto": "udp", "id.orig_p": 40629, "id.resp_h": "128.2.12.0", "facility": "LOCAL0", "ts": 1340647493276, "id.orig_h": "66.93.128.15", "id.resp_p": 514, "message": " IP: entry duplicated 2 times @2012-06-25-13:09:53", "severity": "WARNING"} 77 | {"index": {"_index": "bro-06241900", "_type": "syslog"} } 78 | {"uid": "lhsZfvPM2s5", "proto": "udp", "id.orig_p": 40631, "id.resp_h": "128.2.12.0", "facility": "LOCAL0", "ts": 1340647551462, "id.orig_h": "66.93.128.15", "id.resp_p": 514, "message": " IP: discard from 12.181.172.12 port 55556 to 66.93.182.15 port 54 TCP SYN (default) @2012-06-25-13:12:21", "severity": "WARNING"} 79 | {"index": {"_index": "bro-06241900", "_type": "tunnel"} } 80 | {"uid": "ltygZNzxov", "tunnel_type": "Tunnel::IP", "id.orig_p": 0, "id.resp_h": "128.2.15.155", "ts": 1340647599658, "id.orig_h": "94.25.201.137", "id.resp_p": 0, "action": "Tunnel::DISCOVER"} 81 | {"index": {"_index": "bro-06241900", "_type": "tunnel"} } 82 | {"uid": "fy89Hx63iid", "tunnel_type": "Tunnel::TEREDO", "id.orig_p": 64611, "id.resp_h": "65.123.18.128", "ts": 1340647602701, "id.orig_h": "128.2.195.21", "id.resp_p": 3544, "action": "Tunnel::DISCOVER"} 83 | {"index": {"_index": "bro-06241900", "_type": "weird"} } 84 | {"notice": 0, "uid": "42FJ0XejeT9", "id.orig_p": 4850, "id.resp_h": "69.123.24.83", "ts": 1340647598696, "id.orig_h": "128.2.18.19", "id.resp_p": 80, "peer": "worker-3", "name": "unescaped_special_URI_char"} 85 | {"index": {"_index": "bro-06241900", "_type": "weird"} } 86 | {"notice": 0, "uid": "9v5DdeLTzwd", "id.orig_p": 4378, "id.resp_h": "8.27.18.23", "ts": 1340647598924, "id.orig_h": "128.2.17.52", "id.resp_p": 80, "peer": "worker-3", "name": "inflate_failed"} 87 | --------------------------------------------------------------------------------